Compare commits

...

9 Commits

Author SHA1 Message Date
sshlien
69c1f850cb 2023.11.26 2023-11-26 12:51:23 -05:00
sshlien
f470c694ac 2023.11.17 2023-11-17 13:51:31 -05:00
sshlien
633e8d8848 2023.11.14 2023-11-14 16:36:10 -05:00
sshlien
d93cb473dc 2023.11.08 2023-11-08 10:57:05 -05:00
sshlien
b24803bf86 2023.11.01 2023-10-31 07:17:35 -04:00
sshlien
4e0266179b 2023.10.25 2023-10-25 19:43:27 -04:00
sshlien
2bf0052eb8 2023.08.13 2023-09-13 17:36:44 -04:00
sshlien
1394cd96c5 2023.09.11 2023-09-11 09:41:32 -04:00
sshlien
8a2ec3a898 2023.09.06 2023-09-06 17:37:58 -04:00
7 changed files with 213 additions and 50 deletions

View File

@@ -1,2 +1,2 @@
August 31 2023
November 26 2023

View File

@@ -15103,4 +15103,36 @@ stats_noteon(). In function, output_track_summary(), suppressed
notemeanpitch for percussion channel.
October 25 2023
Midistats returns track activity (note on/off) for every track.
November 1 2023
Midistats returns the control volume settings for every track,
identifies midi files whose note timings are not quantized.
November 2 2023
abc2midi bug: In the following example, not all notes are
tied correctly.
X:1
T: tied note
M: 2/4
L: 1/4
K: C
D2-|:D2 |[1CD-:|[2CD|
No fix is available.
November 8 2023
midistats: extended the size of arrays (midievents and pulsecounter) to
handle certain midi files. The function stats_interpret_pulseCounter()
can detect midi files containing triplets and nonquantized notes.
midicopy: extended to handle midi files with up to 150 tracks.

View File

@@ -15,9 +15,10 @@ 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),
Produces a line with 5 numbers separated by tabs. eg
1 8 384 4057 375
It returns the number of tracks, the number of channels, 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.

View File

@@ -1,4 +1,4 @@
.TH MIDISTATS 1 "9 December 2022"
.TH MIDISTATS 1 "17 November 2023"
.SH NAME
\fBmidistats\fP \- program to summarize the statistical properties of a midi file
.SH SYNOPSIS
@@ -36,11 +36,14 @@ the sum of the MIDI pitches for all the notes,
the sum of the note durations in MIDI pulse units,
the number of control parameter messages,
the number of pressure messages.
and the number of distinct rhythm patterns for each channel
the number of distinct rhythm patterns for each channel
the number of pulses the channel was inactive
the minimum pitch value
the maximum pitch value
the minimum note length in pulses
the maximum note length in pulses
the number of gaps in the channel
the entropy of the pitch class histogram for that channel
.PP
After processing all the individual tracks, the following information
applies to the entire midi file.
@@ -74,9 +77,9 @@ that occur in the midi file.
pitchact is a similar histogram but is weighted by the length of
the notes.
.PP
quietTime is used to compute the track/channel spread in midiexplorer.
It is computed by summing up all the midi pulses which occur
in gaps greater than 8 beats.
chnact returns the amount of note activity in each channel.
.PP
trkact returns the number of notes in each track.
.PP
totalrhythmpatterns is the total number of bar rhythm patterns for
all channels except the percussion channel.
@@ -93,6 +96,14 @@ 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 OPTIONS
.TP
.B -corestats
.TP
.B -pulseanalysis
.TP
.B etc. (See drums.txt in doc folder.)
.SH AUTHOR

View File

@@ -5,8 +5,8 @@ abc2midi version 4.84 January 06 2023
abc2abc version 2.20 February 07 2023
yaps version 1.92 January 06 2023
abcmatch version 1.82 June 14 2022
midicopy version 1.38 May 06 2022
midistats version 0.72 August 31 2023
midicopy version 1.39 November 08 2022
midistats version 0.81 November 26 2023
24th January 2002
Copyright James Allwright

View File

@@ -52,7 +52,7 @@
#define VERSION "1.38 May 05 2022 midicopy"
#define VERSION "1.39 November 07 2023 midicopy"
#include "midicopy.h"
#define NULLFUNC 0
#define NULL 0
@@ -96,8 +96,9 @@ long max_currtime = 0;
long Mf_currcopytime = 0L; /* time of last copied event */
char *trackdata = NULL;
long trackdata_length, trackdata_size;
char *trackstr[64]; /* [SS] 2017-10-20 2019-07-05*/
int trackstr_length[64]; /* [SS] 2017-10-20 2019-07-05*/
/* char *trackstr[64]; [SS] 2017-10-20 2019-07-05*/
char *trackstr[150]; /* [SS] 2023-11-07 */
int trackstr_length[150]; /* [SS] 2017-10-20 2019-07-05* 2023-11-07*/
int trkid = 0;
int activetrack;
int nochanmsg = 1;
@@ -1290,7 +1291,7 @@ build_new_midi_file (format, ntracks, division, fp)
get_tempo_info_from_track_1 ();
if (ntracks > 63) {printf("too many tracks\n"); exit(1); }
if (ntracks > 149) {printf("too many tracks\n"); exit(1); }
/* The rest of the file is a series of tracks */
for (i = 0; i < ntracks; i++)
@@ -1836,7 +1837,7 @@ main (int argc, char *argv[])
printf ("-ver version information\n");
printf ("-trks n1,n2,..(starting from 1)\n");
printf ("-xtrks n1,n2,.. (tracks to exclude)\n"); /* [SS] 2013-10-27 */
printf ("-xchns n1,n2,.. (tracks to exclude)\n"); /* [SS] 2017-12-06 */
printf ("-xchns n1,n2,.. (channels to exclude)\n"); /* [SS] 2022-11-12 */
printf ("-chns n1,n2,..(starting from 1)\n");
printf ("-from n (in midi ticks)\n");
printf ("-to n (in midi ticks)\n");

View File

@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define VERSION "0.72 August 31 2023 midistats"
#define VERSION "0.81 November 26 2023 midistats"
#include <limits.h>
/* Microsoft Visual C++ Version 6.0 or higher */
@@ -49,7 +49,7 @@ extern char* strchr();
#include "midifile.h"
void initfuncs();
void stats_finish();
float histogram_entropy (int *histogram, int size);
float histogram_perplexity (int *histogram, int size);
void stats_noteoff(int chan,int pitch,int vol);
void stats_eot ();
#define max(a,b) (( a > b ? a : b))
@@ -63,9 +63,11 @@ static FILE *F;
static FILE *outhandle; /* for producing the abc file */
int tracknum=0; /* track number */
int lasttrack = 0; /* lasttrack */
int division; /* pulses per quarter note defined in MIDI header */
int quietLimit; /* minimum number of pulses with no activity */
long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
int bpm = 120; /*default tempo */
long laston = 0; /* length of MIDI track in pulses or ticks */
int key[12];
int sharps;
@@ -86,13 +88,14 @@ int divisionsPerBar;
int unitDivision;
int maximumPulse;
int lastBeat;
int hasLyrics = 0;
struct eventstruc {int onsetTime;
unsigned char channel;
unsigned char pitch;
unsigned char velocity;
;} midievents[40000];
;} midievents[50000];
int lastEvent = 0;
@@ -118,6 +121,7 @@ int notechan[2048],notechanvol[2048]; /*for linking on and off midi
int lastTick[2048]; /* for getting last pulse number for chan (0-15) and pitch (0-127) in MIDI file */
int last_on_tick[17]; /* for detecting chords [SS] 2019-08-02 */
int channel_active[17]; /* for dealing with chords [SS] 2023-08-30 */
int channel_used_in_track[17]; /* for dealing with quietTime [SS] 2023-09-06 */
int histogram[256];
unsigned char drumpat[8000];
@@ -147,6 +151,9 @@ struct trkstat {
int lastNoteOff[17];
int quietTime[17];
int rhythmpatterns[17];
int numberOfGaps[17];
int chanvol[17];
float pitchEntropy[17];
} trkdata;
/* The trkstat references the individual channels in the midi file.
@@ -168,8 +175,10 @@ int pitchhistogram[12]; /* pitch distribution for non drum notes */
int channel2prog[17]; /* maps channel to program */
int channel2nnotes[17]; /*maps channel to note count */
int chnactivity[17]; /* [SS] 2018-02-02 */
int trkactivity[40]; /* [SS] 2023-10-25 */
int progactivity[128]; /* [SS] 2018-02-02 */
int pitchclass_activity[12]; /* [SS] 2018-02-02 */
int chanpitchhistogram[204]; /* [SS] 2023-09-13 */
/* [SS] 2017-11-01 */
@@ -192,7 +201,7 @@ static int progmapper[] = {
16, 16, 16, 16, 16, 16, 16, 16
};
int pulseCounter[480];
int pulseCounter[1024];
int pulseDistribution[24];
struct barPattern {
@@ -413,6 +422,7 @@ void stats_header (int format, int ntrks, int ldivision)
quietLimit = ldivision*8;
divisionsPerBar = division*beatsPerBar;
unitDivision = divisionsPerBar/24;
lasttrack = ntrks; /* [SS] 2023-10-25 */
printf("ntrks %d\n",ntrks);
printf("ppqn %d\n",ldivision);
chordthreshold = ldivision/16; /* [SS] 2018-01-21 */
@@ -425,6 +435,8 @@ void stats_header (int format, int ntrks, int ldivision)
trkdata.cntlparam[i] = 0; /* [SS] 2022-03-04 */
trkdata.pressure[i] = 0; /* [SS] 2022-03-04 */
trkdata.quietTime[i] = 0; /* [SS] 2022-08-22 */
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/
channel2nnotes[i] = 0;
@@ -434,6 +446,7 @@ void stats_header (int format, int ntrks, int ldivision)
for (i=0;i<12;i++) pitchhistogram[i] = 0; /* [SS] 2017-11-01 */
for (i=0;i<12;i++) pitchclass_activity[i] = 0; /* [SS] 2018-02-02 */
for (i=0;i<128;i++) progactivity[i] = 0; /* [SS] 2018-02-02 */
for (i=0;i<40;i++) trkactivity[i]=0; /* [SS] 2023-10-25 */
}
void determine_progcolor ()
@@ -460,6 +473,61 @@ int i;
}
/* [SS] 2023-10-30 */
void stats_interpret_pulseCounter () {
int i,j;
int maxcount,ncounts,npeaks,npositives,peaklimit;
int maxloc;
float threshold,peak;
int decimate;
float tripletsCriterion8,tripletsCriterion4;
int resolution = 12;
int nzeros;
threshold = 10.0/(float) division;
maxcount = 0;
ncounts = 0;
npeaks = 0;
for (i=0;i<division;i++) {
ncounts = ncounts + pulseCounter[i];
if (pulseCounter[i] > maxcount) {
maxloc = i;
maxcount = pulseCounter[i];
}
}
peaklimit = (int) (ncounts * 0.020);
for (i=0;i<division;i++) {
if (pulseCounter[i] > peaklimit) npeaks++;
}
for (i = 0; i < resolution; i++) pulseDistribution[i] = 0;
decimate = division/resolution;
for (i = 0; i < division; i++) {
j = i/decimate;
pulseDistribution[j] += pulseCounter[i];
}
/* count zeros */
nzeros = 0;
for (i=0;i<resolution;i++) if((float) pulseDistribution[i]/(float) ncounts < 0.015 ) nzeros++;
npositives = resolution - nzeros;
if (nzeros > 3 && (float) pulseDistribution[resolution-1]/(float) ncounts < 0.1) {printf("clean_quantization\n");
} else if ((float) pulseDistribution[resolution-1]/(float) ncounts > 0.09 ||
npeaks > npositives) {printf("dithered_quantization\n");
} else {
peak = (float) maxcount/ (float) ncounts;
if (peak < threshold) printf("unquantized\n");
}
tripletsCriterion8 = (float) pulseDistribution[8]/ (float) ncounts;
tripletsCriterion4 = (float) pulseDistribution[4]/ (float) ncounts;
if (tripletsCriterion8 > 0.10 || tripletsCriterion4 > 0.10) printf("triplets\n");
if (pulseDistribution[0]/(float) ncounts > 0.95) printf("qnotes");
/*
printf("pulseDistribution:");
for (i=0;i<resolution;i++) printf("%6.3f",(float) pulseDistribution[i]/(float) ncounts);
printf("\n");
printf("nzeros = %d npeaks = %d \n",nzeros,npeaks);
*/
}
void stats_finish()
{
@@ -517,38 +585,39 @@ if (npulses > 0)
for (i=0;i<12;i++) printf("%5.2f ",pitchclass_activity[i]/(double) npulses);
else
for (i=0;i<12;i++) printf("%5.2f ",(double) pitchclass_activity[i]);
printf("\nchanvol "); /* [SS] 2023-10-30 */
for (i=1;i<17;i++) printf("%4d ",trkdata.chanvol[i]);
printf("\nchnact "); /* [SS] 2018-02-08 */
if (npulses > 0)
for (i=1;i<17;i++) printf("%5.2f ",chnactivity[i]/(double) trkdata.npulses[0]);
for (i=1;i<17;i++) printf("%5.3f ",chnactivity[i]/(double) trkdata.npulses[0]);
else
for (i=0;i<17;i++) printf("%5.2f ",(double) chnactivity[i]);
printf("\nquietTime ");
for (i=1;i<17;i++) {
delta = trkdata.npulses[0] - trkdata.quietTime[i];
if (trkdata.quietTime[i] < quietLimit) delta = 0;
delta = delta / (double) trkdata.npulses[0];
/* printf (" %5.3f ", delta); */
printf (" %d ", trkdata.quietTime[i]);
}
printf("\npitchentropy %f\n",histogram_entropy(pitchclass_activity,12));
for (i=0;i<17;i++) printf("%5.3f ",(double) chnactivity[i]);
printf("\ntrkact ");
lasttrack++;
for (i=0;i<lasttrack;i++) printf("% 5d",trkactivity[i]);
printf("\npitchperplexity %f\n",histogram_perplexity(pitchclass_activity,12));
printf("totalrhythmpatterns =%d\n",nrpatterns);
printf("collisions = %d\n",ncollisions);
if (hasLyrics) printf("Lyrics\n");
stats_interpret_pulseCounter ();
printf("\n");
}
float histogram_entropy (int *histogram, int size)
float histogram_perplexity (int *histogram, int size)
{
/* The perplexity is 2 to the power of the entropy */
int i;
int total;
float entropy;
float e,p;
total = 0;
entropy = 0.0;
//printf("\nhistogram_entropy of:");
for (i=0;i<size;i++) {
total += histogram[i];
//printf(" %d",histogram[i]);
}
for (i=0;i<size;i++) {
if (histogram[i] < 1) continue;
@@ -556,7 +625,8 @@ float histogram_entropy (int *histogram, int size)
e = p*log(p);
entropy = entropy + e;
}
return -entropy/log(2.0);
//printf("\n");
return pow(2.0,-entropy/log(2.0));
}
@@ -596,10 +666,12 @@ for (i=1;i<17;i++) {
printf("-1 0 ");
printf("%d %d ",trkdata.cntlparam[i],trkdata.pressure[i]); /* [SS] 2022-03-04 */
printf("%d %d ",trkdata.quietTime[i],trkdata.rhythmpatterns[i]);
if (i != 10) printf("%d %d %d %d",trkdata.notepitchmin[i], trkdata.notepitchmax[i] ,trkdata.notelengthmin[i], trkdata.notelengthmax[i]);
else
if (i != 10) {printf("%d %d %d %d %d",trkdata.notepitchmin[i], trkdata.notepitchmax[i] ,trkdata.notelengthmin[i], trkdata.notelengthmax[i], trkdata.numberOfGaps[i]);
printf(" %f",trkdata.pitchEntropy[i]);
} else
printf("-1 0");
trkdata.quietTime[i] = 0;
trkdata.quietTime[i] = 0; /* in case channel i is used in another track */
trkdata.numberOfGaps[i] = 0;
printf("\n");
channel2nnotes[i] += trkdata.notecount[i] + trkdata.chordcount[i];
@@ -629,12 +701,22 @@ void stats_trackstart()
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 */
for (i=0;i<204;i++) chanpitchhistogram[i] = 0; /* [SS] 2023-09-13 */
}
void stats_trackend()
{
trkdata.npulses[tracknum] = Mf_currtime;
int chan;
int i;
float entropy;
if (trkdata.npulses[0] < Mf_currtime) trkdata.npulses[0] = Mf_currtime;
for (chan = 1; chan < 17; chan++) /* [SS] 2023-09-06 */
if (channel_used_in_track[chan] > 0) trkdata.quietTime[chan] += (trkdata.npulses[0] - trkdata.lastNoteOff[chan]);
for (chan=0;chan<16;chan++) { /* 2023-09-13 */
if (chan == 9 || channel_used_in_track[chan+1] == 0) continue;
trkdata.pitchEntropy[chan+1] = histogram_perplexity(chanpitchhistogram +chan*12,11);
}
output_track_summary();
}
@@ -647,7 +729,11 @@ int chan, pitch, vol;
int barnum;
int unit;
int dithermargin; /* [SS] 2023-08-22 */
int cpitch; /* [SS] 2023-09-13 */
int pulsePosition;
cpitch = pitch % 12;
channel_used_in_track[chan+1]++; /* [SS] 2023-09-06 */
dithermargin = unitDivision/2 - 1;
if (vol == 0) {
/* treat as noteoff */
@@ -655,14 +741,20 @@ int chan, pitch, vol;
trkdata.lastNoteOff[chan+1] = Mf_currtime; /* [SS] 2022.08.22 */
return;
}
pulsePosition = Mf_currtime % division;
pulseCounter[pulsePosition]++;
if (pulsePosition >= 1023) {printf("pulsePosition = %d too large\n",pulsePosition);
exit(1);
}
trkdata.notemeanpitch[chan+1] += pitch;
trkdata.notepitchmax[chan+1] = max(trkdata.notepitchmax[chan+1],pitch);
trkdata.notepitchmin[chan+1] = min(trkdata.notepitchmin[chan+1],pitch);
if (trkdata.lastNoteOff[chan+1] >= 0) {
delta = Mf_currtime - trkdata.lastNoteOff[chan+1];
trkdata.lastNoteOff[chan+1] = -1; /* in case of chord */
if (delta > quietLimit) {
trkdata.quietTime[chan+1] += delta;
trkdata.numberOfGaps[chan+1]++;
trkdata.lastNoteOff[chan+1] = -1; /* in case of chord */
}
}
@@ -686,6 +778,7 @@ int chan, pitch, vol;
unit = ((Mf_currtime+dithermargin) % divisionsPerBar)/unitDivision;
//printf("unit = %d pattern = %d \n",unit,barChn[chan].rhythmPattern);
barChn[chan].rhythmPattern = barChn[chan].rhythmPattern |= (1UL << unit);
chanpitchhistogram[chan*12+cpitch]++; /* [SS] 2023-09-13 */
}
@@ -715,9 +808,10 @@ void stats_noteoff(int chan,int pitch,int vol)
trkdata.notelength[chan+1] += length;
trkdata.notelengthmax[chan+1] = max(trkdata.notelengthmax[chan+1],length);
trkdata.notelengthmin[chan+1] = min(trkdata.notelengthmin[chan+1],length);
if (length < 3) printf("chan = %d lasttick = %d currtime = %ld\n",chan,lastTick[chan*128+pitch],Mf_currtime);
//if (length < 3) printf("chan = %d lasttick = %d currtime = %ld\n",chan,lastTick[chan*128+pitch],Mf_currtime);
trkdata.lastNoteOff[chan+1] = Mf_currtime; /* [SS] 2022.08.22 */
chnactivity[chan+1] += length;
trkactivity[tracknum]++;
if (chan == 9) return; /* drum channel */
pitchclass_activity[pitch % 12] += length;
program = trkdata.program[chan+1];
@@ -772,11 +866,16 @@ if (trkdata.program[chan+1] != 0) {
void stats_parameter(chan,control,value)
int chan, control, value;
{
/*if (control == 7) {
printf("cntrlvolume %d %d \n",chan+1,value);
}
int chan1;
chan1 = chan+1;
/* There may be many volume commands for the same channel. Only
record the first one.
*/
trkdata.cntlparam[chan+1]++;
if (control == 7 && trkdata.chanvol[chan1] == 0) {
/*printf("cntrlvolume %d %d \n",chan+1,value);*/
trkdata.chanvol[chan1] = value; /* [SS] 2023-10-30 */
}
trkdata.cntlparam[chan1]++;
}
@@ -786,6 +885,7 @@ int type, leng;
char *mess;
{
int i;
if (type == 5) hasLyrics = 1; /* [SS] 2023-10-30 */
if (type != 3) return;
printf("metatext %d ",type);
for (i=0;i<leng;i++) printf("%c",mess[i]);
@@ -848,9 +948,10 @@ midievents[lastEvent].channel = chan;
midievents[lastEvent].pitch = pitch;
midievents[lastEvent].velocity = vol;
lastEvent++;
if (lastEvent > 39999) {printf("ran out of space in midievents structure\n");
if (lastEvent > 49999) {printf("ran out of space in midievents structure\n");
exit(1);
}
channel_active[chan+1]++;
}
void record_noteoff(int chan,int pitch,int vol)
@@ -859,6 +960,12 @@ void record_noteoff(int chan,int pitch,int vol)
void record_trackend()
{
}
void record_tempo(long ltempo)
{
tempo = ltempo;
if (bpm == 120) bpm = 60000000.0/tempo;
tempocount++;
}
int int_compare_events(const void *a, const void *b) {
struct eventstruc *ia = (struct eventstruc *)a;
@@ -872,12 +979,16 @@ int int_compare_events(const void *a, const void *b) {
void load_header (int format, int ntrks, int ldivision)
{
int i;
division = ldivision;
lasttrack = ntrks;
for (i=0;i<17;i++) channel_active[i] = 0; /* for counting number of channels*/
}
void initfunc_for_stats()
{
int i;
Mf_error = stats_error; /* [SS] 2017-11-19 */
Mf_header = stats_header;
Mf_trackstart = stats_trackstart;
@@ -900,6 +1011,7 @@ void initfunc_for_stats()
Mf_seqspecific = no_op3;
Mf_text = stats_metatext;
Mf_arbitrary = no_op2;
for (i = 0; i< 1023; i++) pulseCounter[i] = 0;
}
@@ -922,7 +1034,7 @@ void initfunc_for_loadNoteEvents()
Mf_eot = no_op0;
Mf_timesig = no_op4;
Mf_smpte = no_op5;
Mf_tempo = no_op1;
Mf_tempo = record_tempo;
Mf_keysig = no_op2;
Mf_seqspecific = no_op3;
Mf_text = no_op3;
@@ -951,16 +1063,16 @@ int pulsePosition;
int decimate;
float fraction;
int resolution = 12;
for (i = 0; i< 480; i++) pulseCounter[i] = 0;
for (i = 0; i< 1023; i++) pulseCounter[i] = 0;
for (i = 0; i < lastEvent; i++) {
pulsePosition = midievents[i].onsetTime % division;
pulseCounter[pulsePosition]++;
if (pulsePosition >= 480) {printf("pulsePosition = %d too large\n",pulsePosition);
if (pulsePosition >= 1023) {printf("pulsePosition = %d too large\n",pulsePosition);
exit(1);
}
}
for (i = 0; i < resolution; i++) pulseDistribution[i] = 0;
/*for (i = 0; i < 480; i++) printf(" %d",pulseCounter[i]);
/*for (i = 0; i < 1023; i++) printf(" %d",pulseCounter[i]);
printf("\n");
*/
decimate = division/resolution;
@@ -1142,7 +1254,13 @@ printf("\n");
void corestatsOutput() {
printf("%d\t%d\t%d\n", division,lastEvent,lastBeat);
int i;
int nchannels;
nchannels = 0;
for (i=1;i<17;i++)
if (channel_active[i] > 0) nchannels++;
printf("%d\t%d\t%d\t%d\t%d\t%d\n",lasttrack,nchannels, division,bpm,lastEvent,lastBeat);
/*printf("%d\n",tempocount);*/
}