/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include "main.h" #include "throttle.h" #include "../common/cheat.h" #include "input.h" #include "dface.h" extern int32 fps_scale; int CloseGame(void); static char *soundrecfn=0; /* File name of sound recording. */ static int ntsccol=0,ntschue=0,ntsctint=0; int soundvol=100; long soundq=0; int _sound=1; long soundrate=48000; #ifdef WIN32 long soundbufsize=52; #else long soundbufsize=24; #endif #ifdef FRAMESKIP static int frameskip=0; #endif static int inited=0; static int isloaded=0; // Is game loaded? int srendlinev[2]={8,0}; int erendlinev[2]={231,239}; static uint8 *DrBaseDirectory; int eoptions=0; static void DriverKill(void); static int DriverInitialize(FCEUGI *gi); int gametype; FCEUGI *CurGame=NULL; static void ParseGI(FCEUGI *gi) { ParseGIInput(gi); gametype=gi->type; } #ifndef EXTGUI void FCEUD_PrintError(char *s) { puts(s); } void FCEUD_Message(char *s) { fputs(s,stdout); } #endif static char *cpalette=0; static void LoadCPalette(void) { uint8 tmpp[192]; FILE *fp; if(!(fp=FCEUD_UTF8fopen(cpalette,"rb"))) { printf(" Error loading custom palette from file: %s\n",cpalette); return; } fread(tmpp,1,192,fp); FCEUI_SetPaletteArray(tmpp); fclose(fp); } #ifdef EXTGUI extern CFGSTRUCT GUIConfig; #endif static CFGSTRUCT fceuconfig[]={ AC(soundrate), AC(soundq), AC(_sound), AC(soundvol), AC(soundbufsize), ACS(cpalette), AC(ntsctint), AC(ntschue), AC(ntsccol), AC(eoptions), ACA(srendlinev), ACA(erendlinev), ADDCFGSTRUCT(InputConfig), ADDCFGSTRUCT(DriverConfig), #ifdef EXTGUI ADDCFGSTRUCT(GUIConfig), #endif ENDCFGSTRUCT }; static void SaveConfig(void) { char tdir[2048]; sprintf(tdir,"%s"PSS"fceu98.cfg",DrBaseDirectory); FCEUI_GetNTSCTH(&ntsctint, &ntschue); SaveFCEUConfig(tdir,fceuconfig); } static void LoadConfig(void) { char tdir[2048]; sprintf(tdir,"%s"PSS"fceu98.cfg",DrBaseDirectory); FCEUI_GetNTSCTH(&ntsctint, &ntschue); /* Get default settings for if no config file exists. */ LoadFCEUConfig(tdir,fceuconfig); InputUserActiveFix(); } static void CreateDirs(void) { char *subs[7]={"fcs","fcm","snaps","gameinfo","sav","cheats","movie"}; char tdir[2048]; int x; #ifdef WIN32 mkdir(DrBaseDirectory); for(x=0;x<6;x++) { sprintf(tdir,"%s"PSS"%s",DrBaseDirectory,subs[x]); mkdir(tdir); } #else mkdir(DrBaseDirectory,S_IRWXU); for(x=0;x<6;x++) { sprintf(tdir,"%s"PSS"%s",DrBaseDirectory,subs[x]); mkdir(tdir,S_IRWXU); } #endif } #ifndef WIN32 static void SetSignals(void (*t)(int)) { int sigs[11]={SIGINT,SIGTERM,SIGHUP,SIGPIPE,SIGSEGV,SIGFPE,SIGKILL,SIGALRM,SIGABRT,SIGUSR1,SIGUSR2}; int x; for(x=0;x<11;x++) signal(sigs[x],t); } static void CloseStuff(int signum) { DriverKill(); printf("\nSignal %d has been caught and dealt with...\n",signum); switch(signum) { case SIGINT:printf("How DARE you interrupt me!\n");break; case SIGTERM:printf("MUST TERMINATE ALL HUMANS\n");break; case SIGHUP:printf("Reach out and hang-up on someone.\n");break; case SIGPIPE:printf("The pipe has broken! Better watch out for floods...\n");break; case SIGSEGV:printf("Iyeeeeeeeee!!! A segmentation fault has occurred. Have a fluffy day.\n");break; /* So much SIGBUS evil. */ #ifdef SIGBUS #if(SIGBUS!=SIGSEGV) case SIGBUS:printf("I told you to be nice to the driver.\n");break; #endif #endif case SIGFPE:printf("Those darn floating points. Ne'er know when they'll bite!\n");break; case SIGALRM:printf("Don't throw your clock at the meowing cats!\n");break; case SIGABRT:printf("Abort, Retry, Ignore, Fail?\n");break; case SIGUSR1: case SIGUSR2:printf("Killing your processes is not nice.\n");break; } exit(1); } #endif static void DoArgs(int argc, char *argv[]) { int x; static ARGPSTRUCT FCEUArgs[]={ {"-soundbufsize",0,&soundbufsize,0}, {"-soundrate",0,&soundrate,0}, {"-soundq",0,&soundq,0}, #ifdef FRAMESKIP {"-frameskip",0,&frameskip,0}, #endif {"-sound",0,&_sound,0}, {"-soundvol",0,&soundvol,0}, {"-cpalette",0,&cpalette,0x4001}, {"-soundrecord",0,&soundrecfn,0x4001}, {"-ntsccol",0,&ntsccol,0}, {"-pal",0,&eoptions,0x8000|EO_PAL}, {"-lowpass",0,&eoptions,0x8000|EO_LOWPASS}, {"-gg",0,&eoptions,0x8000|EO_GAMEGENIE}, {"-no8lim",0,&eoptions,0x8001}, {"-snapname",0,&eoptions,0x8000|EO_SNAPNAME}, {"-nofs",0,&eoptions,0x8000|EO_NOFOURSCORE}, {"-clipsides",0,&eoptions,0x8000|EO_CLIPSIDES}, {"-nothrottle",0,&eoptions,0x8000|EO_NOTHROTTLE}, {"-slstart",0,&srendlinev[0],0},{"-slend",0,&erendlinev[0],0}, {"-slstartp",0,&srendlinev[1],0},{"-slendp",0,&erendlinev[1],0}, {0,(int *)InputArgs,0,0}, {0,(int *)DriverArgs,0,0}, {0,0,0,0} }; ParseArguments(argc, argv, FCEUArgs); if(cpalette) { if(cpalette[0]=='0') if(cpalette[1]==0) { free(cpalette); cpalette=0; } } FCEUI_SetVidSystem((eoptions&EO_PAL)?1:0); FCEUI_SetGameGenie((eoptions&EO_GAMEGENIE)?1:0); FCEUI_SetLowPass((eoptions&EO_LOWPASS)?1:0); FCEUI_DisableSpriteLimitation(eoptions&1); FCEUI_SetSnapName(eoptions&EO_SNAPNAME); for(x=0;x<2;x++) { if(srendlinev[x]<0 || srendlinev[x]>239) srendlinev[x]=0; if(erendlinev[x]239) erendlinev[x]=239; } FCEUI_SetRenderedLines(srendlinev[0],erendlinev[0],srendlinev[1],erendlinev[1]); DoDriverArgs(); } #include "usage.h" /* Loads a game, given a full path/filename. The driver code must be initialized after the game is loaded, because the emulator code provides data necessary for the driver code(number of scanlines to render, what virtual input devices to use, etc.). */ int LoadGame(const char *path) { FCEUGI *tmp; CloseGame(); if(!(tmp=FCEUI_LoadGame(path,1))) return 0; CurGame=tmp; ParseGI(tmp); RefreshThrottleFPS(); if(!DriverInitialize(tmp)) return(0); if(soundrecfn) { if(!FCEUI_BeginWaveRecord(soundrecfn)) { free(soundrecfn); soundrecfn=0; } } isloaded=1; #ifdef EXTGUI if(eoptions&EO_AUTOHIDE) GUI_Hide(1); #endif FCEUD_NetworkConnect(); return 1; } /* Closes a game. Frees memory, and deinitializes the drivers. */ int CloseGame(void) { if(!isloaded) return(0); FCEUI_CloseGame(); DriverKill(); isloaded=0; CurGame=0; if(soundrecfn) FCEUI_EndWaveRecord(); #ifdef EXTGUI GUI_Hide(0); #endif InputUserActiveFix(); return(1); } void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); void DoFun(void) { uint8 *gfx; int32 *sound; int32 ssize; static int fskipc=0; static int opause=0; #ifdef FRAMESKIP fskipc=(fskipc+1)%(frameskip+1); #endif if(NoWaiting) {gfx=0;} FCEUI_Emulate(&gfx, &sound, &ssize, fskipc); FCEUD_Update(gfx, sound, ssize); if(opause!=FCEUI_EmulationPaused()) { opause=FCEUI_EmulationPaused(); SilenceSound(opause); } } int CLImain(int argc, char *argv[]) { int ret; if(!(ret=FCEUI_Initialize())) return(0); DrBaseDirectory=GetBaseDirectory(); FCEUI_SetBaseDirectory(DrBaseDirectory); CreateDirs(); #ifdef EXTGUI if(argc==2 && !strcmp(argv[1],"-help")) // I hope no one has a game named "-help" :b #else if(argc<=1) #endif { ShowUsage(argv[0]); return(0); } LoadConfig(); DoArgs(argc-2,&argv[1]); FCEUI_SetNTSCTH(ntsccol, ntsctint, ntschue); if(cpalette) LoadCPalette(); /* All the config files and arguments are parsed now. */ #ifdef EXTGUI return(1); #else if(!LoadGame(argv[argc-1])) { DriverKill(); return(0); } while(CurGame) DoFun(); #if(0) { int x; for(x=1;x= GetMaxSound() && fps_scale<=256) uflow=1; /* Go into massive underflow mode. */ if(can > Count) can=Count; else uflow=0; WriteSound(Buffer,can); //if(uflow) puts("Underflow"); tmpcan = GetWriteSound(); // don't underflow when scaling fps if(fps_scale>256 || ((tmpcan < Count*0.90) && !uflow)) { if(XBuf && (inited&4) && !(NoWaiting & 2)) BlitScreen(XBuf); Buffer+=can; Count-=can; if(Count) { if(NoWaiting) { can=GetWriteSound(); if(Count>can) Count=can; WriteSound(Buffer,Count); } else { while(Count>0) { WriteSound(Buffer,(Count= (Count * 1.8))) { if(Count > tmpcan) Count=tmpcan; while(tmpcan > 0) { // printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan); WriteSound(Buffer, (Count <= tmpcan)?Count : tmpcan); tmpcan -= Count; } } #endif } else { if(!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused())) SpeedThrottle(); if(XBuf && (inited&4)) { BlitScreen(XBuf); } } FCEUD_UpdateInput(); //if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE)) // SpeedThrottle(); //if(XBuf && (inited&4)) //{ // BlitScreen(XBuf); //} //if(Count) // WriteSound(Buffer,Count,NoWaiting); //FCEUD_UpdateInput(); } /* Maybe ifndef WXWINDOWS would be better? ^_^ */ #ifndef EXTGUI FILE *FCEUD_UTF8fopen(const char *fn, const char *mode) { return(fopen(fn,mode)); } #endif