?? midifile.cpp
字號:
// MidiFile.cpp
#include "midifile.h"
// --- construct a MIDIFile object to read and parse an SMF file
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::MIDIFile
// | Description :
// |
// | rFile :
// | bBypassSysEx :
// |
// +-------------------------------------------------------------
MIDIFile::MIDIFile(std::ifstream& rFile,bool bBypassSysEx) :
m_pIfile(&rFile),
m_bBypassSysEx(bBypassSysEx)
{
InitializeMembers();
m_pOfile = 0;
}
// --- construct a MIDIFile object to write an SMF file
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::MIDIFile
// | Description :
// |
// | rFile :
// | format :
// | tracks :
// | division :
// |
// +-------------------------------------------------------------
MIDIFile::MIDIFile(std::ofstream& rFile, Short format,Short tracks,Short division) :
m_pOfile(&rFile)
{
assert(tracks == 1 || format != 0);
assert(format >= 0 && format <= 2);
InitializeMembers();
m_nFormat = format;
m_nTracks = tracks;
m_nDivision = division;
m_pIfile = 0;
}
// ---- called by constructors to initialize the data members
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::InitializeMembers
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::InitializeMembers()
{
// --- ensure that typedefs are properly set
assert(sizeof(Short) == 2 && sizeof(Long) == 4);
m_nFormat = 0;
m_nTracks = 0;
m_nDivision = 0;
m_nDeltaTime = 0;
m_bEot = false;
m_bOverride = false;
m_bBypassSysEx = false;
m_bWritingTrack = false;
m_nTrackNo = 0;
m_nTrackLength = 0;
}
// ------ get a byte from the SMF file
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::GetMIDIChar
// | Description :
// |
// +-------------------------------------------------------------
Short MIDIFile::GetMIDIChar() throw (MFBadEof)
{
if (m_pIfile->eof()) // eof should not occur because length values
throw MFBadEof(); // in file control when to call for characters
if (m_pIfile->fail()) // if file does not exist or other input problem
throw MFIFileFail();
char ch;
m_pIfile->get(ch);
return static_cast<Short>(ch) & 0x00ff;
}
// ------- get a byte from the SMF file's track chunk
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::GetMIDITrackChar
// | Description :
// |
// +-------------------------------------------------------------
Short MIDIFile::GetMIDITrackChar() throw (MFBadTrkData)
{
if (--m_nTrackLength < 0) // if the track length is exhausted, we
throw MFBadTrkData(); // should not be asking for more bytes
return GetMIDIChar();
}
// ---- convert byte stream to integer (Endian conversion from MIDI to X86)
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::AtoInt
// | Description :
// |
// | str :
// | nLen :
// |
// +-------------------------------------------------------------
Long MIDIFile::AtoInt(const char* str,int nLen)
{
Long rtn = 0;
for (int i = 0; i < nLen; i++) {
rtn <<= 8;
rtn |= (static_cast<Long>(str[i] & 0x000000ff));
}
return rtn;
}
// ---- read a fixed-length integer
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadInt
// | Description :
// |
// | nCount :
// |
// +-------------------------------------------------------------
Long MIDIFile::ReadInt(int nCount)
{
char* str = new char[nCount];
// --- read the bytes into a buffer
for (int i = 0; i < nCount; i++)
str[i] = GetMIDIChar();
// --- convert the buffer to an integer
Long rtn = AtoInt(str,nCount);
delete [] str;
return rtn;
}
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::WriteInt
// | Description :
// |
// | nCount :
// | value :
// |
// +-------------------------------------------------------------
void MIDIFile::WriteInt(int nCount,Long value)
{
char str[4];
int i;
for (i = 3; i >= 0; --i) {
str[i] = static_cast<unsigned char>(value & 0xff);
value >>= 8;
}
for (i = 4 - nCount; i < 4; i++)
m_pOfile->put(str[i]);
}
// ---- read the SMF header chunk
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadHeader
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::ReadHeader() throw (std::runtime_error)
{
char buff[5]; // Buffer for signature "MThd"
// ----- read the signature
for (int i = 0; i < 4; i++)
buff[i] = GetMIDIChar();
buff[i] = '\0';
// ----- validate the signature
if (std::string(buff) != "MThd")
throw MFBadSig();
// Read and validate the header length (must be 6)
if (Read32() != 6)
throw MFBadHdrLen();
// Read the file format (0, 1, 2)
if ((m_nFormat = Read16()) > 2)
throw MFBadFmt();
// Read the number of tracks
if ((m_nTracks = Read16()) < 0)
throw MFBadTrks();
// Read the quarter-note division
if ((m_nDivision = Read16()) < 0)
throw MFBadDiv();
// --- notify the user of the header and its contents
Header(m_nFormat,m_nTracks,m_nDivision);
}
// ---- read an SMF variable length integer value (event lengths and delta times)
// encoded as a byte stream
// the last byte has the msb == 0
// all others have msb == 1
// bits 0-7 contain the parts of the integer
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadVarLength
// | Description :
// |
// | exc :
// |
// +-------------------------------------------------------------
Long MIDIFile::ReadVarLength(std::runtime_error& exc) throw (std::runtime_error)
{
Long value = 0;
int c;
do {
c = GetMIDITrackChar();
value = (value << 7) + (c & 0x7f);
} while (c & 0x80);
if (value < 0)
throw exc;
return value;
}
// ---- write an SMF variable length integer value
// return the number of bytes written
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::WriteVarLength
// | Description :
// |
// | value :
// |
// +-------------------------------------------------------------
int MIDIFile::WriteVarLength(Long value)
{
unsigned char cBytes[4];
int nCt = 1;
for (int i = 3; i >= 0; --i) {
*(cBytes + i) = (unsigned char)(value & 0x7f);
value >>= 7;
}
for (i = 0; i < 3; i++) {
if (*(cBytes + i) != 0) {
while (i < 3) {
*(cBytes + i) |= 0x80;
m_pOfile->put(cBytes[i++]);
nCt++;
}
}
}
m_pOfile->put(cBytes[3]);
return nCt;
}
// --- return number of parameters based on channel status code
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ParamCount
// | Description :
// |
// | status :
// |
// +-------------------------------------------------------------
int MIDIFile::ParamCount(Short status)
{
if (status == 0xf2) // not sure whether f2 & f3 would ever
return 2;
if (status == 0xf3) // be in an SMF file, but better be safe
return 1;
if (status >= 0xf0)
return 0;
if (status >= 0xe0)
return 2;
if (status < 0xc0)
return 2;
return 1;
}
// ---- Read a system exclusive message
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadSysex
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::ReadSysex()
{
// Read length of system exclusive event
Long length = ReadVarLength(MFBadMetaEvLen());
if (m_bBypassSysEx) {
// ---- bypass the system exclusive event
for (int i = 0; i < length; i++)
GetMIDITrackChar();
SystemExclusive(m_nDeltaTime,length,0);
}
else {
m_data.EventBuffer(length);
// Read in the system exclusive event
for (int i = 0; i < length; i++)
m_data.bf[i] = GetMIDITrackChar();
SystemExclusive(m_nDeltaTime,length,m_data.bf);
}
}
// ---- Read a system exclusive message packet
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadSysexPacket
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::ReadSysexPacket()
{
// Read length of system exclusive event packet
Long length = ReadVarLength(MFBadMetaEvLen());
if (m_bBypassSysEx) {
// ---- bypass the system exclusive event packet
for (int i = 0; i < length; i++)
GetMIDITrackChar();
SystemExclusivePacket(m_nDeltaTime,length,0);
}
else {
m_data.EventBuffer(length);
// Read in the system exclusive event packet
for (int i = 0; i < length; i++)
m_data.bf[i] = GetMIDITrackChar();
SystemExclusivePacket(m_nDeltaTime,length,m_data.bf);
}
}
// ---- read a meta event
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadMeta
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::ReadMeta() throw (std::runtime_error)
{
// --------- Meta message
int msg_type = GetMIDITrackChar(); // Type of meta-event
// Read length of meta event
Long length = ReadVarLength(MFBadMetaEvLen());
m_data.EventBuffer(length);
// Read in the meta event
for (int i = 0; i < length; i++)
m_data.bf[i] = GetMIDITrackChar();
switch(msg_type) {
case META_SEQNUM: // Sequence number
if (length < 2)
throw MFBadMetaEvLen();
SequenceNum(m_nDeltaTime,static_cast<Short>(AtoInt(m_data.bf,2)));
break;
case META_TEXT: // Text event
case META_COPYRIGHT: // Copyright notice
case META_SEQTRKNAME: // Sequence name
case META_INSTNAME: // Instrument name
case META_LYRIC: // Lyric
case META_MARKER: // Marker
case META_CUEPT: // Cue point
TextEvent(m_nDeltaTime,msg_type,length,m_data.bf);
break;
case META_TEMPO: // Set tempo
if (length < 3)
throw MFBadMetaEvLen();
Tempo(m_nDeltaTime,AtoInt(m_data.bf,3));
break;
case META_SMPTE: // SMPTE offset
{
if (length < 5)
throw MFBadMetaEvLen();
int hour = static_cast<int>(m_data.bf[0]);
int min = static_cast<int>(m_data.bf[1]);
int sec = static_cast<int>(m_data.bf[2]);
int frame = static_cast<int>(m_data.bf[3]);
int fract = static_cast<int>(m_data.bf[4]);
SMPTE(m_nDeltaTime,hour,min,sec,frame,fract);
break;
}
case META_TIMESIG: // Time signature
{
if (length < 4)
throw MFBadMetaEvLen();
int numer = static_cast<int>(m_data.bf[0]);
int denom = static_cast<int>(m_data.bf[1]);
int clocks = static_cast<int>(m_data.bf[2]);
int qnotes = static_cast<int>(m_data.bf[3]);
TimeSignature(m_nDeltaTime,numer,denom,clocks,qnotes);
break;
}
case META_KEYSIG: // Key signature
{
if (length < 2)
throw MFBadMetaEvLen();
int sharpflat = static_cast<int>(m_data.bf[0]);
int minor = (static_cast<int>(m_data.bf[1]) == 1);
if (sharpflat > 7 || sharpflat < -7 ||
(minor != 0 && minor != 1))
throw MFBadMetaEvVal();
KeySignature(m_nDeltaTime,sharpflat,minor == 1);
break;
}
case META_SEQSPEC: // Sequencer-specific
SequencerSpecific(m_nDeltaTime,length,m_data.bf);
break;
case META_CHANPFX: // Channel prefix
if (length < 1)
throw MFBadMetaEvLen();
ChannelPrefix(m_nDeltaTime,m_data.bf[0]);
break;
case META_EOT: // End of track
if (length != 0)
throw MFBadMetaEvLen();
EndOfTrack(m_nDeltaTime);
m_bEot = true;
break;
default:
UnknownMetaType(m_nDeltaTime,msg_type);
break;
}
}
// ----- read an event chunk
// +-------------------------------------------------------------
// |
// | Function : MIDIFile::ReadEvent
// | Description :
// |
// +-------------------------------------------------------------
void MIDIFile::ReadEvent() throw (std::runtime_error)
{
static unsigned char running_status = 0x00; // Running status
static unsigned char params[2]; // Event parameters
int cur_param; // Parameter being currently read
m_bOverride = true; // false if user does not override event function
// -------- Read delta-time
Long delta_time = ReadVarLength(MFBadDeltaTime());
m_nDeltaTime += delta_time;
// -------- Read event type
unsigned char stat = GetMIDITrackChar();
if (stat & 0x80) { // Is it a new event type?
running_status = stat; // Set new running status
cur_param = 0; // Start reading at 0th param
} else {
// --- continuation of running status
params[0] = stat; // Record 1st parameter
cur_param = 1; // Start reading at 1st param
}
// -------- Read the parameters corresponding to the status byte
for (int i = ParamCount(running_status)-cur_param; i > 0; i--,cur_param++)
params[cur_param] = GetMIDITrackChar();
// ---- break status into its two parts
int channel = running_status & 0x0f;
int event = running_status & 0xf0;
switch (event) {
case MIDI_NOTEOFF: // Note off
NoteOff(m_nDeltaTime,channel,params[0],params[1]);
break;
case MIDI_NOTEON: // Note on
NoteOn(m_nDeltaTime,channel,params[0],params[1]);
break;
case MIDI_PRESSURE: // Polyphonic key pressure
Pressure(m_nDeltaTime,channel,params[0],params[1]);
break;
case MIDI_CONTROL: // Control change
Controller(m_nDeltaTime,channel,params[0],params[1]);
break;
case MIDI_PROGRAM: // Program change
ProgramChange(m_nDeltaTime,channel,params[0]);
break;
case MIDI_CHANPRES: // Channel pressure
ChannelPressure(m_nDeltaTime,channel,params[0]);
break;
case MIDI_PITCHBEND:// Pitch wheel change
{
Short pitch = (static_cast<Short>(AtoInt(reinterpret_cast<const char*>(params),2)));
PitchBend(m_nDeltaTime,channel,pitch);
break;
}
case SYSEX_META: // System-exclusive or meta event
switch (running_status) {
case 0xf0:
ReadSysex();
break;
case 0xf7:
ReadSysexPacket();
break;
case 0xff:
ReadMeta();
break;
// ------- ( there are several realtime events, but they
// would not be found in an SMF file -------------
default:
UnknownStatus(m_nDeltaTime,channel,event);
break;
}
break;
default:
UnknownStatus(m_nDeltaTime,channel,event);
break;
}
// --- If the user overrides the event, set delta time to 0.
// Otherwise allow it to accumulate so that the variable always
// represents elapsed time since the last user-intercepted event.
// How do we know? The overridable functions set m_bOverride to
// false. Overriding functions do not.
if (m_bOverride)
m_nDeltaTime = 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -