It's a grab bag of arcade games made by Midway.
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#
Present in all four of the CDPAD.DAT files are a couple of placeholder graphics.
(Source: Ferrox)
Source Code#
Present in MEDA.PCK and MEDR.PCK.
#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
}
}
References#
|
The Arcade's Greatest Hits series | |
|---|---|
|
SNES |
|
|
Game Boy (Color) |
|
|
Nintendo 64 |
|
|
Dreamcast |
|
|
PlayStation |
Williams • Midway Collection 2 • Atari Collection 2 (Prototype) • Arcade Party Pak • Atari Anniversary Edition Redux |
|
Windows |
Williams Arcade Classics • Atari Arcade Hits Volume 1 • Atari Arcade Hits Volume 2 |