// // Copyright 1997 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Mon Mar 3 22:23:34 GMT-0800 1997 // Last Modified: Mon Mar 3 22:23:34 GMT-0800 1997 // Last Modified: Sun Mar 24 12:10:00 PST 2002 (small changes for visual c++) // Filename: ...sig/src/sigInfo/MidiFile2.cpp // Web Address: http://sig.sapp.org/src/sigInfo/MidiFile2.cpp // Syntax: C++ // // Description: Older version of the MidiFile class. Different // memory management handling. // #include "MidiFile2.h" #include #ifndef OLDCPP #include #include using namespace std; #else #include #include #endif typedef unsigned int uint; ////////////////////////////// // // MidiFile2::MidiFile2 -- // MidiFile2::MidiFile2(void) { midiData = NULL; dataSize = 0; trackStart = NULL; trackSize = NULL; currTrackIndex = NULL; currTrackCommand = NULL; trackLoopCount = NULL; } MidiFile2::MidiFile2(const char* filename) { midiData = NULL; dataSize = 0; trackStart = NULL; trackSize = NULL; currTrackIndex = NULL; currTrackCommand = NULL; trackLoopCount = NULL; input(filename); } ////////////////////////////// // // MidiFile2::~MidiFile2 -- // MidiFile2::~MidiFile2() { if (midiData != NULL) delete [] midiData; midiData = NULL; dataSize = 0; if (trackStart != NULL) delete [] trackStart; trackStart = NULL; if (trackSize != NULL) delete [] trackSize; trackSize = NULL; if (currTrackIndex != NULL) delete [] currTrackIndex; currTrackIndex = NULL; if (currTrackCommand != NULL) delete [] currTrackCommand; currTrackCommand = NULL; if (trackLoopCount != NULL) delete [] trackLoopCount; trackLoopCount = NULL; } ////////////////////////////// // // MidiFile2::backtrack -- subtrack one from a track index pointer // void MidiFile2::backtrack(int aTrack) { currTrackIndex[aTrack]--; } ////////////////////////////// // // MidiFile2::eot -- returns the loop count, used to check if // this is the first end of track. // int MidiFile2::eot(int aTrack) { return trackLoopCount[aTrack]; } ////////////////////////////// // // MidiFile2::extractByte -- extracts a byte from a track // uchar MidiFile2::extractByte(int aTrack) { uchar output; output = midiData[currTrackIndex[aTrack]]; currTrackIndex[aTrack]++; if (currTrackIndex[aTrack] >= trackStart[aTrack] + trackSize[aTrack] + 8) { trackLoopCount[aTrack]++; currTrackIndex[aTrack] = trackStart[aTrack] + 8; } return output; } ////////////////////////////// // // MidiFile2::extractVLVtime -- gets the delta time // of the specified midi track // ulong MidiFile2::extractVLVtime(int aTrack) { uchar temp; ulong output = 0; temp = extractByte(aTrack); if (temp < 0x80) { output |= temp; return output; } else { output |= 0x7f & temp; output = (output << 7); } temp = extractByte(aTrack); if (temp < 0x80) { output |= temp; return output; } else { output |= 0x7f & temp; output = (output << 7); } temp = extractByte(aTrack); if (temp < 0x80) { output |= temp; return output; } else { output |= 0x7f & temp; output = (output << 7); } temp = extractByte(aTrack); if (temp < 0x80) { output |= temp; return output; } else { output |= 0x7f & temp; output = (output << 7); } cerr << "Error: VLV delta time is too big!" << endl; return 0xffffffff; } ////////////////////////////// // // MidiFile2::getNumTracks -- returns the number of tracks in // the midi file. The number of tracks is stored in // the 4th field of the midi file header in two bytes // from bytes 10-11 (offset 0). // int MidiFile2::getNumTracks(void) { int output = flip2bytes(*((unsigned short*)&midiData[10])); return output; } ////////////////////////////// // // MidiFile2::getTicksPerQuarterNote -- returns the number of // clock ticks per quarternote in the MIDI file. The // number of ticks is stored in the 5th field of the // MIDI file header in two bytes from bytes 12-13 (offset 0) // int MidiFile2::getTicksPerQuarterNote(void) { int output = flip2bytes(*((unsigned short*)&midiData[12])); return output; } ////////////////////////////// // // MidiFile2::getNextMessage -- returns the next midi message // for a given track the time information is the // number of clock ticks for the delta time of the // message. // MidiMessage MidiFile2::getNextMessage(int aTrack) { MidiMessage output; output.time = 0; marker: int timevalue; timevalue = extractVLVtime(aTrack); output.time += timevalue; output.command() = extractByte(aTrack); // make sure not in running status if (output.command() < 0x80) { backtrack(aTrack); output.command() = currTrackCommand[aTrack]; } else { currTrackCommand[aTrack] = output.command(); } // ignore meta messages // might want to not ignore end of track meta, depends on MidiFile2 creation if (output.command() == 0xff) { extractByte(aTrack); // the meta type int metaSize = extractVLVtime(aTrack); for (int i=0; i> 8) | (aNumber << 8); return output; } ////////////////////////////// // // MidiFile2::flip4bytes -- the fun of Intel processors: they are // little endian and bytes in a midi file are big endian. // ulong MidiFile2::flip4bytes(ulong aNumber) { ushort output = 0; output |= (aNumber << 24) & 0xff000000; output |= (aNumber << 8) & 0x00ff0000; output |= (aNumber >> 8) & 0x0000ff00; output |= (aNumber >> 24) & 0x000000ff; return output; } ////////////////////////////// // // MidiFile2::setupTrackStart -- // void MidiFile2::setupTrackStart(void) { // get the first track location which is always the same if (midiData[14] == 'M' && midiData[15] == 'T' && midiData[16] == 'r' && midiData[17] == 'k' ) { trackStart[0] = 14; trackSize[0] = flip4bytes( *((ulong*)&midiData[18]) ); currTrackIndex[0] = trackStart[0] + 8; trackLoopCount[0] = 0; } else { cerr << "Error: invalid track: 0" << endl; exit(1); } int counter = trackStart[0]; int i; for (i=1; i