We just released a Feb. 5 '89 prototype of DuckTales for the NES!
If you'd like to support our preservation efforts (and this wasn't cheap), please consider donating or supporting us on Patreon. Thank you!

Arcade Party Pak

From The Cutting Room Floor
Jump to navigation Jump to search

Title Screen

Arcade Party Pak

Developer: Digital Eclipse
Publisher: Midway Games
Platform: PlayStation
Released in US: September 30, 1999
Released in EU: February 23, 2001


CopyrightIcon.png This game has hidden developer credits.
GraphicsIcon.png This game has unused graphics.


Hidden Developer Credit

Present at 0x6DDDD in SMASH.EXE is a hidden credit for the port of Smash T.V..

PORTED TO PLAYSTATION BY PULSAR INTERACTIVE, 1999, JOHN HARRIS, CHRIS IDEN, DAVID MACE
(Source: Ferrox)

Unused Graphics

OpenIcePS1-placeholder1.pngOpenIcePS1-placeholder2.png

Present in all four of the CDPAD.DAT files are a couple of placeholder graphics.


(Source: Ferrox)

Source Code

The files MEDA.PCK & MEDR.PCK contain game source code.

#include <sys/types.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <libsn.h>

#include <sys/types.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
#include <libcd.h>
#include <libspu.h>
#include <r3000.h>
#include <asm.h>
#include <kernel.h>
#include <libsn.h>

#include "xaapi.h"

#define VERBOSE

// the prototype
extern int CDFile_CdSearchFile(CdlFILE *file_info, char *filename);

void xaStop( void );



#define Min2Milli( a,b,c ) (((a)*60000) + ((b)*1000 ) + ((c)*10 ))
#define CDSpeed (1)
#define Milli2Sectors(a) (((a) * 75 <<(CDSpeed-1) ) / 1000 )
 
typedef struct XaPackFile{
	int	startSector;
	char * fileName;
}XaPackFile;

 
typedef struct XaTrack{
	int	startSector;
	int numSectors;
	int	channel;
	int	packIndex;
}XaTrack;


XaPackFile XaPacks[] = {
	{0,"BIG.PCK;1"},
	{0,"MEDBIG.PCK;1"},
	{0,"MED.PCK;1"},
	{0,"MEDS.PCK;1"},
	{0,"SMALL.PCK;1"},
	{0,0}
};
XaTrack XaTracks[]={
	//small
	{0,Milli2Sectors(Min2Milli(  0,11, 6 )),1,5}, 	//32WIN5
	{0,Milli2Sectors(Min2Milli(  0,12, 6 )),0,5}, 	//09VICMSC
	//medium small
	{0,Milli2Sectors(Min2Milli(  0,16, 9 )),7,4}, 	//28WHEEL
	{0,Milli2Sectors(Min2Milli(  0,24,54 )),6,4}, 	//720track10
	{0,Milli2Sectors(Min2Milli(  0,29,65 )),5,4}, 	//720track12
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),4,4}, 	//2CWIN2
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),3,4}, 	//12WIN7
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),2,4}, 	//14WIN8
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),1,4}, 	//2AWIN1
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),0,4}, 	//16ADDA
	// medium
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),7,3}, 	//2EWIN3
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),6,3}, 	//30WIN4
	{0,Milli2Sectors(Min2Milli(  0,30,68 )),5,3}, 	//720track13
	{0,Milli2Sectors(Min2Milli(  0,30,68 )),4,3}, 	//720track8
	{0,Milli2Sectors(Min2Milli(  0,30,17 )),3,3}, 	//34WIN6
	{0,Milli2Sectors(Min2Milli(  0,34,77 )),2,3}, 	//720track7
	{0,Milli2Sectors(Min2Milli(  0,36,81 )),1,3}, 	//720track3
	{0,Milli2Sectors(Min2Milli(  0,41,92 )),0,3}, 	//720track1
	//medium big
	{0,Milli2Sectors(Min2Milli(  0,42,95 )),7,2}, 	//720track5
	{0,Milli2Sectors(Min2Milli(  0,45, 2 )),6,2}, 	//720track2
	{0,Milli2Sectors(Min2Milli(  0,48, 8 )),5,2}, 	//720track9
	{0,Milli2Sectors(Min2Milli(  0,48, 8 )),4,2}, 	//720track11
	{0,Milli2Sectors(Min2Milli(  0,59,33 )),3,2}, 	//720track6
	{0,Milli2Sectors(Min2Milli(  1, 8,54 )),2,2}, 	//720track14
	{0,Milli2Sectors(Min2Milli(  1,12,40 )),1,2}, 	//05TUNE3
	{0,Milli2Sectors(Min2Milli(  1,28,49 )),0,2}, 	//0FHIMUSC
	//big
	{0,Milli2Sectors(Min2Milli(  1,30, 4 )),7,1}, 	//720track4
	{0,Milli2Sectors(Min2Milli(  1,41,57 )),6,1}, 	//01TUNE2
	{0,Milli2Sectors(Min2Milli(  1,57,66 )),5,1}, 	//0ETUNE4
	{0,Milli2Sectors(Min2Milli(  1,58,66 )),4,1}, 	//B2BONS1
	{0,Milli2Sectors(Min2Milli(  2, 0,68 )),3,1}, 	//02ENDT
	{0,Milli2Sectors(Min2Milli(  2, 1,68)), 2,1}, 	//03TUNE1
	{0,Milli2Sectors(Min2Milli(  2, 3,69 )),1,1}, 	//0ABTUNE3
	{0,Milli2Sectors(Min2Milli(  2, 5,70 )),0,1}, 	//04BTUNE1
	{0,0,0,0},
};


  
CdlFILTER	filter;
static 	CdlLOC pos;
static 	CdlLOC posinfo;
static 	CdlLOC pause_pos;
static 	char	  pad[16];
static 	CdlATV cdMute;
static 	unsigned int cur_pos;

static 	unsigned char result[8];
static 	unsigned char param[8];
static 	unsigned int error = 0;
static 	unsigned int good = 0;

static 	CdlATV cdVol;
static 	unsigned int Volume;

static unsigned int StartSector = 0;
static unsigned int EndSector = 0;
static unsigned int LastCommand = 0;
static unsigned int Command = 0;

#define IDLE		(0)
#define PLAY    	(1)
#define STARTING    (2)
#define NEWCOMMAND  (3)
#define ERRORCHECK  (4)

static 	unsigned int IsPaused= 0;
static 	unsigned int State= IDLE;
static 	unsigned int PausedState= IDLE;
static	unsigned int PreviousState= IDLE;

#ifdef VERBOSE
static int profile;
static int min=1000;
static int max=0;
#endif

XA_SYSTEM *xaSystem;

XA_SYSTEM xaSystemShell; 	// the lovely struct for them to see us 


// set cd mix on in spu common attr
void SetMix( void ) 
{
    SpuCommonAttr c_attr;

    /* Initialise sound */

    c_attr.mask = SPU_COMMON_CDMIX | SPU_COMMON_CDVOLL| SPU_COMMON_CDVOLR ;

    c_attr.cd.mix  = SPU_ON; 	/* cd mixing  */
    c_attr.cd.volume.left = c_attr.cd.volume.right  = 0x1fff; 	/* cd mixing volume */

    SpuSetCommonAttr(&c_attr);

}

// set cdVol struct from global volume value
void MixVol( void )
{
	*(u_long *)&cdVol = 0x00000000;
	Volume = Volume & 0xff;
	cdVol.val0 = cdVol.val3 = Volume;
	cdVol.val1 = cdVol.val2 = Volume;
}


// start song 
static void xastart( unsigned long command)
{
	#ifdef VERBOSE
	printf (" start %d", command );
	#endif
	LastCommand = command;

	filter.file = 1;
	filter.chan = XaTracks[command].channel;

	StartSector = XaTracks[command].startSector;
	EndSector = StartSector + ( XaTracks[command].numSectors) ;

   	CdControlB(CdlSetfilter, (u_char *)&filter, 0) ;

	State = STARTING;
} 

void Ready ( u_char intr, u_char *result )
{
	if (intr == CdlDiskError ) error++;
	if (intr == CdlDataReady )
	{
		CdGetSector(( int *) &posinfo,2);
		cur_pos = CdPosToInt(&posinfo);
		good++;
	}
}

int xaService( void )
{
	int RcntIn;
	#ifdef VERBOSE
	pollhost();
	#endif

	if( IsPaused ) return;
	if( State == IDLE ) return;
	SetMix();		//should not need this
	#ifdef VERBOSE
	RcntIn = profile = VSync(1);
	#endif

	switch( State){
		case NEWCOMMAND:
			CdReadyCallback ( 0 );
			xastart( Command );
			cur_pos = 0;
			break;
		case STARTING:
			SetMix();		//should not need this!
			CdIntToPos( StartSector , &pos);
		  	CdControlF(CdlReadS, (u_char *)&pos);
			CdReadyCallback ( Ready );
			MixVol();
			State = ERRORCHECK;
			break;
		case ERRORCHECK:
			CdSync( 1, result );
			if ( result[0] == CdlNoIntr ) 
			{
				break;
			}
			if ( result[0] == CdlComplete )
			{
				State = PLAY;
			}	
			if ( result[0] == CdlDiskError ) 
			{
				State = STARTING;
			}
			break;

		case PLAY:
		/* check for end of xa track */			
	  	if( cur_pos > EndSector )
		{
			#ifdef VERBOSE
			printf( " END ");
			#endif
			xaStop();
	  	}
		else
		{
			CdMix( &cdVol);
		}
		break;
	}

	#ifdef VERBOSE
	profile = VSync(1) - profile;
	if( profile > max ) max = profile;
	if( profile < min ) min = profile;
	#endif

	return 1; //success
	
}

void xaInit( void )
{
	CdInit();
	SetMix();
	Volume = 0xff;						//full on
	*(u_long *)&cdVol = 0xffffffff;		// full on
	*(u_long *)&cdMute = 0;				// init mute 
	CdMix( &cdMute);					//start out muted
	param[0] = 	 CdlModeRT | CdlModeSF | CdlModeSize1;	  //1x ,ADPCM, filter
	if ( CDSpeed == 2 ){
		param[0] |= 	 CdlModeSpeed;	  //2x	- never happen
	}
  	while (CdControlB(CdlSetmode, param, 0) == 0);		//set cd system in xa streaming mode..

	filter.file = 1;									  //file 1 channel 0
	filter.chan = 0;
  	while (CdControlB(CdlSetfilter, (u_char *)&filter, 0) == 0);// just in case

   	CdIntToPos( XaTracks[0].startSector , &pos);
  	while (CdControlB(CdlSeekL, (u_char *)&pos, 0) == 0);		// seek towards xa data - might help first seek

	CdSync(0,0);		//blocking sync - wait until seek is completed

  	CdControlB(CdlPause,  (u_char *)&pos, 0);		// pause at the xa data area
	
	State= IDLE;
	printf( ( "xa init" ));
	CdReadyCallback ( 0 );							// no callback becasue no xa playing

}
void xaPlay( unsigned long command )
{
	#ifdef VERBOSE
	printf("command %d ",command  );
	#endif
	Command = command;			//twisted shit
	State = NEWCOMMAND;
}


void xaStop( void )
{
	if( State == IDLE ) return;		// can't stop if not playing

	#ifdef VERBOSE
	printf("STOP !!! ");
	#endif
  	CdControlB(CdlPause, 0, 0);

	CdMix( &cdMute);
	State = IDLE;
}
void xaSetVolume( unsigned char volume )
{
	#ifdef VERBOSE
	printf ( "xaSetVolume %d ",volume );
	#endif
	Volume = volume;
	MixVol();

}


//never ever used!
unsigned char xaGetStatus( void )
{
	return State == PLAY;
}

// just use this stuff because it wroks!
void xaPause( void )
{
	if( IsPaused ) return;
	if( State == IDLE ) return;
	CdSync(0,0);

	CdMix( &cdMute);
	IsPaused = 1;
	PausedState= State;

	CdReadyCallback ( 0 );

	do
	{
		CdControl(CdlNop, 0,result);
	}while( result[0] == CdlStatSeek );
  	CdControlB(CdlGetlocL, 0, (u_char *)&pause_pos);
	CdSync(0,0);

  	CdControlB(CdlSeekL,  (u_char *)&pause_pos, 0);
	CdSync(0,0);

  	CdControlB(CdlPause,  (u_char *)&pause_pos, 0);
	CdSync(0,0);
}

void xaResume( void )
{
	if( !IsPaused ) return;
	if( State == IDLE ) return;
	
	IsPaused= 0;

	CdSync(0,0);
  	CdControl(CdlReadS, (u_char *)&pause_pos, 0);
	CdMix( &cdVol);
	State = PausedState;
	CdReadyCallback ( Ready );
}

int XaHandler( void )
{	
	switch( xaSystem->xaSystemRequest )
	{
		case XA_INIT:
			xaInit();
			break;
		case XA_PLAY:
			xaPlay( xaSystem->xaCommandData );
			break;
		case XA_STOP:
			xaStop();
			break;
		case XA_SET_VOLUME:
			xaSetVolume( xaSystem->xaCommandData );
			break;
		case XA_PAUSE:
			xaPause();
			break;
		case XA_RESUME:
			xaResume();
			break;

		case XA_GETSTATUS:
			xaSystem->xaCommandData = xaGetStatus();
			break;

		default:
			// whats up with this - no error checking?
	}
	return 1;		//success!
}
void CacheXADirectory( void ){
 	CdlFILE thisFile;
 	CdlLOC		thisLocation;
	unsigned int thisSector;
	int i=0;

	// get the start sector for each pscked xa file
	while( XaPacks[i].fileName ){

		CDFile_CdSearchFile( &thisFile, XaPacks[i].fileName);
		thisLocation = thisFile.pos;
		thisSector = CdPosToInt( &thisLocation );
		XaPacks[i].startSector = thisSector;
		i++;
	}

	i = 0;
	// patch the start sector into each track 
	// note: packIndex is offset by one to ease null termination
	// note: add channel offset to packed files starsector to get xa data start sector 
	while( XaTracks[i].packIndex ){
		XaTracks[i].startSector = XaPacks[XaTracks[i].packIndex-1].startSector + XaTracks[i].channel ;
		i++;
	}
}


/*sample usage
	XA_CALL->xaSystemRequest = XA_INIT;
	XA_CALL->xaCommandHandler();
	XA_CALL->xaSystemRequest = XA_PLAY;
	XA_CALL->xaCommandData = XA_01TUNE2;
	XA_CALL->xaCommandHandler();

also need a regular call to:
	XA_CALL->xaVsyncService();



*/
void XaSystemPreInit( void )
{
	// cache all the file starts in each xa entry
	CacheXADirectory();

	// set the interface peep-hole to point to the shells xa system struct
	*((unsigned int * )XA_SYSTEM_POINTER) = (unsigned int)&xaSystemShell;
	xaSystem = (XA_SYSTEM*)*((unsigned int * )XA_SYSTEM_POINTER);

	// set the struct entries:
	// function dispathcher
 	xaSystem->xaCommandHandler = &XaHandler;
	// regular service
	xaSystem->xaVsyncService = &xaService;
	// function type
	xaSystem->xaSystemRequest = XA_NULL;
	// function data
 	xaSystem->xaCommandData = 0;
}


// temporary shit to test one xa track
void TestTheXaCrap( void ){

	int i,j;

	xaSystem->xaSystemRequest = XA_INIT;
	xaSystem->xaCommandHandler();


	i = 0;
	// patch the start sector into each track 
	// note: packIndex is offset by one to ease null termination
	// note: add channel offset to packed files starsector to get xa data start sector 
	while( XaTracks[i].packIndex ){

		xaSystem->xaSystemRequest = XA_PLAY;
		xaSystem->xaCommandData = (enumXAs)i;
		xaSystem->xaCommandHandler();


		do{
			VSync(0);
			xaSystem->xaVsyncService();

			xaSystem->xaSystemRequest = XA_GETSTATUS;
			xaSystem->xaCommandHandler();

		}while( xaSystem->xaCommandData );
		i++;
		for ( j = 0;j<180 ;j++) VSync(0);	// wait one second between songs
	}
}