midifile.c++ 5.23 KB
//====================================================================
// midifile.c++
//
// Synopsis:
//
// Author(s)
//  Steve Shepard
//
// Copyright 1993, Silicon Graphics, Inc.
// All Rights Reserved.
//
// This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
// the contents of this file may not be disclosed to third parties, copied or
// duplicated in any form, in whole or in part, without the prior written
// permission of Silicon Graphics, Inc.
//
// RESTRICTED RIGHTS LEGEND:
// Use, duplication or disclosure by the Government is subject to restrictions
// as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
// and Computer Software clause at DFARS 252.227-7013, and/or in similar or
// successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
// rights reserved under the Copyright Laws of the United States.
//====================================================================

#include "midifile.h"
#include "time.h"

MIDIFile::MIDIFile()
{
    file        = NULL;
    tracks      = NULL;
    division    = NULL;
}

int MIDIFile::Open(const char *name, const char *rw)
{
    file = fopen(name, rw);
    if (!file)
        return -1;

    if (parseFile() != 0)
        return -1;
    
}

int MIDIFile::Close()
{
    return fclose(file);
}

Event *MIDIFile::GetNextEvent(int trackNum)
{
    int         i;
    ListIter    iter;
    Track       *track;

    if (trackNum >= trackList.GetCount()) {
        printf("invalid track number %d\n", trackNum);
        return 0;
    }
    
    trackList.PointToFirst(iter);
    for (i = 0; i < trackNum; i++) {
        trackList.PointToNext(iter);        
    }

    if ((track = trackList.GetIteratorValue(iter)) != NULL) {
        return track->GetNextEvent();
    } else {
        return 0;
    }
}

int MIDIFile::GetTrackCount()
{
    return tracks;
}

int MIDIFile::parseFile()
{
    TrackHdr    hdr;
    ChunkHdr    chdr;
    int         count;
    int         i;
    
    count = fread (&chdr, sizeof(ChunkHdr), 1, file);
    if (count != 1)
        return -1;

    count = fread(&hdr, (int) chdr.ckSize, 1, file);
    if (count != 1)
        return -1;
    
    division = hdr.division;
    tracks = hdr.ntrks;
    
    ListIter iter;
    for (i = 0; i < tracks; i++) {
        Track *track = new Track(i);
        count = parseTrack(track);
        trackList.PointToLast(iter);
        trackList.AppendData(iter, track);
    }
}

int MIDIFile::parseTrack(Track *track)
{
    unsigned long time;
    ChunkHdr    chdr;
    
    int count = fread(&chdr, sizeof(ChunkHdr), 1, file);
    assert(count == 1);

    Time curTime(0, division);

    for (count = 0; count < chdr.ckSize; ) {
        Event *event;
        count += parseVarLen(&time, file);
        count += parseEvent(&event);

        Time deltaTime((int)time, division);            
        curTime += deltaTime;

        event->SetTime(curTime);
        track->AddEvent(event);
    }

    return count;
}

int MIDIFile::parseEvent(Event **event)
{
    int         bytes = 0;
    
    unsigned char type = getc(file);
    bytes += 1;
    
    if (type == 0xff) {

        char c = getc(file); /* meta event type */
        bytes += 1;

        switch (c) {
            case (0x0):
                *event = new MSeqNum();
                break;
                
            case (0x1):
            case (0x2):
            case (0x3):
            case (0x4):
            case (0x5):
            case (0x6):
            case (0x7):
                *event = new MTextEvent();
                break;
                
            case (0x2f):
                *event = new MEndTrack();
                break;
                
            case (0x51):
                *event = new MSetTempo();
                break;
                
            case (0x54):
                *event = new MSMPTE();
                break;
                
            case (0x58):
                *event = new MTimeSig();
                break;
                
            case (0x59):
                *event = new MKeySig();
                break;
                
            case (0x7f):
            default:
                *event = new MetaEvent();
                break;
        }

        ((MetaEvent *)*event)->SetSubtype(c);
        
    } else if ((type >= 0xf0) && (type <= 0xfe)) {
        printf("sysx\n");
    } else {
        static char status=0;
        if ((type >> 4) < 0x8) { // running status
            assert(status != 0);
            *event = new MIDIEvent(status);
            ungetc(type, file);
            bytes--;
        } else {
            *event = new MIDIEvent(type);
            status = type;
        }
    }
    
    bytes += (*event)->Init(file);

    return bytes;
}

void MIDIFile::Print()
{
    ListIter	iter;
    Track       *track;

    for (trackList.PointToFirst( iter );
         (track = trackList.GetIteratorValue( iter )) != NULL;
	 trackList.PointToNext( iter )) {

        track->Print();
    }
}

int parseVarLen(unsigned long *rval, FILE *file)
{
    register long value = 0;
    register char c;
    int i = 1;
    
    if ((value = getc(file)) & 0x80) {
        value &= 0x7f;
        do {
            value = (value << 7) + ((c = getc(file)) & 0x7f);
            i++;
        } while (c & 0x80);
    }

    *rval = value;
    
    return i;
}