midicvt.c++ 8.56 KB
#include <stdio.h>
#include <stdlib.h>
#include <bstring.h>
#include <assert.h>
#include <getopt.h>
#include <math.h>

#include "midifile.h"
#include "list.h"

static char usage[] = "[-v] [-s] [-o] <infile> <outfile>";

class MIDICvt : public MIDIFile
{
  protected:
    virtual void midiHeader(TrackHdr *hdr);

    /* Meta Message handlers */
    virtual void midiTempo(long tempo);
    virtual void midiSeqNum(short num);
    virtual void midiText(int type, char *str, int len);
    virtual void midiEndOfTrack();
    virtual void midiSMPTE(char hours, char min, char sec, char fr, char ff);
    virtual void midiTimeSig(char nn, char dd, char cc, char bb);
    virtual void midiKeySig(char sf, char mi);
    virtual void midiSeqSpecific(char *msg, long len);
    virtual void midiMetaMisc(int type, char *msg, long len);

    /* Channel Message handlers */
    virtual void midiNoteOn(char chan, char note, char velocity);
    virtual void midiNoteOff(char chan, char note, char velocity);
    virtual void midiKeyPressure(char chan, char key, char velocity);
    virtual void midiControlChange(char chan, char control, char value);
    virtual void midiPitchBend(char chan, char msb, char lsb);
    virtual void midiProgramChange(char chan, char program);
    virtual void midiChannelPressure(char chan, char pressure);

    /* System exclusive handlers */
    virtual void midiSysEx(char *buffer, int len);
    virtual void midiSysExStart(char *buffer, int len);

    /* write operations */
    virtual void midiWriteTrack(int track);
};

List    list;
int     division;
int     strip = 0;

void main(int argc, char **argv)
{
    int         c;
    extern char *optarg;
    extern int  optind;
    int         errflg=0;
    char        *ifile=0;
    char        *ofile=0;
    int         verbose=0;
    
    while ((c = getopt(argc, argv, "vso")) != EOF) {        
        switch (c) {
	    case 'o':
		list.OrderEvents(1);
		break;
	    case 'v':
                verbose = 1;
		break;
            case 's':
                strip = 1;
                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,"%s: must specify an output file\n", argv[0]);
        exit(1);
    }

    ofile = argv[optind];
    
    MIDICvt *midiIn = new MIDICvt;
    if (!midiIn) exit(1);
    
    midiIn->Open(ifile, "r");

    MIDICvt *midiOut = new MIDICvt;
    if (!midiOut) exit(1);

    midiOut->Open(ofile, "w");
    
    midiIn->Parse();
    
    midiOut->Write(0, 1, division);
    
    midiIn->Close();
    midiOut->Close();
}

void MIDICvt::midiHeader(TrackHdr *hdr)
{
    if (hdr->format == 0) {
        printf("Note: %s is already a type 0 file\n", name);
    }

    division = hdr->division;    
}

/* Meta Message handlers */
void MIDICvt::midiTempo(long tempo)
{
    Node *node = new Node();

    node->type = META_TYPE;
    node->subtype = 0x51;
    node->time = curTime;
    node->data = (char *)malloc(3);
    node->len  = 3;

    node->data[0] = (char)(tempo >> 16) & 0xff;
    node->data[1] = (char)(tempo >>  8) & 0xff;
    node->data[2] = (char)(tempo & 0xff);

    list.Insert(node);    
}

void MIDICvt::midiSeqNum(short num)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = 0x0;
        node->time = curTime;
        node->data = (char *)malloc(2);
        node->len  = 2;

        node->data[0] = (num >> 8) & 0xff;
        node->data[1] = num & 0xff;

        list.Insert(node);
    }
}

void MIDICvt::midiText(int type, char *str, int len)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = type;
        node->time = curTime;
        node->data = str;
        node->len  = len;

        list.Insert(node);
    }
}
        
void MIDICvt::midiEndOfTrack()
{
}

void MIDICvt::midiSMPTE(char hours, char min, char sec, char fr, char ff)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = 0x54;
        node->time = curTime;
        node->data = (char *)malloc(5);
        node->len  = 5;

        node->data[0] = hours;
        node->data[1] = min;
        node->data[2] = sec;
        node->data[3] = fr;
        node->data[4] = ff;

        list.Insert(node);
    }
}

void MIDICvt::midiTimeSig(char nn, char dd, char cc, char bb)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = 0x58;
        node->time = curTime;
        node->data = (char *)malloc(4);
        node->len  = 4;

        node->data[0] = nn;
        node->data[1] = dd;
        node->data[2] = cc;
        node->data[3] = bb;

        list.Insert(node);
    }
}

void MIDICvt::midiKeySig(char sf, char mi)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = 0x59;
        node->time = curTime;
        node->data = (char *)malloc(2);
        node->len  = 2;

        node->data[0] = sf;
        node->data[1] = mi;

        list.Insert(node);    
    }    
}

void MIDICvt::midiSeqSpecific(char *msg, long len)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = 0x7f;
        node->time = curTime;
        node->data = msg;
        node->len  = len;

        list.Insert(node);    
    }
}

void MIDICvt::midiMetaMisc(int type, char *msg, long len)
{
    if (!strip) {
        Node *node = new Node();

        node->type = META_TYPE;
        node->subtype = type;
        node->time = curTime;
        node->data = msg;
        node->len  = len;

        list.Insert(node);
    }
}


/* Channel Message handlers */
void MIDICvt::midiNoteOn(char chan, char key, char velocity)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_NoteOn | chan;
    node->b1 = key;
    node->b2 = velocity;
    
    list.Insert(node);    
}

void MIDICvt::midiNoteOff(char chan, char key, char)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_NoteOn | chan;
    node->b1 = key;
    node->b2 = 0;
    
    list.Insert(node);    
}

void MIDICvt::midiKeyPressure(char chan, char key, char velocity)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_PolyKeyPressure | chan;
    node->b1 = key;
    node->b2 = velocity;
    
    list.Insert(node);    
}

void MIDICvt::midiControlChange(char chan, char control, char value)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_ControlChange | chan;
    node->b1 = control;
    node->b2 = value;
    
    list.Insert(node);    
}

void MIDICvt::midiPitchBend(char chan, char msb, char lsb)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_PitchBendChange | chan;
    node->b1 = msb;
    node->b2 = lsb;
    
    list.Insert(node);    
}

void MIDICvt::midiProgramChange(char chan, char program)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_ProgramChange | chan;
    node->b1 = program;
    node->b2 = 0;
    
    list.Insert(node);    
}

void MIDICvt::midiChannelPressure(char chan, char pressure)
{
    Node *node = new Node();

    node->type = MIDI_TYPE;
    node->time = curTime;
    node->status = MIDI_ChannelPressure | chan;
    node->b1 = pressure;
    node->b2 = 0;
    
    list.Insert(node);    
}

/* System exclusive handlers */
void MIDICvt::midiSysEx(char *data, int len)
{
    if (!strip) {
        Node *node = new Node();

        node->type = SYSEX_TYPE;
        node->time = curTime;
        node->data = data;
        node->len  = len;
    
        list.Insert(node);
    }
}

void MIDICvt::midiSysExStart(char *data, int len)
{
    if (!strip) {
        Node *node = new Node();

        node->type = SYSEX_TYPE;
        node->time = curTime;
        node->data = data;
        node->len  = len;
    
        list.Insert(node);
    }
}

void MIDICvt::midiWriteTrack(int )
{
    Node *item;
    long lastTime = 0;
    
    for (item = list.head; item != 0; item = item->next) {

        long delta = item->time - lastTime;

	if(item->type == MIDI_TYPE) {
            writeMidiEvent(delta, item->status, item->b1, item->b2);
	} else if(item->type == META_TYPE) {
            writeMetaEvent(delta, item->subtype, item->data, (int)item->len);
	}

        lastTime = item->time;
    }
}