Пример #1
0
static void RoundVGMData(void)
{
	UINT32 DstPos;
	UINT8 ChipID;
	UINT8 Command;
	UINT32 CmdDelay;
	UINT8 TempByt;
	UINT16 TempSht;
	UINT32 TempLng;
#ifdef WIN32
	UINT32 CmdTimer;
	char TempStr[0x80];
	char MinSecStr[0x80];
#endif
	UINT32 CmdLen;
	bool StopVGM;
	bool IsDelay;
	bool WasDelay;
	bool WriteEvent;
	UINT32 LoopPos;
	UINT32 DelayQueue;
	
	DstData = (UINT8*)malloc(VGMDataLen);
	VGMPos = VGMHead.lngDataOffset;
	DstPos = VGMHead.lngDataOffset;
	
	DidSomething = false;
#ifdef WIN32
	CmdTimer = 0;
#endif
	VGMSmplPos = 0x00;
	DelayQueue = 0x00;
	LoopPos = 0x00;
	StopVGM = false;
	IsDelay = false;
	while(VGMPos < VGMHead.lngEOFOffset)
	{
		CmdLen = 0x00;
		Command = VGMData[VGMPos + 0x00];
		WasDelay = IsDelay;
		IsDelay = false;
		
		CmdDelay = 0x00;
		if (Command >= 0x70 && Command <= 0x8F)
		{
			switch(Command & 0xF0)
			{
			case 0x70:
				TempSht = (Command & 0x0F) + 0x01;
				VGMSmplPos += TempSht;
				CmdDelay = TempSht;
				IsDelay = true;
				break;
			case 0x80:
				TempSht = Command & 0x0F;
				VGMSmplPos += TempSht;
				CmdDelay = TempSht;
				break;
			}
			CmdLen = 0x01;
		}
		else
		{
			// Cheat Mode (to use 2 instances of 1 chip)
			ChipID = 0x00;
			switch(Command)
			{
			case 0x30:
				if (VGMHead.lngHzPSG & 0x40000000)
				{
					Command += 0x20;
					ChipID = 0x01;
				}
				break;
			case 0xA1:
				if (VGMHead.lngHzYM2413 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xA2:
			case 0xA3:
				if (VGMHead.lngHzYM2612 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xA4:
				if (VGMHead.lngHzYM2151 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xA5:
				if (VGMHead.lngHzYM2203 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xA6:
			case 0xA7:
				if (VGMHead.lngHzYM2608 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xA8:
			case 0xA9:
				if (VGMHead.lngHzYM2610 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xAA:
				if (VGMHead.lngHzYM3812 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xAB:
				if (VGMHead.lngHzYM3526 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			case 0xAC:
				if (VGMHead.lngHzY8950 & 0x40000000)
				{
					Command -= 0x50;
					ChipID = 0x01;
				}
				break;
			}
			
			switch(Command)
			{
			case 0x66:	// End Of File
				CmdLen = 0x01;
				StopVGM = true;
				break;
			case 0x62:	// 1/60s delay
				TempSht = 735;
				VGMSmplPos += TempSht;
				CmdDelay = TempSht;
				CmdLen = 0x01;
				IsDelay = true;
				break;
			case 0x63:	// 1/50s delay
				TempSht = 882;
				VGMSmplPos += TempSht;
				CmdDelay = TempSht;
				CmdLen = 0x01;
				IsDelay = true;
				break;
			case 0x61:	// xx Sample Delay
				memcpy(&TempSht, &VGMData[VGMPos + 0x01], 0x02);
				VGMSmplPos += TempSht;
				CmdDelay = TempSht;
				CmdLen = 0x03;
				IsDelay = true;
				break;
			case 0x50:	// SN76496 write
				CmdLen = 0x02;
				break;
			case 0x51:	// YM2413 write
				CmdLen = 0x03;
				break;
			case 0x52:	// YM2612 write port 0
			case 0x53:	// YM2612 write port 1
				CmdLen = 0x03;
				break;
			case 0x67:	// PCM Data Stream
				TempByt = VGMData[VGMPos + 0x02];
				memcpy(&TempLng, &VGMData[VGMPos + 0x03], 0x04);
				TempLng &= 0x7FFFFFFF;
				CmdLen = 0x07 + TempLng;
				break;
			case 0xE0:	// Seek to PCM Data Bank Pos
				CmdLen = 0x05;
				break;
			case 0x4F:	// GG Stereo
				CmdLen = 0x02;
				break;
			case 0x54:	// YM2151 write
				CmdLen = 0x03;
				break;
			case 0xC0:	// Sega PCM memory write
				CmdLen = 0x04;
				break;
			case 0xB0:	// RF5C68 register write
				CmdLen = 0x03;
				break;
			case 0xC1:	// RF5C68 memory write
				CmdLen = 0x04;
				break;
			case 0x55:	// YM2203
				CmdLen = 0x03;
				break;
			case 0x56:	// YM2608 write port 0
			case 0x57:	// YM2608 write port 1
				CmdLen = 0x03;
				break;
			case 0x58:	// YM2610 write port 0
			case 0x59:	// YM2610 write port 1
				CmdLen = 0x03;
				break;
			case 0x5A:	// YM3812 write
				CmdLen = 0x03;
				break;
			case 0x5B:	// YM3526 write
				CmdLen = 0x03;
				break;
			case 0x5C:	// Y8950 write
				CmdLen = 0x03;
				break;
			case 0x5E:	// YMF262 write port 0
			case 0x5F:	// YMF262 write port 1
				CmdLen = 0x03;
				break;
			case 0x5D:	// YMZ280B write
				CmdLen = 0x03;
				break;
			case 0x68:	// PCM RAM write
				CmdLen = 0x0C;
				break;
			case 0x90:	// DAC Ctrl: Setup Chip
				CmdLen = 0x05;
				break;
			case 0x91:	// DAC Ctrl: Set Data
				CmdLen = 0x05;
				break;
			case 0x92:	// DAC Ctrl: Set Freq
				CmdLen = 0x06;
				break;
			case 0x93:	// DAC Ctrl: Play from Start Pos
				CmdLen = 0x0B;
				break;
			case 0x94:	// DAC Ctrl: Stop immediately
				CmdLen = 0x02;
				break;
			case 0x95:	// DAC Ctrl: Play Block (small)
				CmdLen = 0x05;
				break;
			default:
				switch(Command & 0xF0)
				{
				case 0x30:
				case 0x40:
					CmdLen = 0x02;
					break;
				case 0x50:
				case 0xA0:
				case 0xB0:
					CmdLen = 0x03;
					break;
				case 0xC0:
				case 0xD0:
					CmdLen = 0x04;
					break;
				case 0xE0:
				case 0xF0:
					CmdLen = 0x05;
					break;
				default:
					printf("Unknown Command: %X\n", Command);
					CmdLen = 0x01;
					//StopVGM = true;
					break;
				}
				break;
			}
		}
		WriteEvent = ! IsDelay;
		
		if (VGMHead.lngLoopOffset && VGMPos == VGMHead.lngLoopOffset)
		{
			LoopPos = DstPos;
			WasDelay = true;
		}
		if (IsDelay)
		{
			if (! DelayQueue && CmdDelay > MAX_SMALL_DELAY)
			{
				WriteEvent = true;
			}
			else if (CmdDelay <= MAX_SMALL_DELAY && ! WasDelay)
			{
				DelayQueue += CmdDelay;
				DidSomething = true;
			}
			else
			{
				if (WasDelay)
				{
					CmdDelay = 0x00;
					WriteEvent = true;
				}
				CmdDelay += DelayQueue;
				while(CmdDelay)
				{
					if (CmdDelay <= 0xFFFF)
						TempSht = (UINT16)CmdDelay;
					else
						TempSht = 0xFFFF;
					
					if (TempSht <= 0x10)
					{
						DstData[DstPos] = 0x70 | (TempSht - 0x01);
						DstPos ++;
					}
					else
					{
						DstData[DstPos + 0x00] = 0x61;
						memcpy(&DstData[DstPos + 0x01], &TempSht, 0x02);
						DstPos += 0x03;
					}
					CmdDelay -= TempSht;
				}
				DelayQueue = 0x00;
			}
		}
		if (WriteEvent)
		{
			memcpy(&DstData[DstPos], &VGMData[VGMPos], CmdLen);
			DstPos += CmdLen;
		}
		VGMPos += CmdLen;
		if (StopVGM)
			break;
		
#ifdef WIN32
		if (CmdTimer < GetTickCount())
		{
			PrintMinSec(VGMSmplPos, MinSecStr);
			PrintMinSec(VGMHead.lngTotalSamples, TempStr);
			TempLng = VGMPos - VGMHead.lngDataOffset;
			CmdLen = VGMHead.lngEOFOffset - VGMHead.lngDataOffset;
			printf("%04.3f %% - %s / %s (%08X / %08X) ...\r", (float)TempLng / CmdLen * 100,
					MinSecStr, TempStr, VGMPos, VGMHead.lngEOFOffset);
			CmdTimer = GetTickCount() + 200;
		}
#endif
	}
	VGMHead.lngTotalSamples = VGMSmplPos - DelayQueue;
	
	if (VGMHead.lngLoopOffset && ! LoopPos)
		printf("Warning! Failed to relocate Loop Point!\n");
	
	WriteVGMHeader(DstData, VGMData, DstPos, LoopPos);
	
	return;
}
Пример #2
0
//----------------------------------------------------------------------------------------------
// Pause optimiser
//----------------------------------------------------------------------------------------------
BOOL OptimiseVGMPauses(char *filename) {
  gzFile *in,*out;
  struct TVGMHeader VGMHeader;
  char *outfilename,b0,b1,b2;
  long int OldLoopOffset;
  int i,PauseLength=0;

  if (!FileExists(filename)) return FALSE;

  // Open input file
  in=gzopen(filename,"rb");

  // Read its VGM header
  if(!ReadVGMHeader(in,&VGMHeader,FALSE)) {
    gzclose(in);
	return FALSE;
  }

  OldLoopOffset=VGMHeader.LoopOffset+LOOPDELTA;

  // Make the output filename...
  outfilename=MakeTempFilename(filename);
  
  // ...open it...
  out=gzopen(outfilename,"wb0");

  // ...skip to the data section...
  gzseek(in,VGM_DATA_OFFSET,SEEK_SET);
  gzseek(out,VGM_DATA_OFFSET,SEEK_SET);

  // ...and parse the input file
  // Go through the file; if it's a pause, add it to the total; if it's data, write the current total and zero it
  do {
    // Update loop point
    // Write any remaining pauyse being buffered first, though
    if (gztell(in)==OldLoopOffset) {
      WritePause(out,PauseLength);
      PauseLength=0;
      VGMHeader.LoopOffset=gztell(out)-LOOPDELTA;
    }

    b0=gzgetc(in);
    switch (b0) {
    case VGM_GGST:  // GG stereo
    case VGM_PSG:  // PSG write
      WritePause(out,PauseLength);
      PauseLength=0;
      b1=gzgetc(in);
      gzputc(out,b0);
      gzputc(out,b1);
      break;
    case VGM_YM2413:  // YM2413
    case VGM_YM2612_0:  // YM2612 port 0
    case VGM_YM2612_1:  // YM2612 port 1
    case VGM_YM2151:  // YM2151
    case 0x55:  // Reserved up to 0x5f
    case 0x56:  // All have 2 bytes of data
    case 0x57:
    case 0x58:
    case 0x59:
    case 0x5a:
    case 0x5b:
    case 0x5c:
    case 0x5d:
    case 0x5e:
    case 0x5f:
      WritePause(out,PauseLength);
      PauseLength=0;
      b1=gzgetc(in);
      b2=gzgetc(in);
      gzputc(out,b0);
      gzputc(out,b1);
      gzputc(out,b2);
      break;
    case VGM_PAUSE_WORD:  // Wait n samples
      b1=gzgetc(in);
      b2=gzgetc(in);
      PauseLength+=MAKEWORD(b1,b2);
      break;
    case VGM_PAUSE_60TH:  // Wait 1/60 s
      PauseLength+=LEN60TH;
      break;
    case VGM_PAUSE_50TH:  // Wait 1/50 s
      PauseLength+=LEN50TH;
      break;
//    case VGM_PAUSE_BYTE:  // Wait n samples
//      b1=gzgetc(in);
//      PauseLength+=b1;
//      break;
    case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
    case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // Wait 1-16 samples
      PauseLength+=(b0 & 0xf)+1;
      break;
    case VGM_END:  // End of sound data
      WritePause(out,PauseLength);
      PauseLength=0;
      b0=EOF;  // break out of loop
      break;
    default:
      break;
    }  // end switch
  } while (b0!=EOF);

  // At end:
  // 1. Write EOF mrker
  gzputc(out,VGM_END);
  // 2. Copy GD3 tag
  if (VGMHeader.GD3Offset) {
    struct TGD3Header GD3Header;
    int NewGD3Offset=gztell(out)-GD3DELTA;
    gzseek(in,VGMHeader.GD3Offset+GD3DELTA,SEEK_SET);
    gzread(in,&GD3Header,sizeof(GD3Header));
    gzwrite(out,&GD3Header,sizeof(GD3Header));
    for (i=0; i<GD3Header.Length; ++i) gzputc(out,gzgetc(in));
    VGMHeader.GD3Offset=NewGD3Offset;
  }
  // 3. Fill in VGM header
  VGMHeader.EoFOffset=gztell(out)-EOFDELTA;
  // LoopOffset updated while optimising

  gzclose(out);

  WriteVGMHeader(outfilename,VGMHeader);

  // Clean up
  gzclose(in);

  ReplaceFile(filename,outfilename);

  free(outfilename);

  return TRUE;
}