Beispiel #1
0
bool TriAcePS1Track::LoadTrackMainLoop(uint32_t stopOffset)
{
	TriAcePS1Seq* seq = (TriAcePS1Seq*)parentSeq;
	uint32_t scorePatternPtrOffset = dwOffset;
	uint16_t scorePatternOffset = GetShort(scorePatternPtrOffset);
	while (scorePatternOffset != 0xFFFF)
	{
		if (seq->patternMap[scorePatternOffset])
			seq->curScorePattern = NULL;
		else
		{
			TriAcePS1ScorePattern* pattern = new TriAcePS1ScorePattern(seq, scorePatternOffset);
			seq->patternMap[scorePatternOffset] = pattern;
			seq->curScorePattern = pattern;
			seq->aScorePatterns.push_back(pattern);
		}
		uint32_t endOffset = ReadScorePattern(scorePatternOffset);
		if (seq->curScorePattern)
			seq->curScorePattern->unLength = endOffset - seq->curScorePattern->dwOffset;
		AddSimpleItem(scorePatternPtrOffset, 2, L"Score Pattern Ptr");
		scorePatternPtrOffset += 2;
		scorePatternOffset = GetShort(scorePatternPtrOffset);
	}
	AddEndOfTrack(scorePatternPtrOffset, 2);
	unLength = scorePatternPtrOffset+2 - dwOffset;
	return true;
}
Beispiel #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;
}
Beispiel #3
0
// I'm going to try to follow closely to the original Salamander 2 code at 0x30C6
bool KonamiGXTrack::ReadEvent(void)
{
	ULONG beginOffset = curOffset;
	ULONG deltatest = GetTime();
	//AddDelta(ReadVarLen(curOffset));

	BYTE status_byte = GetByte(curOffset++);

	if (status_byte == 0xFF)
	{
		if (bInJump)
		{
			bInJump = false;
			curOffset = jump_return_offset;
		}
		else
		{
			AddEndOfTrack(beginOffset, curOffset-beginOffset);
			return 0;
		}
	}
	else if (status_byte == 0x60)
	{
		return 1;
	}
	else if (status_byte == 0x61)
	{
		return 1;
	}
	else if (status_byte < 0xC0)		//note event
	{
		BYTE note, delta;
		if (status_byte < 0x62)
		{
			delta = GetByte(curOffset++);
			note = status_byte;
			prevDelta = delta;
		}
		else
		{
			delta = prevDelta;
			note = status_byte - 0x62;
		}
		
		BYTE nextDataByte = GetByte(curOffset++);
		BYTE dur, vel;
		if (nextDataByte < 0x80)
		{
			dur = nextDataByte;
			prevDur = dur;
			vel = GetByte(curOffset++);
		}
		else
		{
			dur = prevDur;
			vel = nextDataByte - 0x80;
		}
		
		//AddNoteOn(beginOffset, curOffset-beginOffset, note, vel);
		//AddDelta(dur);
		//AddNoteOffNoItem(note);
		UINT newdur = (delta*dur)/0x64;
		if (newdur == 0)
			newdur = 1;
		AddNoteByDur(beginOffset, curOffset-beginOffset, note, vel, newdur);
		AddTime(delta);
		if (newdur > delta)
			ATLTRACE("newdur > delta.  %X > %X.  occurring at %X\n", newdur, delta, beginOffset);
		//AddDelta(dur);
	}
	else switch (status_byte)
	{
	case 0xC0:
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xCE:
		curOffset+=2;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xD0:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xD1:
	case 0xD2:
	case 0xD3:
	case 0xD4:
	case 0xD5:
	case 0xD6:
		curOffset+=2;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xDE:
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE0:		//Rest
		{
			BYTE delta = GetByte(curOffset++);
			AddTime(delta);
		}
		break;
	case 0xE1:		//Hold
		{
			BYTE delta = GetByte(curOffset++);
			BYTE dur = GetByte(curOffset++);
			UINT newdur = (delta*dur)/0x64;
			AddTime(newdur);
			this->MakePrevDurNoteEnd();
			AddTime(delta-newdur);
		}
		break;
	case 0xE2:			//program change
		{
			BYTE progNum = GetByte(curOffset++);
			AddProgramChange(beginOffset, curOffset-beginOffset, progNum);
		}
		break;
	case 0xE3:			//stereo related
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE4:
	case 0xE5:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE6:
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE7:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE8:
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xE9:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xEA:			//tempo
		{
			BYTE bpm = GetByte(curOffset++);
			AddTempoBPM(beginOffset, curOffset-beginOffset, bpm);
		}
		break;
	case 0xEC:
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xEE:			//master vol
		{
			BYTE vol = GetByte(curOffset++);
			//AddMasterVol(beginOffset, curOffset-beginOffset, vol);
		}
		break;
	case 0xEF:
		curOffset+=2;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF0:
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF1:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF2:
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF3:
		curOffset+=3;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF6:
	case 0xF7:
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xF8:
		curOffset+=2;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xFA:			//release rate
		curOffset++;
		AddUnknown(beginOffset, curOffset-beginOffset);
		break;
	case 0xFD:
		curOffset += 4;
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Loop", NULL, CLR_LOOP);
		break;
	case 0xFE:
		bInJump = true;
		jump_return_offset = curOffset+4;
		AddGenericEvent(beginOffset, jump_return_offset-beginOffset, L"Jump", NULL, CLR_LOOP);
		curOffset = GetWordBE(curOffset);
		//if (curOffset > 0x100000)
		//	return 0;
		break;
	default:
		AddEndOfTrack(beginOffset, curOffset-beginOffset);
		return false;
	}
	return true;
}
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;
}
Beispiel #5
0
//--------------------------------------------------
//Revisions:
//	2009. 6.17(Wed.) :	Re-make by "Sound tester 774" in "内蔵音源をMIDI変換するスレ(in http://www.2ch.net)"
//						Add un-known command(op-code).
//--------------------------------------------------
bool AkaoTrack::ReadEvent(void)
{
	ULONG beginOffset = curOffset;
	BYTE status_byte = GetByte(curOffset++);

	int i, k;

	if (status_byte < 0x9A)   //it's either a  note-on message, a tie message, or a rest message
	{
		//looking at offset 8005E5C8 in the FFO FF2 exe for this delta time table code  4294967296  0x100000000/0xBA2E8BA3   = 1.374999... = 11/8
		//0x68 after eq = 9
		/*i = ((status_byte * 0xBA2E8BA3) & 0xFF00000000) >> 32; // emulating multu and mfhi instruction
		//i >>= 3;  //srl 3
*/		i = status_byte / 11;
		k = i*2;  //sll 1 - aka multiply by 2
		k +=  i;   //addu $v0, $v1
		k *= 4;  //sll 2 - aka multiply by 4
		k -= i;  //subu    $v0, $v1
		k = status_byte - k; //subu    $v0, $s1, $v0
		//k now equals the table index value
		//relative key calculation found at 8005E6F8 in FFO FF2 exe

		if (status_byte < 0x83) // it's a note-on message
		{
			relative_key = status_byte / 11;
			base_key = octave*12;
			if (bNotePlaying)
			{
				AddNoteOffNoItem(prevKey);
				bNotePlaying = false;
			}
			//if (bAssociatedWithSSTable)
			//	FindNoteInstrAssoc(hFile, base_key + relative_key);


			AddNoteOn(beginOffset, curOffset-beginOffset, base_key + relative_key, vel);
			bNotePlaying = true;

			AddTime(delta_time_table[k]);
		}
		else if (status_byte < 0x8F)  //if it's between 0x83 and 0x8E it is a tie event
		{
			AddTime(delta_time_table[k]);
			if (loop_counter[loop_layer] == 0 && loop_layer == 0)		//do this so we don't repeat this for every single time it loops
				AddGenericEvent(beginOffset, curOffset-beginOffset, L"Tie", NULL, CLR_TIE);
		}
		else				//otherwise, it's between 0x8F and 0x99 and it's a rest message
		{
			if (bNotePlaying)
			{
				AddNoteOff(beginOffset, curOffset-beginOffset, prevKey);
				bNotePlaying = false;
			}
			AddRest(beginOffset, curOffset-beginOffset, delta_time_table[k]);
		}
	}
	else if ((status_byte >= 0xF0) && (status_byte <= 0xFB))
	{
		relative_key = status_byte-0xF0;
		base_key = octave*12;
		if (bNotePlaying)
		{
			AddNoteOffNoItem(prevKey);
			bNotePlaying = false;
		}
		bNotePlaying = true;
		AddNoteOn(beginOffset, curOffset-beginOffset+1, base_key + relative_key, vel);
		AddTime(GetByte(curOffset++));
	}
	else switch (status_byte)
	{
	 case 0xA0 :
//		----[ 2009. 6.12	change ]-----
//		 AddUnknown(beginOffset, curOffset-beginOffset);
//		 break;
		AddEndOfTrack(beginOffset, curOffset-beginOffset);
		return false;

	 case 0xA1 :			// change program to articulation number
		{
			((AkaoSeq*)parentSeq)->bUsesIndividualArts = true;
			BYTE artNum = GetByte(curOffset++);
			BYTE progNum = ((AkaoSeq*)parentSeq)->instrset->aInstrs.size() + artNum;
			AddProgramChange(beginOffset, curOffset-beginOffset, progNum);
		}
		break;

	case 0xA2 :			// set next note length [ticks]
		curOffset++;
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Next note length", NULL, CLR_CHANGESTATE);
		break;

	 case 0xA3 :			//set track volume
		 vol = GetByte(curOffset++);			//expression value		
		 AddVol(beginOffset, curOffset-beginOffset, vol);
		 break;

	 case 0xA4:			// pitch slide half steps.  (Portamento)
		{
			BYTE dur = GetByte(curOffset++);		//first byte is duration of slide
			BYTE steps = GetByte(curOffset++);		//second byte is number of halfsteps to slide... not sure if signed or not, only seen positive
			//AddPitchBendSlide(
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Portamento", NULL, CLR_PORTAMENTO);
		}
		break;

	 case 0xA5 :			//set octave
		 octave = GetByte(curOffset++);
		 AddSetOctave(beginOffset, curOffset-beginOffset, octave);
		 break;

	 case 0xA6 :			//set octave + 1
		 AddIncrementOctave(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xA7 :			//set octave - 1
		 AddDecrementOctave(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xA8 :			//set expression (USED TO BE VELOCITY, may go back after testing, as this is messy)
		 {
			 //vel = GetByte(curOffset++);
			 //vel = Convert7bitPercentVolValToStdMidiVal(vel);		//I THINK THIS APPLIES, BUT NOT POSITIVE
			 //AddGenericEvent(beginOffset, curOffset-beginOffset, L"Set Velocity", NULL, BG_CLR_CYAN);
			 BYTE cExpression = GetByte(curOffset++);
////			 こっちのlog演算は要らない
////			 vel = Convert7bitPercentVolValToStdMidiVal(vel);		//I THINK THIS APPLIES, BUT NOT POSITIVE
			 vel = 127;		//とりあえず 127 にしておく
			 AddExpression(beginOffset, curOffset-beginOffset, cExpression);
		 }
		 break;

	 case 0xA9 :			//set Expression fade
		 {
			BYTE dur = GetByte(curOffset++);
			BYTE targExpr = GetByte(curOffset++);			//reads the target velocity value - the velocity value we are fading toward
			AddExpressionSlide(beginOffset, curOffset-beginOffset, dur, targExpr);
		 }
		 break;

	 case 0xAA :			//set pan
		 {
			BYTE pan = GetByte(curOffset++);
			AddPan(beginOffset, curOffset-beginOffset, pan);
		 }
		break;

	 case 0xAB :			//set pan fade
		 {
			BYTE dur = GetByte(curOffset++);
			BYTE targPan = GetByte(curOffset++);			//reads the target velocity value - the velocity value we are fading toward
			AddPanSlide(beginOffset, curOffset-beginOffset, dur, targPan);
		 }
		 break;

	 case 0xAC :			//unknown
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

/*AD = set attack AE = set decay AF = set sustain level  B0 = AE then AF
<CBongo> B1 = set sustain release  B2 = set release
 B7 might be set A,D,S,R values all at once
 B3 appears to be "reset ADSR to the initial values from the instrument/sample data"*/

	 case 0xAD :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xAE :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xAF :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xB0 :
		 curOffset++;
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xB1 :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xB2 :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;
	 case 0xB3 :
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"ADSR", NULL, CLR_ADSR);
		 break;

	//
	//	0xB4 to 0xB7	LFO Pitch bend
	//	0xB8 to 0xBC	LFO Expression
	//	0xBC to 0xBF	LFO Panpot
	//

	 case 0xB4 :			//unknown
		 curOffset += 3;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Pitch bend) Length, cycle", NULL, CLR_LFO);
		 break;
	 case 0xB5 :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Pitch bend) Depth", NULL, CLR_LFO);
		 break;
	 case 0xB6 :			//unknown
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Pitch bend) off", NULL, CLR_LFO);
		 break;
	 case 0xB7 :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xB8 :			//unknown
		 curOffset += 3;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Expression) Length, cycle", NULL, CLR_LFO);
		 break;
	 case 0xB9 :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Expression) Depth", NULL, CLR_LFO);
		 break;
	 case 0xBA :			//unknown
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Expression) off", NULL, CLR_LFO);
		 break;
	 case 0xBB :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xBC :			//unknown
		 curOffset += 2;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Panpot) Length, cycle", NULL, CLR_LFO);
		 break;
	 case 0xBD :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Panpot) Depth", NULL, CLR_LFO);
		 break;
	 case 0xBE :			//unknown
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Panpot) off", NULL, CLR_LFO);
		 break;
	 case 0xBF :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xC0 :
		 {
			char cTranspose = GetByte(curOffset++);
			AddTranspose(beginOffset, curOffset-beginOffset,cTranspose);
		 }
		 break;
	 case 0xC1 :
		 {
			BYTE cTranspose = GetByte(curOffset++);
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Transpose move", NULL, CLR_TRANSPOSE);
		 }
		 break;

	case 0xC2 :
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reverb On", NULL, CLR_REVERB);
		 break;
	case 0xC3 :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reverb Off", NULL, CLR_REVERB);
		break;

	case 0xC4 :
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"Noise On", NULL, CLR_UNKNOWN);
		 break;
	case 0xC5 :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Noise Off", NULL, CLR_UNKNOWN);
		break;

	case 0xC6 :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"FM Modulation On", NULL, CLR_UNKNOWN);
		break;
	case 0xC7 :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"FM Modulation Off", NULL, CLR_UNKNOWN);
		break;

	case 0xC8 :			// set loop begin marker
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Repeat Start", NULL, CLR_LOOP);
		loop_begin_layer++;
		loop_begin_loc[loop_begin_layer] = curOffset;
		//bInLoop = true;
		break;

	case 0xC9 :
		{
			BYTE value1 = GetByte(curOffset++);
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Repeat End", NULL, CLR_LOOP);
			if (loop_begin_layer == 0)		//if loop_begin_layer == 0, then there was never a matching loop begin event!  this is seen in ff9 402 and ff9 hunter's chance
				break;
			if (loopID[loop_layer] != curOffset)
			{
				loop_layer++;
				loopID[loop_layer] = curOffset;
				curOffset = loop_begin_loc[loop_begin_layer];
				loop_counter[loop_layer] = value1-2;
				bInLoop = true;
			}
			else if (loop_counter[loop_layer] > 0)
			{
				loop_counter[loop_layer]--;
				curOffset = loop_begin_loc[loop_begin_layer];
				//if (loop_counter[loop_layer] == 0 && loop_layer == 1)
				//	bInLoop = false;
			}
			else
			{
				loopID[loop_layer]=0;
				loop_layer--;
				loop_begin_layer--;
				if (loop_layer == 0)
					bInLoop = false;
			}
		}
		break;

	case 0xCA :
		{
			BYTE value1 = 2;
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Repeat End", NULL, CLR_LOOP);
			if (loop_begin_layer == 0)
				break;
			if (loopID[loop_layer] != curOffset)
			{
				loop_layer++;
				loopID[loop_layer] = curOffset;
				curOffset = loop_begin_loc[loop_begin_layer];
				loop_counter[loop_layer] = value1-2;
				bInLoop = true;
			}
			else if (loop_counter[loop_layer] > 0)
			{
				loop_counter[loop_layer]--;
				curOffset = loop_begin_loc[loop_begin_layer];
				//if (loop_counter[loop_layer] == 0 && loop_layer == 1)
				//	bInLoop = false;
			}
			else
			{
				loopID[loop_layer]=0;
				loop_layer--;
				loop_begin_layer--;
				if (loop_layer == 0)
					bInLoop = false;
			}
		}
		break;

	case 0xCC :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Slur On", NULL, CLR_PORTAMENTO);
		break;
	case 0xCD :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Slur Off", NULL, CLR_PORTAMENTO);
		break;

	case 0xD0 :
		AddNoteOff(beginOffset, curOffset-beginOffset, prevKey);
		break;

	case 0xD1 :			// unknown
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Deactivate Notes?", NULL, CLR_UNKNOWN);
		break;

	case 0xD2 :
		curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		break;

	case 0xD3 :
		curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		break;

	case 0xD8 :			//pitch bend
		{
			BYTE cValue = GetByte(curOffset++);		//signed data byte.  range of 1 octave (0x7F = +1 octave 0x80 = -1 octave)
			int fullValue = (int)(cValue * 64.503937007874015748031496062992);
			fullValue += 0x2000;
			BYTE lo = fullValue & 0x7F;
			BYTE hi = (fullValue & 0x3F80) >> 7;
			AddPitchBendMidiFormat(beginOffset, curOffset-beginOffset, lo, hi);
		}
		break;

	 case 0xD9 :
		 curOffset++;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"Pitch bend move", NULL, CLR_UNKNOWN);
		 break;

	 case 0xDA :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xDC :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xDD :
		 curOffset += 2;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Pitch bend) times", NULL, CLR_UNKNOWN);
		 break;
	 case 0xDE :
		 curOffset += 2;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Expression) times", NULL, CLR_UNKNOWN);
		 break;
	 case 0xDF :
		 curOffset += 2;
		 AddGenericEvent(beginOffset, curOffset-beginOffset, L"LFO(Panpot) times", NULL, CLR_UNKNOWN);
		 break;

	 case 0xE1 :
		 curOffset++;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xE6 :
		 curOffset += 2;
		 AddUnknown(beginOffset, curOffset-beginOffset);
		 break;

	 case 0xFC :			//tie time
		 //if (nVersion == VERSION_1 || nVersion == VERSION_2)
		//	 goto MetaEvent;
		 //rest_time += pDoc->GetByte(j++);
		AddTime(GetByte(curOffset++));
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"Tie (custom)", NULL, CLR_TIE);
		break;

	 case 0xFD :
		 {
			 if (bNotePlaying)
			 {
				 AddNoteOffNoItem(prevKey);
		 		bNotePlaying = false;
			 }
			 BYTE restTime = GetByte(curOffset++);
			 AddRest(beginOffset, curOffset-beginOffset, restTime);
		 }
		 break;

	 case 0xFE :			//meta event
		//MetaEvent:
		switch (GetByte(curOffset++))
		{
		case 0x00 :			//tempo
			{
				BYTE value1 = GetByte(curOffset++);
				BYTE value2 = GetByte(curOffset++);
				double dValue1 = ((value2<<8) + value1)/218.4555555555555555555555555;		//no clue how this magic number is properly derived
				AddTempoBPM(beginOffset, curOffset-beginOffset, dValue1);
			}
			break;

		case 0x01 :			//tempo slide
			{
				BYTE value1 = GetByte(curOffset++);    //NEED TO ADDRESS value 1	
				BYTE value2 = GetByte(curOffset++);
				//AddTempoSlide(
				//RecordMidiSetTempo(current_delta_time, value2); 
			}
			break;

		case 0x02 :			//reverb
			curOffset++;
			curOffset++;
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reverb Level", NULL, CLR_REVERB);
			break;

		case 0x03 :			//reverb
			curOffset++;
			curOffset++;
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reverb Fade", NULL, CLR_REVERB);
			break;

		case 0x04 :			//signals this track uses the drum kit
			AddProgramChange(beginOffset, curOffset-beginOffset, 127, L"Drum kit On");
			//channel = 9;
			break;

		case 0x05 :			//reverb
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Drum kit Off", NULL, CLR_UNKNOWN);
			break;

		case 0x06 :			//Branch Relative
			{
				ULONG dest = (S16)GetShort(curOffset) + curOffset;
				curOffset += 2;
				ULONG eventLength = curOffset - beginOffset;
				bool bContinue = false;

				curOffset = dest;

				// Check the remaining area that will be processed by CPU-controlled jump.
				for (vector<ULONG>::iterator itAddr = vCondJumpAddr.begin(); itAddr != vCondJumpAddr.end(); ++itAddr)
				{
					if (!IsOffsetUsed(*itAddr))
					{
						// There is an area not visited yet, VGMTrans must try to go there.
						bContinue = true;
						break;
					}
				}

				if (readMode == READMODE_FIND_DELTA_LENGTH)
					deltaLength = GetTime();

				AddGenericEvent(beginOffset, eventLength, L"Dal Segno.(Loop)", NULL, CLR_LOOP);
				return bContinue;

				/*USHORT siValue = GetShort(pDoc, j);
				if (nScanMode == MODE_CONVERT_MIDI)		//if we are converting the midi, the actually branch
				{
					if (seq_repeat_counter-- > 0)
						curOffset += siValue;
					else
						curOffset += 2;
				}
				else
					curOffset += 2;								//otherwise, just skip over the relative branch offset*/
			}
			break;

		case 0x07 :			//Permanence Loop break with conditional.
			{
				BYTE condValue = GetByte(curOffset++);
				ULONG dest = (S16)GetShort(curOffset) + curOffset;
				curOffset += 2;
				ULONG eventLength = curOffset - beginOffset;

				// This event performs conditional jump if certain CPU variable matches to the condValue.
				// VGMTrans will simply try to parse all events as far as possible, instead.
				// (Test case: FF9 416 Final Battle)
				if (!IsOffsetUsed(beginOffset))
				{
					// For the first time, VGMTrans just skips the event,
					// but remembers the destination address for future jump.
					vCondJumpAddr.push_back(dest);
				}
				else
				{
					// For the second time, VGMTrans jumps to the destination address.
					curOffset = dest;
				}

				AddGenericEvent(beginOffset, eventLength, L"Dal Segno (Loop) Break", NULL, CLR_LOOP);
			}
			break;

		case 0x09 :			//Repeat break with conditional.
			curOffset++;
			curOffset++;
			curOffset++;
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Repeat Break", NULL, CLR_LOOP);
			break;

		//case 0x0E :			//call subroutine
		//case 0x0F :			//return from subroutine

		case 0x10 :			//unknown
			curOffset++;
			AddUnknown(beginOffset, curOffset-beginOffset);
			break;

		case 0x14 :			//program change
			{
				BYTE curProgram = GetByte(curOffset++);
				//if (!bAssociatedWithSSTable)
				//	RecordMidiProgramChange(current_delta_time, curProgram, hFile);
				AddProgramChange(beginOffset, curOffset-beginOffset, curProgram);
			}
			break;

		case 0x15 :			//Time Signature
			{
				BYTE denom = 4; curOffset++;//(192 / GetByte(curOffset++));
				BYTE numer = GetByte(curOffset++);
				//AddTimeSig(beginOffset, curOffset-beginOffset, numer, denom, parentSeq->GetPPQN());
			}
			break;

		case 0x16 :			//Maker
			curOffset += 2;
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"Maker", NULL, CLR_UNKNOWN);
			break;
		case 0x1C :			//unknown
			curOffset++;
			AddUnknown(beginOffset, curOffset-beginOffset);
			break;
		default :
			AddGenericEvent(beginOffset, curOffset-beginOffset, L"UNKNOWN META EVENT", NULL, CLR_UNRECOGNIZED);
			break;
		}
		break;

	default :
		AddGenericEvent(beginOffset, curOffset-beginOffset, L"UNKNOWN EVENT", NULL, CLR_UNRECOGNIZED);
		break;
	}
	return true;
}
Beispiel #6
0
//==============================================================
//		Process of 1 Event
//--------------------------------------------------------------
//	Input
//		Nothing
//	Output
//		Nothing
//	Memo
//		SeqTrack::LoadTrack() から call される。
//==============================================================
bool HOSATrack::ReadEvent(void)
{

	//==================================
	//	[ Local 変数 ]
	//----------------------------------
	const		ULONG	beginOffset	= curOffset;					//start offset point

	const		BYTE	cCommand	= GetByte(curOffset++);			//command (op-code)
	const		BYTE	cCom_bit0	= (cCommand & 0x1F);			//length / contents
	const		BYTE	cCom_bit5	= (cCommand & 0x60) >> 5;		//Delta times
	const		BYTE	cCom_bit7	= (cCommand & 0x80) >> 7;		//0=Notes / 1=Controls

//	unsigned 	int					iMinLengthCounter;				//デルタタイム最小値
//				int					i;		//general
//	vector<char>::iterator			it_note;
//	vector<int unsigned >::iterator	it_Length;



	//==================================
	//	[ Process of "Delta time" and "Note off Event" ]
	//----------------------------------
	//Command用の(DeltaCounter==0)まで繰り返し。
	//while(iDeltaTimeCounter!=0){

	//	//Search the minimum length time [ticks]
	//	iMinLengthCounter	=	iDeltaTimeCounter;
	//	for(i=0;i<listLength.size();i++){
	//		if(iMinLengthCounter > listLength[i]){
	//			iMinLengthCounter = listLength[i];
	//		}
	//	}

	//	//Writing delta time.
	//	AddDelta(iMinLengthCounter);
	//	
	//	//Subtract the minimum length time from "Delta time" and "Length times"
	//	iDeltaTimeCounter	-=	iMinLengthCounter;
	//	for(i=0;i<listNote.size();i++){
	//		listLength[i] -= iMinLengthCounter;
	//	}

	//	//Search the ("Length times" == 0)
	//	it_note		= listNote.begin();
	//	it_Length	= listLength.begin();
	//	while(it_Length != listLength.end()){
	//		if(*it_Length==0){
	//			//Write "Note-off Event"
	//			AddNoteOffNoItem(*it_note);
	//			//Erase note-information from vector.
	//			it_note		= listNote.erase(it_note);
	//			it_Length	= listLength.erase(it_Length);
	//		} else {
	//			it_note++;
	//			it_Length++;
	//		}
	//	}
	//}



	//==================================
	//	[ Process of command (note / control) ]
	//----------------------------------

	//----------------------------------
	//	Command: Notes  (cCommand == 0x00 - 0x7F)
	if(cCom_bit7==0){

		//--------
		//[2]Update the default Note Number
		cNoteNum	= GetByte(curOffset++);

		//--------
		//[3]Update the default Delta time
		ReadDeltaTime(cCom_bit5, &iDeltaTimeCom);

		//--------
		//[4]Update the default Length
		iLengthTimeNote = GetShort(parentSeq->dwOffset + 0x10 + cCom_bit0*2);
		if(iLengthTimeNote==0){
//			iLengthTimeNote = ReadVarLen(curOffset);		//No count curOffset
			iLengthTimeNote = DecodeVariable();
		};

		//--------
		//[5]Update the default Velocity
		if(cNoteNum & 0x80){
			cNoteNum &= 0x7F;
			cVelocity = GetByte(curOffset++);
		};

		//--------
		//[3]Update the default Delta time (continuation)
		if(cCom_bit5==1){
			iDeltaTimeCom = iLengthTimeNote;	//Delta time is the same as note length.
		};
		iDeltaTimeNote = iDeltaTimeCom;			//Default delta time for Note.

		//--------
		//Write Note-On Event
		AddNoteByDur(beginOffset, curOffset-beginOffset, cNoteNum, cVelocity, iLengthTimeNote);


	//----------------------------------
	//	Command: Controls  (cCommand == 0x80 - 0x9F, 0xC0 - 0xFF)
	} else {
		if(cCom_bit5!=1){
			switch(cCom_bit0){
				//------------
				//End of Track
				case(0x00):
					AddEndOfTrack(beginOffset, curOffset-beginOffset);
					return false;
					break;
				//------------
				//Tempo
				case(0x01):
					cTempo = GetByte(curOffset++);
					AddTempoBPM(beginOffset, curOffset-beginOffset, cTempo);
					break;
				//------------
				//Reverb
				case(0x02):
					curOffset++;
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Reverb Depth", NULL, CLR_REVERB);
					break;
				//------------
				//Instrument
				case(0x03):
					cInstrument = GetByte(curOffset++);
					AddProgramChange(beginOffset, curOffset-beginOffset, cInstrument);
					break;
				//------------
				//Volume
				case(0x04):
					cVolume = GetByte(curOffset++);
					AddVol(beginOffset, curOffset-beginOffset, cVolume);
					break;
				//------------
				//Panpot
				case(0x05):
					cPanpot = GetByte(curOffset++);
					AddPan(beginOffset, curOffset-beginOffset, cPanpot);
					break;
				//------------
				//Expression
				case(0x06):
					cExpression = GetByte(curOffset++);
					AddExpression(beginOffset, curOffset-beginOffset, cExpression);
					break;
				//------------
				//Unknown
				case(0x07):
					curOffset++;
					curOffset++;
					AddUnknown(beginOffset, curOffset-beginOffset);
					break;
				//------------
				//Dal Segno. (Loop)
				case(0x09):
					curOffset++;
					AddGenericEvent(beginOffset, curOffset-beginOffset, L"Dal Segno.(Loop)", NULL, CLR_LOOP);
					break;
				//------------
				//Unknown
				case(0x0F):
					AddUnknown(beginOffset, curOffset-beginOffset);
					break;
				//------------
				//Unknowns
				default:
					curOffset++;
					AddUnknown(beginOffset, curOffset-beginOffset);
					break;
			}

			//--------
			//[3]Delta time
			ULONG	beginOffset2 = curOffset;
			ReadDeltaTime(cCom_bit5, &iDeltaTimeCom);
			if(curOffset != beginOffset2){
				AddGenericEvent(beginOffset2,curOffset-beginOffset2, L"Delta time", NULL, CLR_CHANGESTATE);
			};

	//----------------------------------
	//	Command: Notes  (cCommand == 0xA0 - 0xBF)
		} else {
			if(cCom_bit0 & 0x10){
				//Add (Command = 0xB0 - 0xBF)
				cNoteNum+=(cCom_bit0 & 0x0F);
			}else{
				//Sub (Command = 0xA0 - 0xAF)
				cNoteNum-=(cCom_bit0 & 0x0F);
			};
			//--------
			//Write Note-On Event
			AddNoteByDur(beginOffset, curOffset-beginOffset, cNoteNum, cVelocity, iLengthTimeNote);
			iDeltaTimeCom		= iDeltaTimeNote;
		}
	}

	//==================================
	//	[ Process of "Note" with note length ]
	//----------------------------------
	//if(fNoteOutput!=0){
	//	//Write "Note-on Event"
	//	AddNoteOn(beginOffset, curOffset-beginOffset, fNoteOutput, cVelocity);
	//	//Add note-information to vector.
	//	listNote.push_back(fNoteOutput);		//Note Number
	//	listLength.push_back(iLengthTimeNote);	//Length
	//	//Next delta time
	//	iDeltaTimeCom		= iDeltaTimeNote;
	//}



	//==================================
	//	[ Process of "Setting Delta time" ]
	//----------------------------------
	//iDeltaTimeCounter = iDeltaTimeCom;
	AddTime(iDeltaTimeCom);



	return true;

}
bool CompileSnesTrack::ReadEvent(void)
{
	CompileSnesSeq* parentSeq = (CompileSnesSeq*)this->parentSeq;

	uint32_t beginOffset = curOffset;
	if (curOffset >= 0x10000) {
		return false;
	}

	uint8_t statusByte = GetByte(curOffset++);
	bool bContinue = true;

	std::wstringstream desc;

	CompileSnesSeqEventType eventType = (CompileSnesSeqEventType)0;
	std::map<uint8_t, CompileSnesSeqEventType>::iterator pEventType = parentSeq->EventMap.find(statusByte);
	if (pEventType != parentSeq->EventMap.end()) {
		eventType = pEventType->second;
	}

	switch (eventType)
	{
	case EVENT_UNKNOWN0:
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;

	case EVENT_UNKNOWN1:
	{
		uint8_t arg1 = GetByte(curOffset++);
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte
			<< std::dec << std::setfill(L' ') << std::setw(0)
			<< L"  Arg1: " << (int)arg1;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;
	}

	case EVENT_UNKNOWN2:
	{
		uint8_t arg1 = GetByte(curOffset++);
		uint8_t arg2 = GetByte(curOffset++);
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte
			<< std::dec << std::setfill(L' ') << std::setw(0)
			<< L"  Arg1: " << (int)arg1
			<< L"  Arg2: " << (int)arg2;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;
	}

	case EVENT_UNKNOWN3:
	{
		uint8_t arg1 = GetByte(curOffset++);
		uint8_t arg2 = GetByte(curOffset++);
		uint8_t arg3 = GetByte(curOffset++);
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte
			<< std::dec << std::setfill(L' ') << std::setw(0)
			<< L"  Arg1: " << (int)arg1
			<< L"  Arg2: " << (int)arg2
			<< L"  Arg3: " << (int)arg3;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;
	}

	case EVENT_UNKNOWN4:
	{
		uint8_t arg1 = GetByte(curOffset++);
		uint8_t arg2 = GetByte(curOffset++);
		uint8_t arg3 = GetByte(curOffset++);
		uint8_t arg4 = GetByte(curOffset++);
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte
			<< std::dec << std::setfill(L' ') << std::setw(0)
			<< L"  Arg1: " << (int)arg1
			<< L"  Arg2: " << (int)arg2
			<< L"  Arg3: " << (int)arg3
			<< L"  Arg4: " << (int)arg4;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;
	}

	case EVENT_UNKNOWN5:
	{
		uint8_t arg1 = GetByte(curOffset++);
		uint8_t arg2 = GetByte(curOffset++);
		uint8_t arg3 = GetByte(curOffset++);
		uint8_t arg4 = GetByte(curOffset++);
		uint8_t arg5 = GetByte(curOffset++);
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte
			<< std::dec << std::setfill(L' ') << std::setw(0)
			<< L"  Arg1: " << (int)arg1
			<< L"  Arg2: " << (int)arg2
			<< L"  Arg3: " << (int)arg3
			<< L"  Arg4: " << (int)arg4
			<< L"  Arg5: " << (int)arg5;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		break;
	}

	case EVENT_GOTO:
	{
		uint16_t dest = GetShort(curOffset); curOffset += 2;
		desc << L"Destination: $" << std::hex << std::setfill(L'0') << std::setw(4) << std::uppercase << (int)dest;
		uint32_t length = curOffset - beginOffset;

		curOffset = dest;
		if (!IsOffsetUsed(dest)) {
			AddGenericEvent(beginOffset, length, L"Jump", desc.str().c_str(), CLR_LOOPFOREVER);
		}
		else {
			bContinue = AddLoopForever(beginOffset, length, L"Jump");
		}
		break;
	}

	case EVENT_LOOP_END:
	{
		uint8_t repeatNest = GetByte(curOffset++);
		uint16_t dest = GetShort(curOffset); curOffset += 2;

		desc << L"Nest Level: " << (int)repeatNest << L"  Destination: $" << std::hex << std::setfill(L'0') << std::setw(4) << std::uppercase << (int)dest;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Repeat End", desc.str().c_str(), CLR_LOOP, ICON_ENDREP);

		repeatCount[repeatNest]--;
		if (repeatCount[repeatNest] != 0) {
			curOffset = dest;
		}
		break;
	}

	case EVENT_END:
	{
		AddEndOfTrack(beginOffset, curOffset-beginOffset);
		bContinue = false;
		break;
	}

	case EVENT_VIBRATO:
	{
		uint8_t envelopeIndex = GetByte(curOffset++);
		desc << L"Envelope Index: " << (int)envelopeIndex;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Vibrato", desc.str().c_str(), CLR_MODULATION, ICON_CONTROL);
		break;
	}

	case EVENT_PORTAMENTO_TIME:
	{
		uint8_t rate = GetByte(curOffset++);
		desc << L"Rate: " << (int)rate;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Portamento Time", desc.str().c_str(), CLR_PORTAMENTOTIME, ICON_CONTROL);
		break;
	}

	case EVENT_VOLUME:
	{
		uint8_t newVolume = GetByte(curOffset++);
		spcVolume = newVolume;
		uint8_t midiVolume = Convert7bitPercentVolValToStdMidiVal(spcVolume / 2);
		AddVol(beginOffset, curOffset - beginOffset, midiVolume);
		break;
	}

	case EVENT_VOLUME_ENVELOPE:
	{
		uint8_t envelopeIndex = GetByte(curOffset++);
		desc << L"Envelope Index: " << (int)envelopeIndex;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Volume Envelope", desc.str().c_str(), CLR_VOLUME, ICON_CONTROL);
		break;
	}

	case EVENT_TRANSPOSE:
	{
		int8_t delta = (int8_t)GetByte(curOffset++);
		spcTranspose += delta;
		AddTranspose(beginOffset, curOffset - beginOffset, spcTranspose, L"Transpose (Relative)");
		break;
	}

	case EVENT_VOLUME_REL:
	{
		int8_t delta = (int8_t)GetByte(curOffset++);
		spcVolume += delta;
		uint8_t midiVolume = Convert7bitPercentVolValToStdMidiVal(spcVolume / 2);
		AddVol(beginOffset, curOffset - beginOffset, midiVolume, L"Volume (Relative)");
		break;
	}

	case EVENT_NOTE:
	{
		bool rest = (statusByte == 0x00);

		uint8_t duration;
		bool hasDuration = ReadDurationBytes(curOffset, duration);
		if (hasDuration) {
			spcNoteDuration = duration;
			desc << L"Duration: " << (int)duration;
		}

		if (rest) {
			AddRest(beginOffset, curOffset - beginOffset, spcNoteDuration);
		}
		else {
			uint8_t noteNumber = statusByte - 1;
			AddNoteByDur(beginOffset, curOffset - beginOffset, noteNumber, 100, spcNoteDuration,
				hasDuration ? L"Note with Duration" : L"Note");
			AddTime(spcNoteDuration);
		}
		break;
	}

	case EVENT_LOOP_COUNT:
	{
		uint8_t repeatNest = GetByte(curOffset++);
		uint8_t times = GetByte(curOffset++);
		int actualTimes = (times == 0) ? 256 : times;

		desc << L"Nest Level: " << (int)repeatNest << L"  Times: " << actualTimes;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Loop Count", desc.str().c_str(), CLR_LOOP, ICON_STARTREP);

		repeatCount[repeatNest] = times;
		break;
	}

	case EVENT_FLAGS:
	{
		uint8_t flags = GetByte(curOffset++);
		spcFlags = flags;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Flags", desc.str().c_str(), CLR_CHANGESTATE, ICON_CONTROL);
		break;
	}

	case EVENT_TEMPO:
	{
		uint8_t newTempo = GetByte(curOffset++);
		spcTempo = newTempo;
		AddTempoBPM(beginOffset, curOffset - beginOffset, parentSeq->GetTempoInBPM(newTempo));
		break;
	}

	case EVENT_TUNING:
	{
		int16_t newTuning;
		if (parentSeq->version == COMPILESNES_ALESTE || parentSeq->version == COMPILESNES_JAKICRUSH) {
			newTuning = (int8_t)GetByte(curOffset++);
		}
		else {
			newTuning = (int16_t)GetShort(curOffset); curOffset += 2;
		}

		desc << L"Pitch Register Delta: " << (int)newTuning;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Tuning", desc.str().c_str(), CLR_CHANGESTATE, ICON_CONTROL);
		break;
	}

	case EVENT_CALL:
	{
		uint16_t dest = GetShort(curOffset); curOffset += 2;
		desc << L"Destination: $" << std::hex << std::setfill(L'0') << std::setw(4) << std::uppercase << (int)dest;

		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Pattern Play", desc.str().c_str(), CLR_LOOP, ICON_STARTREP);

		subReturnAddress = curOffset;
		curOffset = dest;
		break;
	}

	case EVENT_RET:
	{
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"End Pattern", desc.str().c_str(), CLR_TRACKEND, ICON_ENDREP);
		curOffset = subReturnAddress;
		break;
	}

	case EVENT_PROGCHANGE:
	{
		uint8_t newProg = GetByte(curOffset++);
		AddProgramChange(beginOffset, curOffset - beginOffset, newProg, true);
		break;
	}

	case EVENT_ADSR:
	{
		uint8_t envelopeIndex = GetByte(curOffset++);
		desc << L"Envelope Index: " << (int)envelopeIndex;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"ADSR", desc.str().c_str(), CLR_VOLUME, ICON_CONTROL);
		break;
	}

	case EVENT_PORTAMENTO_ON:
	{
		spcFlags |= COMPILESNES_FLAGS_PORTAMENTO;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Portamento On", desc.str().c_str(), CLR_PORTAMENTO, ICON_CONTROL);
		break;
	}

	case EVENT_PORTAMENTO_OFF:
	{
		spcFlags &= ~COMPILESNES_FLAGS_PORTAMENTO;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Portamento Off", desc.str().c_str(), CLR_PORTAMENTO, ICON_CONTROL);
		break;
	}

	case EVENT_PANPOT_ENVELOPE:
	{
		uint8_t envelopeIndex = GetByte(curOffset++);
		desc << L"Envelope Index: " << (int)envelopeIndex;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Panpot Envelope", desc.str().c_str(), CLR_PAN, ICON_CONTROL);
		break;
	}

	case EVENT_PAN:
	{
		int8_t newPan = GetByte(curOffset++);
		spcPan = newPan;

		double volumeScale;
		uint8_t midiPan = Convert7bitLinearPercentPanValToStdMidiVal((uint8_t)(newPan + 0x80) / 2, &volumeScale);
		AddExpressionNoItem(ConvertPercentAmpToStdMidiVal(volumeScale));
		AddPan(beginOffset, curOffset - beginOffset, midiPan);
		break;
	}

	case EVENT_LOOP_BREAK:
	{
		uint8_t repeatNest = GetByte(curOffset++);
		uint16_t dest = GetShort(curOffset); curOffset += 2;

		desc << L"Nest Level: " << (int)repeatNest << L"  Destination: $" << std::hex << std::setfill(L'0') << std::setw(4) << std::uppercase << (int)dest;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Repeat Break", desc.str().c_str(), CLR_LOOP, ICON_ENDREP);

		repeatCount[repeatNest]--;
		if (repeatCount[repeatNest] == 0) {
			curOffset = dest;
		}
		break;
	}

	case EVENT_DURATION_DIRECT:
	{
		uint8_t duration;
		if (!ReadDurationBytes(curOffset, duration)) {
			// address out of range
			return false;
		}
		spcNoteDuration = duration;

		desc << L"Duration: " << (int)duration;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Duration (Direct)", desc.str().c_str(), CLR_DURNOTE, ICON_CONTROL);
		break;
	}

	case EVENT_DURATION:
	{
		uint8_t duration;
		if (!ReadDurationBytes(curOffset, duration)) {
			// address out of range
			return false;
		}
		spcNoteDuration = duration;

		desc << L"Duration: " << (int)duration;
		AddGenericEvent(beginOffset, curOffset - beginOffset, L"Duration", desc.str().c_str(), CLR_DURNOTE, ICON_CONTROL);
		break;
	}

	case EVENT_PERCUSSION_NOTE:
	{
		uint8_t duration;
		bool hasDuration = ReadDurationBytes(curOffset, duration);
		if (hasDuration) {
			spcNoteDuration = duration;
			desc << L"Duration: " << (int)duration;
		}

		uint8_t percNoteNumber = statusByte - parentSeq->STATUS_PERCUSSION_NOTE_MIN;
		AddPercNoteByDur(beginOffset, curOffset - beginOffset, percNoteNumber, 100, spcNoteDuration,
			hasDuration ? L"Percussion Note with Duration" : L"Percussion Note");
		AddTime(spcNoteDuration);
		break;
	}

	default:
		desc << L"Event: 0x" << std::hex << std::setfill(L'0') << std::setw(2) << std::uppercase << (int)statusByte;
		AddUnknown(beginOffset, curOffset-beginOffset, L"Unknown Event", desc.str().c_str());
		pRoot->AddLogItem(new LogItem((std::wstring(L"Unknown Event - ") + desc.str()).c_str(), LOG_LEVEL_ERR, L"CompileSnesSeq"));
		bContinue = false;
		break;
	}

	//wostringstream ssTrace;
	//ssTrace << L"" << std::hex << std::setfill(L'0') << std::setw(8) << std::uppercase << beginOffset << L": " << std::setw(2) << (int)statusByte  << L" -> " << std::setw(8) << curOffset << std::endl;
	//OutputDebugString(ssTrace.str().c_str());

	return bContinue;
}