Initial
This commit is contained in:
448
midiseq/miditrck.cpp
Normal file
448
midiseq/miditrck.cpp
Normal file
@@ -0,0 +1,448 @@
|
||||
#include <common/math.hpp>
|
||||
#include <midiseq/miditrck.hpp>
|
||||
|
||||
bool MidiTrack::readTrack(void)
|
||||
{
|
||||
mBytesRead=0;
|
||||
if(PureHeader::Unset==mTimingMethod)return false;
|
||||
if(!mMidiFile.read(mTrack,sizeof(mTrack)))return false;
|
||||
if(::strncmp(mTrack,"MTrk",sizeof(mTrack)))return false;
|
||||
if(!mMidiFile.read(mLengthData))return false;
|
||||
if(!mLengthData)return false;
|
||||
readTime();
|
||||
|
||||
while(mBytesRead<mLengthData)
|
||||
{
|
||||
if(!mMidiFile.read(mEventType))return true;
|
||||
mBytesRead++;
|
||||
if(!handleEvent())return true;
|
||||
if(mBytesRead>=mLengthData)break;
|
||||
readTime();
|
||||
if(NullEvent==mRunningEvent)mLastEventType=mEventType;
|
||||
else mLastEventType=mRunningEvent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiTrack::readTime(void)
|
||||
{
|
||||
switch(mTimingMethod)
|
||||
{
|
||||
case PureHeader::DeltaTime :
|
||||
case PureHeader::TimeCode :
|
||||
mDeltaTime=readVarLength();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleEvent(void)
|
||||
{
|
||||
WORD returnCode;
|
||||
|
||||
switch(mEventType)
|
||||
{
|
||||
case MetaEvent :
|
||||
mRunningEvent=NullEvent;
|
||||
returnCode=handleMetaEvent();
|
||||
break;
|
||||
case SystemExclusiveOne :
|
||||
case SystemExclusiveTwo :
|
||||
mRunningEvent=NullEvent;
|
||||
returnCode=handleSystemExclusiveEvent();
|
||||
break;
|
||||
default :
|
||||
returnCode=handleMIDIChannelMessage();
|
||||
break;
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
WORD MidiTrack::isChannelMessage(BYTE eventType)const
|
||||
{
|
||||
BYTE status((eventType>>4)&0x0F);
|
||||
|
||||
if((status<=0x07)||(0x0F==status))
|
||||
{
|
||||
outDebug("[isChannelMessage] FAIL",eventType);
|
||||
return false;
|
||||
}
|
||||
if((status>=0x08&&status<=0x0B)||(status==0x0E))return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleMIDIChannelMessage(void)
|
||||
{
|
||||
WORD returnCode;
|
||||
|
||||
if(isRunningStatus(mEventType))
|
||||
{
|
||||
if(NullEvent==mRunningEvent)mRunningEvent=mLastEventType;
|
||||
mLastData=mEventType;
|
||||
mEventType=mLastEventType;
|
||||
}
|
||||
else mRunningEvent=NullEvent;
|
||||
if(isChannelMessage(mEventType))returnCode=processMIDIChannelMessage();
|
||||
else returnCode=FALSE;
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleMetaEvent(void)
|
||||
{
|
||||
BYTE entryType;
|
||||
WORD returnCode(TRUE);
|
||||
|
||||
if(!mMidiFile.read(entryType))return FALSE;
|
||||
mBytesRead++;
|
||||
switch(entryType)
|
||||
{
|
||||
case SequenceNumberEvent :
|
||||
outDebug("[handleMetaEvent]SequenceNumberEvent");
|
||||
returnCode=handleMetaSequenceNumberEvent();
|
||||
break;
|
||||
case TextEvent :
|
||||
outDebug("[handleMetaEvent]TextEvent");
|
||||
returnCode=handleMetaTextEvent();
|
||||
break;
|
||||
case CopyrightNotice :
|
||||
outDebug("[handleMetaEvent]CopyrightNotice");
|
||||
returnCode=handleMetaTextEvent();
|
||||
break;
|
||||
case SequenceTrackName :
|
||||
outDebug("[handleMetaEvent]SequenceTrackName");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case InstrumentName :
|
||||
outDebug("[handleMetaEvent]InstrumentName");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case Lyric :
|
||||
outDebug("[handleMetaEvent]Lyric");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case Marker :
|
||||
outDebug("[handleMetaEvent]Marker");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case CuePoint :
|
||||
outDebug("[handleMetaEvent]CuePoint");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case ChannelPrefix :
|
||||
outDebug("[handleMetaEvent]ChannelPrefix");
|
||||
handleChannelPrefix();
|
||||
break;
|
||||
case EndOfTrack :
|
||||
outDebug("[handleMetaEvent]EndOfTrack");
|
||||
handleGenericMetaEvent();
|
||||
endOfTrack();
|
||||
returnCode=FALSE;
|
||||
break;
|
||||
case SetTempo :
|
||||
outDebug("[handleMetaEvent]SetTempo");
|
||||
handleSetTempoEvent();
|
||||
break;
|
||||
case SMPTEFormatSpec :
|
||||
outDebug("[handleMetaEvent]SMTPFormatSpec");
|
||||
handleSMPTEFormatEvent();
|
||||
break;
|
||||
case TimeSignature :
|
||||
outDebug("[handleMetaEvent]TimeSignature");
|
||||
handleTimeSignatureEvent();
|
||||
break;
|
||||
case KeySignature :
|
||||
outDebug("[handleMetaEvent]KeySignature");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
case SequencerSpecificMetaEvent :
|
||||
outDebug("[handleMetaEvent]SequencerSpecificMetaEvent");
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
default :
|
||||
handleGenericMetaEvent();
|
||||
break;
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleSystemExclusiveEvent(void)
|
||||
{
|
||||
return handleGenericMetaEvent();
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleMetaSequenceNumberEvent(void)
|
||||
{
|
||||
WORD sequenceNumber;
|
||||
|
||||
if(!mMidiFile.read(sequenceNumber))return FALSE;
|
||||
mBytesRead++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleMetaTextEvent(void)
|
||||
{
|
||||
BYTE textLength;
|
||||
BYTE textByte;
|
||||
String strText;
|
||||
|
||||
if(!mMidiFile.read(textLength))return FALSE;
|
||||
mBytesRead++;
|
||||
for(short index=0;index<textLength;index++)
|
||||
{
|
||||
if(!mMidiFile.read(textByte))return FALSE;
|
||||
strText+=textByte;
|
||||
mBytesRead++;
|
||||
}
|
||||
textMessage(strText);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleSetTempoEvent(void)
|
||||
{
|
||||
DWORD microsecsPerQtrNote(0L);
|
||||
BYTE tempoBytes[TempoEventLength];
|
||||
short entryLength;
|
||||
|
||||
entryLength=(short)readVarLength();
|
||||
if(sizeof(tempoBytes)!=entryLength)return FALSE;
|
||||
if(!mMidiFile.read(tempoBytes,sizeof(tempoBytes)))return FALSE;
|
||||
microsecsPerQtrNote+=(DWORD)tempoBytes[0]*65536L;
|
||||
microsecsPerQtrNote+=(DWORD)tempoBytes[1]*256L;
|
||||
microsecsPerQtrNote+=(DWORD)tempoBytes[2];
|
||||
outDebug(String("[MidiTrack::handleSetTempoEvent] microsecsPerQtrNote=")+String().fromInt(microsecsPerQtrNote));
|
||||
setTempo(microsecsPerQtrNote);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleTimeSignatureEvent(void)
|
||||
{
|
||||
BYTE tsBytes[TimeInfo::LengthTimeInfo];
|
||||
|
||||
if(TimeInfo::LengthTimeInfo!=readVarLength())return FALSE;
|
||||
if(!mMidiFile.read(tsBytes,sizeof(tsBytes)))return FALSE;
|
||||
TimeInfo midiTimeSignature(tsBytes[0],Math::power(2,tsBytes[1]),tsBytes[2],tsBytes[3]);
|
||||
timeSignature(midiTimeSignature);
|
||||
outDebug("[handleTimeSignatureEvent]"+midiTimeSignature.toString());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleSMPTEFormatEvent(void)
|
||||
{
|
||||
SMPTEFormat smpteFormatInfo;
|
||||
if(SMPTEFormat::SMPTEFormatLength!=readVarLength())
|
||||
{
|
||||
outDebug("[handleSMPTEFormatEvent] Unexpected SMPTEFormatLength");
|
||||
return FALSE;
|
||||
}
|
||||
smpteFormatInfo<<mMidiFile;
|
||||
smpteFormat(smpteFormatInfo);
|
||||
outDebug("[handleSMPTEFormatEvent]"+smpteFormatInfo.toString());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleChannelPrefix(void)
|
||||
{
|
||||
BYTE charByte;
|
||||
short entryLength;
|
||||
|
||||
entryLength=readVarLength();
|
||||
for(short index=0;index<entryLength;index++){if(!mMidiFile.read(charByte))return FALSE;mBytesRead++;}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::handleGenericMetaEvent(void)
|
||||
{
|
||||
BYTE charByte;
|
||||
short entryLength;
|
||||
|
||||
entryLength=(short)readVarLength();
|
||||
for(short index=0;index<entryLength;index++){if(!mMidiFile.read(charByte))return FALSE;mBytesRead++;}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WORD MidiTrack::processMIDIChannelMessage(void)
|
||||
{
|
||||
WORD returnCode(TRUE);
|
||||
BYTE channel;
|
||||
BYTE messageDataOne;
|
||||
BYTE messageDataTwo;
|
||||
BYTE requiredDataBytes;
|
||||
|
||||
channel=mEventType&0x0F;
|
||||
requiredDataBytes=isChannelMessage(mEventType);
|
||||
switch(mEventType&0xF0)
|
||||
{
|
||||
case MIDIProgramChange :
|
||||
if(NullEvent==mRunningEvent)mMidiFile.read(messageDataOne);
|
||||
else messageDataOne=mLastData;
|
||||
messageDataOne&=0x7F;
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,messageDataOne,0));
|
||||
if(NullEvent!=mRunningEvent)mBytesRead++;
|
||||
break;
|
||||
case MIDINoteOff :
|
||||
if(PureNote::PureNoteLength!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)mNoteOff<<mMidiFile;
|
||||
else
|
||||
{
|
||||
mMidiFile.read(messageDataOne);
|
||||
mNoteOff.pitch(mLastData);
|
||||
mNoteOff.velocity(messageDataOne);
|
||||
channel=mLastChannel;
|
||||
}
|
||||
mNoteOff.pitch(mNoteOff.pitch()&0x7F);
|
||||
mNoteOff.velocity(mNoteOff.velocity()&0x7F);
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,mNoteOff.pitch(),mNoteOff.velocity()));
|
||||
if(NullEvent==mRunningEvent)mBytesRead+=PureNote::PureNoteLength;
|
||||
else mBytesRead+=PureNote::PureNoteLength-1;
|
||||
break;
|
||||
case MIDINoteOn :
|
||||
if(PureNote::PureNoteLength!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)mNoteOn<<mMidiFile;
|
||||
else
|
||||
{
|
||||
mMidiFile.read(messageDataOne);
|
||||
mNoteOn.pitch(mLastData);
|
||||
mNoteOn.velocity(messageDataOne);
|
||||
channel=mLastChannel;
|
||||
}
|
||||
mNoteOn.pitch(mNoteOn.pitch()&0x7F);
|
||||
mNoteOn.velocity(mNoteOn.velocity()&0x7F);
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,mNoteOn.pitch(),mNoteOn.velocity()));
|
||||
if(NullEvent==mRunningEvent)mBytesRead+=PureNote::PureNoteLength;
|
||||
else mBytesRead+=PureNote::PureNoteLength-1;
|
||||
break;
|
||||
case MIDIKeyPressure :
|
||||
if(2!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)
|
||||
{
|
||||
mMidiFile.read(messageDataOne);
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageDataOne=mLastData;
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
messageDataOne&=0x7F;
|
||||
messageDataTwo&=0x7F;
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,messageDataOne,messageDataTwo));
|
||||
if(NullEvent==mRunningEvent)mBytesRead+=requiredDataBytes;
|
||||
else mBytesRead++;
|
||||
break;
|
||||
case MIDIParameter :
|
||||
if(2!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)
|
||||
{
|
||||
mMidiFile.read(messageDataOne);
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageDataOne=mLastData;
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
messageDataOne&=0x7F;
|
||||
messageDataTwo&=0x7F;
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,messageDataOne,messageDataTwo));
|
||||
if(NullEvent==mRunningEvent)mBytesRead+=requiredDataBytes;
|
||||
else mBytesRead++;
|
||||
break;
|
||||
case MIDIPitchBend :
|
||||
if(2!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)
|
||||
{
|
||||
mMidiFile.read(messageDataOne);
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageDataOne=mLastData;
|
||||
mMidiFile.read(messageDataTwo);
|
||||
}
|
||||
messageDataOne&=0x7F;
|
||||
messageDataTwo&=0x7F;
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,messageDataOne,messageDataTwo));
|
||||
if(NullEvent==mRunningEvent)mBytesRead+=requiredDataBytes;
|
||||
else mBytesRead++;
|
||||
break;
|
||||
case MIDIChannelPressure :
|
||||
if(1!=requiredDataBytes){returnCode=FALSE;break;}
|
||||
if(NullEvent==mRunningEvent)mMidiFile.read(messageDataOne);
|
||||
else messageDataOne=mLastData;
|
||||
messageDataOne&=0x7F;
|
||||
midiChannelMessage(PureEvent(mEventType,mDeltaTime,channel,messageDataOne,0));
|
||||
if(NullEvent==mRunningEvent)mBytesRead++;
|
||||
break;
|
||||
default :
|
||||
returnCode=FALSE;
|
||||
break;
|
||||
}
|
||||
mLastChannel=channel;
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
DWORD MidiTrack::readVarLength(void)
|
||||
{
|
||||
DWORD valueData(0L);
|
||||
BYTE byteValue;
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
mMidiFile.read(byteValue);
|
||||
mBytesRead++;
|
||||
valueData=(valueData*0x80)+(byteValue&0x7F);
|
||||
if(!(byteValue&0x80))break;
|
||||
}
|
||||
return valueData;
|
||||
}
|
||||
|
||||
void MidiTrack::outDebug(const String &message,BYTE data)const
|
||||
{
|
||||
if(!mIsDebug)return;
|
||||
String strData;
|
||||
String strHeader=String("[MidiTrack]");
|
||||
::sprintf(strData.str(),"%d (0x%08lx)",data,data);
|
||||
::OutputDebugString(strHeader+message+String(" DATA=")+strData+String("\n"));
|
||||
}
|
||||
|
||||
void MidiTrack::outDebug(const String &message)const
|
||||
{
|
||||
if(!mIsDebug)return;
|
||||
String strHeader=String("[MidiTrack]");
|
||||
::OutputDebugString(strHeader+message+String("\n"));
|
||||
}
|
||||
|
||||
// virtuals
|
||||
|
||||
void MidiTrack::setTempo(DWORD /*microsecondsPerQuarterNote*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void MidiTrack::midiChannelMessage(PureEvent &/*channelEvent*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void MidiTrack::timeSignature(const TimeInfo &/*someTimeInfo*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void MidiTrack::smpteFormat(const SMPTEFormat &/*someSMPTEFormat*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void MidiTrack::textMessage(const String &/*strText*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void MidiTrack::endOfTrack(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user