15 #define kPollEveryNFrames 4 //Poll input only every this many frames
17 #define TRACE printf("trace: %s:%s\n", __FILE__, __func__);
18 #define DIE(format, ...) do { \
19 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
20 fprintf(stderr, format "\n", ## __VA_ARGS__); \
24 void S9xMessage(int type, int number, const char * message)
26 printf("%s\n", message);
29 void S9xLoadSDD1Data()
31 Settings.SDD1Pack=FALSE;
36 if (!Memory.Init () || !S9xInitAPU())
37 DIE("Memory or APU failed");
41 S9xSetSoundMute (TRUE);
43 // TODO: PAL/NTSC something better than this
44 Settings.PAL = Settings.ForcePAL;
46 Settings.FrameTime = Settings.PAL?Settings.FrameTimePAL:Settings.FrameTimeNTSC;
47 Memory.ROMFramesPerSecond = Settings.PAL?50:60;
49 IPPU.RenderThisFrame = TRUE;
54 const char * file = S9xGetFilename(".smc");
56 printf("ROM: %s\n", file);
58 if (!Memory.LoadROM(file))
59 DIE("Loading ROM failed");
61 file = S9xGetFilename(".srm");
62 printf("SRAM: %s\n", file);
63 Memory.LoadSRAM(file);
66 /* This comes nearly straight from snes9x */
67 static void frameSync() {
68 static struct timeval next1 = {0, 0};
71 if (Settings.TurboMode)
73 if(Settings.SkipFrames == AUTO_FRAMERATE ||
74 ++IPPU.FrameSkip >= Settings.SkipFrames)
77 IPPU.SkippedFrames = 0;
78 IPPU.RenderThisFrame = TRUE;
83 IPPU.RenderThisFrame = FALSE;
90 while (gettimeofday(&now, 0) < 0);
92 /* If there is no known "next" frame, initialize it now */
93 if (next1.tv_sec == 0) { next1 = now; ++next1.tv_usec; }
95 /* If we're on AUTO_FRAMERATE, we'll display frames always
96 * only if there's excess time.
97 * Otherwise we'll display the defined amount of frames.
99 unsigned limit = Settings.SkipFrames == AUTO_FRAMERATE
100 ? (timercmp(&next1, &now, <) ? 10 : 1)
101 : Settings.SkipFrames;
103 IPPU.RenderThisFrame = ++IPPU.SkippedFrames >= limit;
104 if(IPPU.RenderThisFrame)
106 IPPU.SkippedFrames = 0;
110 /* If we were behind the schedule, check how much it is */
111 if(timercmp(&next1, &now, <))
114 (now.tv_sec - next1.tv_sec) * 1000000
115 + now.tv_usec - next1.tv_usec;
118 /* More than a half-second behind means probably
119 * pause. The next line prevents the magic
120 * fast-forward effect.
127 /* Delay until we're completed this frame */
129 /* Can't use setitimer because the sound code already could
130 * be using it. We don't actually need it either.
133 while(timercmp(&next1, &now, >))
135 /* If we're ahead of time, sleep a while */
137 (next1.tv_sec - now.tv_sec) * 1000000
138 + next1.tv_usec - now.tv_usec;
142 // XXX : CHECK_SOUND(); S9xProcessEvents(FALSE);
144 while (gettimeofday(&now, 0) < 0);
145 /* Continue with a while-loop because usleep()
146 * could be interrupted by a signal
150 /* Calculate the timestamp of the next frame. */
151 next1.tv_usec += Settings.FrameTime;
152 if (next1.tv_usec >= 1000000)
154 next1.tv_sec += next1.tv_usec / 1000000;
155 next1.tv_usec %= 1000000;
159 /** Wraps s9xProcessEvents, taking care of kPollEveryNFrames */
160 static inline void pollEvents() {
161 static int frames = 0;
163 if (++frames > kPollEveryNFrames) {
164 S9xProcessEvents(FALSE);
169 int main(int argc, const char ** argv) {
172 DIE("SDL_Init: %s", SDL_GetError());
175 S9xLoadConfig(argc, argv);
177 // S9x initialization
178 S9xInitDisplay(argc, argv);
179 S9xInitAudioOutput();
180 S9xInitInputDevices();
184 // Load rom and related files
187 // Late initialization
188 sprintf(String, "DrNokSnes - %s", Memory.ROMName);
190 S9xHacksLoadFile(Config.hacksFile[0] ? Config.hacksFile : 0);
191 if (!S9xGraphicsInit())
192 DIE("S9xGraphicsInit failed");
193 S9xAudioOutputEnable(true);
196 frameSync(); // May block, or set frameskip to true.
197 S9xMainLoop(); // Does CPU things, renders if needed.
199 } while (!Config.quitting);
202 S9xAudioOutputEnable(false);
203 S9xDeinitAudioOutput();
212 void S9xDoAction(unsigned char action)
214 if (action & kActionQuit)
215 Config.quitting = true;
217 if (action & kActionToggleFullscreen)
218 S9xVideoToggleFullscreen();