Files
Work/midiseq/miditrck.cpp
2024-08-07 09:16:27 -04:00

449 lines
11 KiB
C++

#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;
}