midistat.c++ 4.04 KB
#include <stdio.h>
#include <stdlib.h>
#include <bstring.h>
#include <assert.h>
#include <getopt.h>
#include <math.h>

#include "midifile.h"

static char usage[] = "-verbose <MIDI file>";

class Stat 
{
  protected:
    int program;
    int channel;
    int data[128];
    int hasData;
    
  public:
    Stat(int program, int channel);
    void Register(int key);
    void Print();
};

Stat::Stat(int prog, int chan)
{
    program = prog;
    channel = chan;
    hasData = 0;
    
    int i;
    for (i = 0; i < 128; i++)
        data[i] = 0;
    
}

void Stat::Register(int key)
{
    if (key > 127) {
        printf("bogus key %d\n", key);
        return;
    }

    hasData = 1;
    data[key]++;
}

void Stat::Print() 
{
    if (hasData) {
        if (channel == -1) {
            printf("Default Program\n");
            printf("===============\n");
        } else {
            printf("Channel %3d, Program %3d\n", channel, program);
            printf("========================\n");
        }
        
        printf("\n");
        
        int i,j;
        printf("key :  ");
        for (i = 0; i < 8; i++) {
            printf("%4d  ", i);
        }
        printf("\n");
        printf("-------------------------------------------------------\n");
        
        for (i = 0; i < 128; i += 8) {
            printf("%4.4d:  ", i);
            for (j = 0; j < 8; j++) {
                printf("%4d  ", data[i+j]);
            }
            printf("\n");
        }
        printf("\n");
    }
    
}

class Node
{
  public:
    Node *next;
    Stat *stat;
    Node(Stat *stat);
};

Node::Node(Stat *st) 
{
    next = 0;
    stat = st;
}

class StatList
{
  public:
    Node *head;
    Node *tail;
    StatList();
    void Append(Stat *);
};

StatList::StatList()
{
    head = tail = 0;
}

void StatList::Append(Stat *stat)
{
    Node *node = new Node(stat);
    
    if (!head) {
        head = tail = node;
    } else {
        tail->next = node;
        node->next = 0;
        tail = node;
    }
}

class MIDIStat : public MIDIFile
{
  protected:
    /* Channel Message handlers */
    virtual void midiNoteOn(char chan, char note, char velocity);
    virtual void midiProgramChange(char chan, char program);

  public:
    int noteCount;
    MIDIStat(void);
};

Stat *defaultStat;
Stat *curStat[16];
StatList list;

void main(int argc, char **argv)
{
    int c;
    extern char *optarg;
    extern int  optind;
    int         errflg=0;
    char        *ifile;
    char        *ofile=0;
    int         verbose=0;
    
    while ((c = getopt(argc, argv, "vo:")) != EOF) {        
        switch (c) {
	    case 'v':
                verbose = 1;
		break;
            case 'o':
                ofile = optarg;
                break;
            case '?':
                errflg++;
                break;
        }
    }

    if (errflg || optind == argc) {
        (void)fprintf(stderr, "%s %s\n", argv[0], usage);
        exit (2);
    }

    ifile = argv[optind++];
    if (optind != argc) {
	fprintf(stderr, "warning: only first file (%s) used, rest ignored\n",
	   ifile);
    }

    if (ofile == 0)
        ofile = "tmp.seq";
    
    defaultStat = new Stat(-1,-1);
    list.Append(defaultStat);
    
    int i;
    for (i = 0; i < 16; i++) {
        curStat[i] = 0;
    }
    
    MIDIStat *midifile = new MIDIStat;
    midifile->Open(ifile, "r");
    
    midifile->Parse();
    
    midifile->Close();

    for (i = 0; i < 16; i++) {
        if (curStat[i]) {
            list.Append(curStat[i]);
        }
    }

    printf("%d notes\n", midifile->noteCount);
    
    Node *node;
    for (node = list.head; node != 0; node = node->next) {
        node->stat->Print();
    }
}

MIDIStat::MIDIStat()
{
    noteCount = 0;
}

/* Channel Message handlers */
void MIDIStat::midiNoteOn(char chan, char note, char )
{
    noteCount++;
    
    if (curStat[chan])
        curStat[chan]->Register(note);
    else
        defaultStat->Register(note);
}

void MIDIStat::midiProgramChange(char chan, char program)
{
    if (curStat[chan])
        list.Append(curStat[chan]);
    
    curStat[chan] = new Stat(program, chan);
}