void HMISong :: DoRestart()
{
	int i;

	// Set initial state.
	FakeTrack = &Tracks[NumTracks];
	NoteOffs.Clear();
	for (i = 0; i <= NumTracks; ++i)
	{
		Tracks[i].TrackP = 0;
		Tracks[i].Finished = false;
		Tracks[i].RunningStatus = 0;
		Tracks[i].PlayedTime = 0;
	}
	ProcessInitialMetaEvents ();
	for (i = 0; i < NumTracks; ++i)
	{
		Tracks[i].Delay = ReadVarLen(&Tracks[i]);
	}
	Tracks[i].Delay = 0;	// for the FakeTrack
	Tracks[i].Enabled = true;
	TrackDue = Tracks;
	TrackDue = FindNextDue();
}
Exemple #2
0
bool PS1Seq::ReadEvent(void)
{
	uint32_t beginOffset = curOffset;
	uint32_t delta = ReadVarLen(curOffset);
	if (curOffset >= rawfile->size())
		return false;
	AddTime(delta);

	uint8_t status_byte = GetByte(curOffset++);

	//if (status_byte == 0)				//Jump Relative
	//{
	//	short relOffset = (short)GetShortBE(curOffset);
	//	AddGenericEvent(beginOffset, 4, L"Jump Relative", NULL, BG_CLR_PINK);
	//	curOffset += relOffset;

	//	curOffset += 4;		//skip the first 4 bytes (no idea)
	//	SetPPQN(GetShortBE(curOffset));
	//	curOffset += 2;
	//	AddTempo(curOffset, 3, GetWordBE(curOffset-1) & 0xFFFFFF);
	//	curOffset += 3;
	//	uint8_t numer = GetByte(curOffset++);
	//	uint8_t denom = GetByte(curOffset++);
	//	if (numer == 0 || numer > 32)				//sanity check
	//		return false;
	//	AddTimeSig(curOffset-2, 2, numer, 1<<denom, GetPPQN());
	//	SetEventsOffset(offset() + 0x0F);
	//}
//	else
		if (status_byte <= 0x7F)			// Running Status
	{
		if (status_byte == 0)			// some games were ripped to PSF with the EndTrack event missing, so
		{
			if (GetWord(curOffset) == 0)	//if we read a sequence of four 0 bytes, then just treat that
				return false;				//as the end of the track
		}
		status_byte = runningStatus;
		curOffset--;
	}
	else
		runningStatus = status_byte;


	channel = status_byte&0x0F;
	SetCurTrack(channel);

	switch (status_byte & 0xF0)
	{
	case 0x90 :						//note event
		key = GetByte(curOffset++);
		vel = GetByte(curOffset++);
		if (vel > 0)													//if the velocity is > 0, it's a note on
			AddNoteOn(beginOffset, curOffset-beginOffset, key, vel);
		else															//otherwise it's a note off
			AddNoteOff(beginOffset, curOffset-beginOffset, key);
		break;

	case 0xB0 :
		{
			uint8_t controlNum = GetByte(curOffset++);
			uint8_t value = GetByte(curOffset++);
			switch (controlNum)		//control number
			{
			case 0 :							//bank select
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Bank Select", L"", CLR_MISC);
				AddBankSelectNoItem(value);
				break;

			case 6 :							//data entry
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN Data Entry", L"", CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 7 :							//volume
				AddVol(beginOffset, curOffset-beginOffset, value);
				break;

			case 10 :							//pan
				AddPan(beginOffset, curOffset-beginOffset, value);
				break;

			case 11 :							//expression
				AddExpression(beginOffset, curOffset-beginOffset, value);
				break;

			case 64 :							//damper (hold)
				AddSustainEvent(beginOffset, curOffset-beginOffset, value);
				break;

			case 91 :							//reverb depth (_SsContExternal)
				AddReverb(beginOffset, curOffset-beginOffset, value);
				break;

			case 98 :							//(0x62) NRPN 1 (LSB)
				switch (value)
				{
				case 20 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1 #20", L"", CLR_MISC);
					break;

				case 30 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1 #30", L"", CLR_MISC);
					break;

				default:
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1", L"", CLR_MISC);
					break;
				}

				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 99 :							//(0x63) NRPN 2 (MSB)
				switch (value)
				{
				case 20 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Loop Start", L"", CLR_LOOP);
					break;

				case 30 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Loop End", L"", CLR_LOOP);
					break;

				default:
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 2", L"", CLR_MISC);
					break;
				}

				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 100 :							//(0x64) RPN 1 (LSB), no effect?
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"RPN 1", L"", CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 101 :							//(0x65) RPN 2 (MSB), no effect?
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"RPN 2", L"", CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 121 :							//reset all controllers
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reset All Controllers", L"", CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			default:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control Event", L"", CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;
			}
		}
		break;

	case 0xC0 :
		{
			uint8_t progNum = GetByte(curOffset++);
			AddProgramChange(beginOffset, curOffset-beginOffset, progNum);
		}
		break;

	case 0xE0 :
		{
			uint8_t hi = GetByte(curOffset++);
			uint8_t lo = GetByte(curOffset++);
			AddPitchBendMidiFormat(beginOffset, curOffset-beginOffset, hi, lo);
		}
		break;

	case 0xF0 : 
		{
			if (status_byte == 0xFF)
			{
				switch (GetByte(curOffset++))
				{
				case 0x51 :			//tempo.  This is different from SMF, where we'd expect a 51 then 03.  Also, supports
									//a string of tempo events
					AddTempo(beginOffset, curOffset+3-beginOffset, (GetShortBE(curOffset) << 8) | GetByte(curOffset + 2));
					curOffset += 3;
					break;
				
				case 0x2F :
					AddEndOfTrack(beginOffset, curOffset-beginOffset);
					return false;

				default :
					AddUnknown(beginOffset, curOffset-beginOffset, L"Meta Event");
					return false;
				}
			}
			else
			{
				AddUnknown(beginOffset, curOffset-beginOffset);
				return false;
			}
		}
		break;

	default:
		AddUnknown(beginOffset, curOffset-beginOffset);
		return false;
	}
	return true;
}
		}
		events += 3;

		if (ReadVarLen == ReadVarLenHMI && (event & 0x70) == (MIDI_NOTEON & 0x70))
		{ // HMI note on events include the time until an implied note off event.
			NoteOffs.AddNoteOff(track->ReadVarLenHMI(), event & 0x0F, data1);
		}
	}
	else
	{
		// Skip SysEx events just because I don't want to bother with them.
		// The old MIDI player ignored them too, so this won't break
		// anything that played before.
		if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
		{
			len = ReadVarLen(track);
			track->TrackP += len;
		}
		else if (event == MIDI_META)
		{
			// It's a meta-event
			event = track->TrackBegin[track->TrackP++];
			CHECK_FINISHED
			len = ReadVarLen(track);
			CHECK_FINISHED

			if (track->TrackP + len <= track->MaxTrackP)
			{
				switch (event)
				{
				case MIDI_META_EOT:
Exemple #4
0
static T_BOOL ReadMidiTrackEvents(MIDI_INFO *midiInfo)
{
    long delta = 0;
    unsigned char command;

    while(1)
    {
        delta += ReadVarLen(midiInfo);
        command = *midiInfo->midiData;
        midiInfo->midiData++;

        /* The followings belong to MIDI Control Events */
        if ((command & 0xf0) == 0x80 || (command & 0xf0) == 0x90)
        {
            midiInfo->midiEvent[midiInfo->eventNum].delta = delta;
            midiInfo->midiEvent[midiInfo->eventNum].command = (command & 0xf0);
            midiInfo->midiEvent[midiInfo->eventNum].channel = (command & 0x0f);
            midiInfo->midiEvent[midiInfo->eventNum].note = *midiInfo->midiData;
            midiInfo->midiData++;
            midiInfo->midiEvent[midiInfo->eventNum].velocity = *midiInfo->midiData;
            midiInfo->midiData++;
            midiInfo->eventNum++;
            delta = 0;
        }
        else if (command < 0x80)            /* running status: available in MIDI Control Events */
        {
            midiInfo->midiEvent[midiInfo->eventNum].delta = delta;
            midiInfo->midiEvent[midiInfo->eventNum].command = midiInfo->midiEvent[midiInfo->eventNum-1].command;
            midiInfo->midiEvent[midiInfo->eventNum].channel = midiInfo->midiEvent[midiInfo->eventNum-1].channel;
            midiInfo->midiEvent[midiInfo->eventNum].note = command;
            midiInfo->midiEvent[midiInfo->eventNum].velocity = *midiInfo->midiData;
            midiInfo->midiData++;
            midiInfo->eventNum++;
            delta = 0;
        }
        else if ((command & 0xf0) == 0xa0 || (command & 0xf0) == 0xb0 || (command & 0xf0) == 0xe0)
        {                                   /* skip 2 bytes */
            command = *midiInfo->midiData;
            midiInfo->midiData++;
            command = *midiInfo->midiData;
            midiInfo->midiData++;
        }
        else if ((command & 0xf0) == 0xc0 || (command & 0xf0) == 0xd0)
        {                                   /* skip 1 byte */
            command = *midiInfo->midiData;
            midiInfo->midiData++;
        }

        /* The followings belong to SysEx Events */
        else if (command == 0xf0 || command == 0xf7)
        {
            unsigned long length;

            length = ReadVarLen(midiInfo);
            while (length--)
            {
                command = *midiInfo->midiData;
                midiInfo->midiData++;
            }
        }

        /* The followings belong to Meta Events */
        else if (command == 0xff)
        {
            unsigned long length;
            unsigned char metatype;

            metatype = *midiInfo->midiData;
            midiInfo->midiData++;
            length = ReadVarLen(midiInfo);
//          length = *midiInfo->midiData;
//          midiInfo->midiData++;
            if (metatype == 0x2f)           /* end of track */
            {
//              midiInfo->midiEvent[midiInfo->eventNum].delta = delta;
//              midiInfo->midiEvent[midiInfo->eventNum].command = metatype;
//              midiInfo->eventNum++;
                break;
            }
            else if (metatype == 0x51)
            {
                T_U8 strTemp[10];
                memcpy(strTemp, midiInfo->midiData, (T_U16)length);
                midiInfo->midiData += length;
                midiInfo->tempo = UniteMultiHex(strTemp, 0, length - 1);
            }
            else                            /* skip several bytes */
            {
                while (length--)
                {
                    command = *midiInfo->midiData;
                    midiInfo->midiData++;
                }
            }
        }
        if (midiInfo->eventNum >= MAX_EVENT)
            return AK_FALSE;
    }

    return AK_TRUE;
}
Exemple #5
0
void ProcessMusic(void){
	u8 c1,c2,tmp,trackVol;
	s16 vol;
	u16 uVol,tVol;
	u8 channel;
	struct TrackStruct* track;


	//process patches envelopes & pitch slides
	for(unsigned char trackNo=0;trackNo<CHANNELS;trackNo++){
		track=&tracks[trackNo];

		//update envelope
		if(track->envelopeStep!=0){
			vol=track->envelopeVol+track->envelopeStep;		
			if(vol<0){
				vol=0;			
			}else if(vol>0xff){
				vol=0xff;						
			}
			track->envelopeVol=vol;
		}
	
		if(track->flags & TRACK_FLAGS_SLIDING){

			mixer.channels.all[trackNo].step+=track->slideStep;
			u16 tStep=pgm_read_word(&(steptable[track->slideNote]));

			if((track->slideStep>0 && mixer.channels.all[trackNo].step>=tStep) || 
				(track->slideStep<0 && mixer.channels.all[trackNo].step<=tStep))
			{					
				mixer.channels.all[trackNo].step = tStep;					
				track->flags &= ~(TRACK_FLAGS_SLIDING);	
			}
		}
	}



	//Process song MIDI notes
	if(playSong){
	
		#if MUSIC_ENGINE == MIDI
			
			//process all simultaneous events
			while(currDeltaTime==nextDeltaTime){

				c1=pgm_read_byte(songPos++);
			
				if(c1==0xff){
					//META data type event
					c1=pgm_read_byte(songPos++);

				
					if(c1==0x2f){ //end of song
						playSong=false;
						break;	
					}else if(c1==0x6){ //marker
						c1=pgm_read_byte(songPos++); //read len
						c2=pgm_read_byte(songPos++); //read data
						if(c2=='S'){ //loop start
							loopStart=songPos;
						}else if(c2=='E'){//loop end
							songPos=loopStart;
						}
					}
				

				}else{

					if(c1&0x80) lastStatus=c1;					
					channel=lastStatus&0x0f;
				
					//get next data byte
					//Note: maybe we should not advance the cursor
					//in case we receive an unsupported command				
					if(c1&0x80) c1=pgm_read_byte(songPos++); 

					switch(lastStatus&0xf0){

						//note-on
						case 0x90:
							//c1 = note						
							c2=pgm_read_byte(songPos++)<<1; //get volume
						
							if(tracks[channel].flags|TRACK_FLAGS_ALLOCATED){ //allocated==true
								TriggerNote(channel,tracks[channel].patchNo,c1,c2);
							}
							break;

						//controllers
						case 0xb0:
							///c1 = controller #
							c2=pgm_read_byte(songPos++); //get controller value
						
							if(c1==CONTROLER_VOL){
								tracks[channel].trackVol=c2<<1;
							}else if(c1==CONTROLER_EXPRESSION){
								tracks[channel].expressionVol=c2<<1;
							}else if(c1==CONTROLER_TREMOLO){
								tracks[channel].tremoloLevel=c2<<1;
							}else if(c1==CONTROLER_TREMOLO_RATE){
								tracks[channel].tremoloRate=c2<<1;
							}
						
							break;

						//program change
						case 0xc0:
							// c1 = patch #						
							tracks[channel].patchNo=c1;
							break;

					}//end switch(c1&0xf0)


				}//end if(c1==0xff)

				//read next delta time
				nextDeltaTime=ReadVarLen(&songPos);			
				currDeltaTime=0;
		
				#if SONG_SPEED == 1
					if(songSpeed != 0){
						uint32_t l  = (uint32_t)(nextDeltaTime<<8);

						if(songSpeed < 0){//slower
							(uint32_t)(l += (uint32_t)(-songSpeed*(nextDeltaTime<<1)));
							(uint32_t)(l >>= 8);
						}
						else//faster
							(uint32_t)(l /= (uint32_t)((1<<8)+(songSpeed<<1)));

						nextDeltaTime = l;
					}
Exemple #6
0
int CMIDISource::ReadData(int nIndex, void *pData, int nSize)
{
	StreamPos *pPos;
	unsigned char *pBuffer;
	MIDITrack *pTrack;
	int nStatus;
	int nValue;

	if (nIndex >= m_nOutputNum)
		return 0;

	pPos = m_pStreamPos + nIndex;
	if (pPos->nHeadPos == 0)  //invalid track
		return 0;
	if (pPos->nRelPos >= pPos->nSize)
		return 0;

	SourceSeekData(pPos->nAbsPos, SEEK_SET);
	pBuffer = (unsigned char *)pData;
	pTrack = m_pTracks + nIndex;

	pTrack->nTicks += ReadVarLen();  //delta time
	nStatus = SourceReadData();
	if (nStatus >= 0xF0 && nStatus < 0xFF)  //system exclusive event
	{
		pBuffer[0] = nStatus;
		nValue = ReadVarLen();
		SourceReadData(pBuffer + 1, nValue);
		assert(nSize >= 1 + nValue);
		if (nSize > 1 + nValue)
			nSize = 1 + nValue;
	}
	else
	{
		if ((nStatus & 0x80) == 0)  //running status
		{
			pBuffer[0] = pTrack->nStatus;
			pBuffer[1] = nStatus;
		}
		else  //MIDI event or meta event
		{
			pTrack->nStatus = nStatus;
			pBuffer[0] = nStatus;
			pBuffer[1] = SourceReadData();
		}
		switch (pBuffer[0] & 0xF0)
		{
			case 0x80:
			case 0x90:
			case 0xA0:
			case 0xB0:
			case 0xE0:
				pBuffer[2] = SourceReadData();
				nSize = 3;
				break;
			case 0xC0:
			case 0xD0:
				nSize = 2;
				break;
			case 0xF0:
				nValue = ReadVarLen();  //data length
				SourceReadData(pBuffer + 2, nValue);
				assert(nSize >= 2 + nValue);
				if (nSize > 2 + nValue)
					nSize = 2 + nValue;
				break;
			default:
				nSize = 0;
				break;
		}  //switch
	}  //else

	pPos->nAbsPos = SourceGetPosition();
	pPos->nRelPos = pPos->nAbsPos - pPos->nHeadPos;
	pPos->nTime = TicksToTime(pTrack->nTicks);
	if (pPos->nTime < m_nSeekTime)  //event before seektime
	{
		pPos->nTime = 0;  //render immediately
		if (pBuffer[0] >= 0x80 && pBuffer[0] <= 0x9F)  //note on or note off
			pBuffer[0] = 0x00;  //invalid event, should not be renderered
	}

	return nSize;
}
bool HeartBeatPS1Seq::ReadEvent(void)
{
	uint32_t beginOffset = curOffset;

	// in this format, end of track (FF 2F 00) comes without delta-time.
	// so handle that crazy sequence the first.
	if (curOffset + 3 <= rawfile->size())
	{
		if (GetByte(curOffset) == 0xff &&
			GetByte(curOffset + 1) == 0x2f &&
			GetByte(curOffset + 2) == 0x00)
		{
			curOffset += 3;
			AddEndOfTrack(beginOffset, curOffset-beginOffset);
			return false;
		}
	}

	uint32_t delta = ReadVarLen(curOffset);
	if (curOffset >= rawfile->size())
		return false;
	AddTime(delta);

	uint8_t status_byte = GetByte(curOffset++);

	if (status_byte <= 0x7F)			// Running Status
	{
		status_byte = runningStatus;
		curOffset--;
	}
	else
		runningStatus = status_byte;

	channel = status_byte&0x0F;
	SetCurTrack(channel);

	switch (status_byte & 0xF0)
	{
	case 0x80 :						//note off
		key = GetByte(curOffset++);
		vel = GetByte(curOffset++);
		AddNoteOff(beginOffset, curOffset-beginOffset, key);
		break;

	case 0x90 :						//note event
		key = GetByte(curOffset++);
		vel = GetByte(curOffset++);
		if (vel > 0)													//if the velocity is > 0, it's a note on
			AddNoteOn(beginOffset, curOffset-beginOffset, key, vel);
		else															//otherwise it's a note off
			AddNoteOff(beginOffset, curOffset-beginOffset, key);
		break;

	case 0xA0 :
		AddUnknown(beginOffset, curOffset-beginOffset);
		return false;

	case 0xB0 :
		{
			uint8_t controlNum = GetByte(curOffset++);
			uint8_t value = GetByte(curOffset++);
			switch (controlNum)		//control number
			{
			case 1:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Modulation", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 2: // identical to CC#11?
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Breath Controller?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 4:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Foot Controller?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 5:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Portamento Time?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 6 :
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN Data Entry", NULL, CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 7 :							//volume
				AddVol(beginOffset, curOffset-beginOffset, value);
				break;

			case 9:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 9", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 10 :							//pan
				AddPan(beginOffset, curOffset-beginOffset, value);
				break;

			case 11 :							//expression
				AddExpression(beginOffset, curOffset-beginOffset, value);
				break;

			case 20:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 20", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 21:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 21", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 22:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 22", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 23:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 23", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 32:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Bank LSB?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 52:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 52", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 53:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 53", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 54:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 54", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 55:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 55", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 56:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 56", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 64:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Hold 1?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 69:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Hold 2?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 71:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Resonance?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 72:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Release Time?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 73:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Attack Time?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 74:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Cut Off Frequency?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 75:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Decay Time?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 76:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Vibrato Rate?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 77:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Vibrato Depth?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 78:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Vibrato Delay?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 79:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control 79", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 91:
				AddReverb(beginOffset, curOffset-beginOffset, value);
				break;

			case 92:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Tremolo Depth?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 98:
				switch (value)
				{
				case 20 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1 #20", NULL, CLR_MISC);
					break;

				case 30 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1 #30", NULL, CLR_MISC);
					break;

				default:
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 1", NULL, CLR_MISC);
					break;
				}

				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 99 :							//(0x63) nrpn msb
				switch (value)
				{
				case 20 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Loop Start", NULL, CLR_LOOP);
					break;

				case 30 :
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Loop End", NULL, CLR_LOOP);
					break;

				default:
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"NRPN 2", NULL, CLR_MISC);
					break;
				}

				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 121:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reset All Controllers", NULL, CLR_MISC);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 126:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"MONO?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			case 127:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Poly?", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;

			default:
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Control Event", NULL, CLR_UNKNOWN);
				if (VGMSeq::readMode == READMODE_CONVERT_TO_MIDI) {
					pMidiTrack->AddControllerEvent(channel, controlNum, value);
				}
				break;
			}
		}
		break;

	case 0xC0 :
		{
			uint8_t progNum = GetByte(curOffset++);
			AddProgramChange(beginOffset, curOffset-beginOffset, progNum);
		}
		break;

	case 0xD0 :
		AddUnknown(beginOffset, curOffset-beginOffset);
		return false;

	case 0xE0 :
		{
			uint8_t hi = GetByte(curOffset++);
			uint8_t lo = GetByte(curOffset++);
			AddPitchBendMidiFormat(beginOffset, curOffset-beginOffset, hi, lo);
		}
		break;

	case 0xF0 : 
		{
			if (status_byte == 0xFF)
			{
				if (curOffset + 1 > rawfile->size())
					return false;

				uint8_t metaNum = GetByte(curOffset++);
				uint32_t metaLen = ReadVarLen(curOffset);
				if (curOffset + metaLen > rawfile->size())
					return false;

				switch (metaNum)
				{
				case 0x51 :
					AddTempo(beginOffset, curOffset+metaLen-beginOffset, (GetShortBE(curOffset) << 8) | GetByte(curOffset + 2));
					curOffset += metaLen;
					break;

				case 0x58 :
				{
					uint8_t numer = GetByte(curOffset);
					uint8_t denom = GetByte(curOffset + 1);
					AddTimeSig(beginOffset, curOffset+metaLen-beginOffset, numer, 1<<denom, (uint8_t)GetPPQN());
					curOffset += metaLen;
					break;
				}

				case 0x2F : // apparently not used, but just in case.
					AddEndOfTrack(beginOffset, curOffset+metaLen-beginOffset);
					curOffset += metaLen;
					return false;

				default :
					AddUnknown(beginOffset, curOffset+metaLen-beginOffset);
					curOffset += metaLen;
					break;
				}
			}
			else
			{
				AddUnknown(beginOffset, curOffset-beginOffset);
				return false;
			}
		}
		break;
	}
	return true;
}
Exemple #8
0
/* Loads a mid file in to a MidiFile object
 * @param pFile - pointer to the start of the midi file
 * @param size - size of the file in bytes
 * @returns MidiFile object with the information from the mid file
 */
MidiFile* ParseMidi(const char *pFile, size_t size)
{
   if(!pFile)
      return NULL;
   
   const char *pOffset = pFile;
   
   // "RIFF" is a (useless) wrapper sometimes applied to midis
   if(CompareToString(pFile, "RIFF"))
   {
      pOffset += 8;
      // if the next bytes are not "RMID", it is not a midi file
      if(!CompareToString(pFile, "RMID"))
      {
         return NULL;
      }
      pOffset += 4;
   }
   
   MidiFile::Header_Chunk *pHd = (MidiFile::Header_Chunk*)pOffset;
   // if the midi header is not found, it is not a midi file
   if(!CompareToString(pFile, "MThd"))
   {
      return NULL;
   }
   
   // Reverse the endian bytes of data
   FlipEndianness(&pHd->length);
   FlipEndianness(&pHd->format);
   FlipEndianness(&pHd->numTracks);
   FlipEndianness(&pHd->ticksPerBeat);
   
   MidiFile *pMidiFile = new MidiFile();
   
   pMidiFile->name[0] = 0;
   pMidiFile->format = pHd->format;
   pMidiFile->ticksPerBeat = pHd->ticksPerBeat;
   pMidiFile->numTracks = pHd->numTracks;
   pMidiFile->tracks.resize(pHd->numTracks);
   
   pOffset += 8 + pHd->length;
   
   for(int t = 0; t < pMidiFile->numTracks && pOffset < pFile + size; ++t)
   {
      MidiFile::Track_Chunk track;
      memcpy(&track.signature, pOffset, sizeof(track.signature));
      pOffset += sizeof(track.signature);
      memcpy(&track.length, pOffset, sizeof(track.length));
      pOffset += sizeof(track.length);

      FlipEndianness(&track.length);
      
      if(CompareToString(&track.signature, "MTrk"))
      {
         const char *pTrk = pOffset;
         uint32_t tick = 0;
         
         // this is most certainly null, but get it just in case
         MidiFile::MidiEvent *pEv = pMidiFile->tracks[t];
         
         while(pTrk < pOffset + track.length)
         {
            uint32_t delta = ReadVarLen(pTrk);
            tick += delta;
            uint8_t status = *(uint8_t*)pTrk++;
            
            MidiFile::MidiEvent *pEvent = NULL;
            
            if(status == MidiFile::MidiEventType::MidiEventType_Meta)
            {
               // meta event
               uint8_t type = *(uint8_t*)pTrk++;
               uint32_t bytes = ReadVarLen(pTrk);
               
               // read event
               switch(type)
               {
                  case MidiFile::MidiMeta_SequenceNumber:
                  {
                     static int sequence = 0;
                     
                     MidiFile::MidiEvent_SequenceNumber *pSeq = new MidiFile::MidiEvent_SequenceNumber;
                     pEvent = pSeq;
                     
                     if(!bytes)
                        pSeq->sequence = sequence++;
                     else
                     {
                        uint16_t seq;
                        memcpy(&seq, pTrk, 2);
                        FlipEndianness(&seq);
                        pSeq->sequence = (int)seq;
                     }
                     break;
                  }
                  case MidiFile::MidiMeta_Text:
                  case MidiFile::MidiMeta_Copyright:
                  case MidiFile::MidiMeta_TrackName:
                  case MidiFile::MidiMeta_Instrument:
                  case MidiFile::MidiMeta_Lyric:
                  case MidiFile::MidiMeta_Marker:
                  case MidiFile::MidiMeta_CuePoint:
                  case MidiFile::MidiMeta_PatchName:
                  case MidiFile::MidiMeta_PortName:
                  {
                     MidiFile::MidiEvent_Text *pText = new MidiFile::MidiEvent_Text;
                     pEvent = pText;
                     memcpy(pText->buffer, pTrk, bytes);
                     pText->buffer[bytes] = 0;
                     break;
                  }
                  case MidiFile::MidiMeta_EndOfTrack:
                  {
                     MidiFile::MidiEvent *pE = new MidiFile::MidiEvent;
                     pEvent = pE;
                     pTrk = pOffset + track.length;
                     break;
                  }
                  case MidiFile::MidiMeta_Tempo:
                  {
                     MidiFile::MidiEvent_Tempo *pTempo = new MidiFile::MidiEvent_Tempo;
                     pEvent = pTempo;
                     pTempo->microsecondsPerBeat = ((uint8_t*)pTrk)[0] << 16;
                     pTempo->microsecondsPerBeat |= ((uint8_t*)pTrk)[1] << 8;
                     pTempo->microsecondsPerBeat |= ((uint8_t*)pTrk)[2];
                     pTempo->BPM = 60000000.0f/(float)pTempo->microsecondsPerBeat;
                     break;
                  }
                  case MidiFile::MidiMeta_SMPTE:
                  {
                     MidiFile::MidiEvent_SMPTE *pSMPTE = new MidiFile::MidiEvent_SMPTE;
                     pEvent = pSMPTE;
                     pSMPTE->hours = ((uint8_t*)pTrk)[0];
                     pSMPTE->minutes = ((uint8_t*)pTrk)[1];
                     pSMPTE->seconds = ((uint8_t*)pTrk)[2];
                     pSMPTE->frames = ((uint8_t*)pTrk)[3];
                     pSMPTE->subFrames = ((uint8_t*)pTrk)[4];
                     break;
                  }
                  case MidiFile::MidiMeta_TimeSignature:
                  {
                     MidiFile::MidiEvent_TimeSignature *pTS = new MidiFile::MidiEvent_TimeSignature;
                     pEvent = pTS;
                     pTS->numerator = ((uint8_t*)pTrk)[0];
                     pTS->denominator = 1 << ((uint8_t*)pTrk)[1];
                     pTS->clocks = ((uint8_t*)pTrk)[2];
                     pTS->d = ((uint8_t*)pTrk)[3];
                     break;
                  }
                  case MidiFile::MidiMeta_KeySignature:
                  {
                     MidiFile::MidiEvent_KeySignature *pKS = new MidiFile::MidiEvent_KeySignature;
                     pEvent = pKS;
                     pKS->sf = ((uint8_t*)pTrk)[0];
                     pKS->minor = ((uint8_t*)pTrk)[1];
                     break;
                  }
                  case MidiFile::MidiMeta_Custom:
                  {
                     MidiFile::MidiEvent_Custom *pCustom = new MidiFile::MidiEvent_Custom;
                     pEvent = pCustom;
                     pCustom->pData = pTrk;
                     pCustom->size = bytes;
                     break;
                  }
               }
               
               if(pEvent)
                  pEvent->subType = type;
               
               pTrk += bytes;
            }
            else if(status == MidiFile::MidiEventType::MidiEventType_SYSEX || status == MidiFile::MidiEventType::MidiEventType_SYSEX2)
            {
               uint32_t bytes = ReadVarLen(pTrk);
               MidiFile::MidiEvent_SYSEX *pSYSEX = new MidiFile::MidiEvent_SYSEX;
               pEvent = pSYSEX;
               pSYSEX->pData = pTrk;
               pSYSEX->size = bytes;
               pTrk += bytes;
            }
            else
            {
               static int lastStatus = 0;
               
               if(status < 0x80)
               {
                  --pTrk;
                  status = lastStatus;
               }
               
               lastStatus = status;
               
               int eventType = status&0xF0;
               
               // some malformed midis cannot be trusted to conform to expectations, do not readvarlen these!
               int param1 = (*pTrk & 0x7F);
               pTrk++;
               int param2 = 0;
               // param2 will contain useful info, if the event isn't programChange or channelAfterTouch
               if(eventType != MidiFile::MidiNote_ProgramChange && eventType != MidiFile::MidiNote_ChannelAfterTouch)
               {
                  param2 = (*pTrk & 0x7F);
                  pTrk++;
               }
               
               switch(eventType)
               {
                  case MidiFile::MidiNote_NoteOn:
                  case MidiFile::MidiNote_NoteOff:
                  {
                     MidiFile::MidiEvent_Note *pNote = new MidiFile::MidiEvent_Note;
                     pEvent = pNote;
                     pNote->event = status&0xF0;
                     pNote->channel = status&0x0F;
                     pNote->note = param1;
                     pNote->velocity = param2;
                     status &= 0xF0;
                     break;
                  }
               }
               
               if(pEvent)
               {
                  pEvent->subType = status;
                  status = MidiFile::MidiEventType_Note;
               }
            }
            
            // append event to track
            if(pEvent)
            {
               pEvent->tick = tick;
               pEvent->delta = delta;
               pEvent->type = status;
               pEvent->pNext = NULL;
               
               if(!pEv)
               {
                  // set the first event
                  pMidiFile->tracks[t] = pEvent;
               }
               else
               {
                  // set the next event
                  pEv->pNext = pEvent;
               }
               // point to the most recent event
               pEv = pEvent;
            }
         }
      }
      
      pOffset += track.length;
   }
   
   return pMidiFile;
}