Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / main.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus - main.c                                                  *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2012 CasualJames                                        *
5  *   Copyright (C) 2008-2009 Richard Goedeken                              *
6  *   Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9                       *
7  *   Copyright (C) 2002 Hacktarux                                          *
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  *   This program is distributed in the hope that it will be useful,       *
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
17  *   GNU General Public License for more details.                          *
18  *                                                                         *
19  *   You should have received a copy of the GNU General Public License     *
20  *   along with this program; if not, write to the                         *
21  *   Free Software Foundation, Inc.,                                       *
22  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
23  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25 /* This is MUPEN64's main entry point. It contains code that is common
26  * to both the gui and non-gui versions of mupen64. See
27  * gui subdirectories for the gui-specific code.
28  * if you want to implement an interface, you should look here
29  */
30
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <SDL.h>
35
36 #define M64P_CORE_PROTOTYPES 1
37 #include "api/m64p_types.h"
38 #include "api/callbacks.h"
39 #include "api/config.h"
40 #include "api/m64p_config.h"
41 #include "api/debugger.h"
42 #include "api/vidext.h"
43
44 #include "main.h"
45 #include "eventloop.h"
46 #include "rom.h"
47 #include "savestates.h"
48 #include "util.h"
49
50 #include "memory/memory.h"
51 #include "osal/files.h"
52 #include "osal/preproc.h"
53 #include "osd/osd.h"
54 #include "osd/screenshot.h"
55 #include "plugin/plugin.h"
56 #include "r4300/r4300.h"
57 #include "r4300/interupt.h"
58 #include "r4300/reset.h"
59
60 #ifdef DBG
61 #include "debugger/dbg_types.h"
62 #include "debugger/debugger.h"
63 #endif
64
65 #ifdef WITH_LIRC
66 #include "lirc.h"
67 #endif //WITH_LIRC
68
69 /* version number for Core config section */
70 #define CONFIG_PARAM_VERSION 1.01
71
72 /** globals **/
73 m64p_handle g_CoreConfig = NULL;
74
75 m64p_frame_callback g_FrameCallback = NULL;
76
77 int         g_MemHasBeenBSwapped = 0;   // store byte-swapped flag so we don't swap twice when re-playing game
78 int         g_EmulatorRunning = 0;      // need separate boolean to tell if emulator is running, since --nogui doesn't use a thread
79
80 /** static (local) variables **/
81 static int   l_CurrentFrame = 0;         // frame counter
82 static int   l_TakeScreenshot = 0;       // Tell OSD Rendering callback to take a screenshot just before drawing the OSD
83 static int   l_SpeedFactor = 100;        // percentage of nominal game speed at which emulator is running
84 static int   l_FrameAdvance = 0;         // variable to check if we pause on next frame
85 static int   l_MainSpeedLimit = 1;       // insert delay during vi_interrupt to keep speed at real-time
86
87 static osd_message_t *l_msgVol = NULL;
88 static osd_message_t *l_msgFF = NULL;
89 static osd_message_t *l_msgPause = NULL;
90
91 /*********************************************************************************************************
92 * static functions
93 */
94
95 static const char *get_savepathdefault(const char *configpath)
96 {
97     static char path[1024];
98
99     if (!configpath || (strlen(configpath) == 0)) {
100         snprintf(path, 1024, "%ssave%c", ConfigGetUserDataPath(), OSAL_DIR_SEPARATORS[0]);
101         path[1023] = 0;
102     } else {
103         snprintf(path, 1024, "%s%c", configpath, OSAL_DIR_SEPARATORS[0]);
104         path[1023] = 0;
105     }
106
107     /* create directory if it doesn't exist */
108     osal_mkdirp(path, 0700);
109
110     return path;
111 }
112
113
114 /*********************************************************************************************************
115 * helper functions
116 */
117
118
119 const char *get_savestatepath(void)
120 {
121     /* try to get the SaveStatePath string variable in the Core configuration section */
122     return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveStatePath"));
123 }
124
125 const char *get_savesrampath(void)
126 {
127     /* try to get the SaveSRAMPath string variable in the Core configuration section */
128     return get_savepathdefault(ConfigGetParamString(g_CoreConfig, "SaveSRAMPath"));
129 }
130
131 void main_message(m64p_msg_level level, unsigned int corner, const char *format, ...)
132 {
133     va_list ap;
134     char buffer[2049];
135     va_start(ap, format);
136     vsnprintf(buffer, 2047, format, ap);
137     buffer[2048]='\0';
138     va_end(ap);
139
140     /* send message to on-screen-display if enabled */
141     if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
142         osd_new_message((enum osd_corner) corner, "%s", buffer);
143     /* send message to front-end */
144     DebugMessage(level, "%s", buffer);
145 }
146
147
148 /*********************************************************************************************************
149 * global functions, for adjusting the core emulator behavior
150 */
151
152 int main_set_core_defaults(void)
153 {
154     float fConfigParamsVersion;
155     int bSaveConfig = 0, bUpgrade = 0;
156
157     if (ConfigGetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
158     {
159         DebugMessage(M64MSG_WARNING, "No version number in 'Core' config section. Setting defaults.");
160         ConfigDeleteSection("Core");
161         ConfigOpenSection("Core", &g_CoreConfig);
162         bSaveConfig = 1;
163     }
164     else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
165     {
166         DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Core' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
167         ConfigDeleteSection("Core");
168         ConfigOpenSection("Core", &g_CoreConfig);
169         bSaveConfig = 1;
170     }
171     else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
172     {
173         float fVersion = (float) CONFIG_PARAM_VERSION;
174         ConfigSetParameter(g_CoreConfig, "Version", M64TYPE_FLOAT, &fVersion);
175         DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Core' config section to %.2f", fVersion);
176         bUpgrade = 1;
177         bSaveConfig = 1;
178     }
179
180     /* parameters controlling the operation of the core */
181     ConfigSetDefaultFloat(g_CoreConfig, "Version", (float) CONFIG_PARAM_VERSION,  "Mupen64Plus Core config parameter set version number.  Please don't change this version number.");
182     ConfigSetDefaultBool(g_CoreConfig, "OnScreenDisplay", 1, "Draw on-screen display if True, otherwise don't draw OSD");
183 #if defined(DYNAREC)
184     ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 2, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
185 #else
186     ConfigSetDefaultInt(g_CoreConfig, "R4300Emulator", 1, "Use Pure Interpreter if 0, Cached Interpreter if 1, or Dynamic Recompiler if 2 or more");
187 #endif
188     ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) ");
189     ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games");
190     ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation");
191     ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support");
192     ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state");
193     ConfigSetDefaultString(g_CoreConfig, "ScreenshotPath", "", "Path to directory where screenshots are saved. If this is blank, the default value of ${UserConfigPath}/screenshot will be used");
194     ConfigSetDefaultString(g_CoreConfig, "SaveStatePath", "", "Path to directory where emulator save states (snapshots) are saved. If this is blank, the default value of ${UserConfigPath}/save will be used");
195     ConfigSetDefaultString(g_CoreConfig, "SaveSRAMPath", "", "Path to directory where SRAM/EEPROM data (in-game saves) are stored. If this is blank, the default value of ${UserConfigPath}/save will be used");
196     ConfigSetDefaultString(g_CoreConfig, "SharedDataPath", "", "Path to a directory to search when looking for shared data files");
197
198     /* handle upgrades */
199     if (bUpgrade)
200     {
201         if (fConfigParamsVersion < 1.01f)
202         {  // added separate SaveSRAMPath parameter in v1.01
203             const char *pccSaveStatePath = ConfigGetParamString(g_CoreConfig, "SaveStatePath");
204             if (pccSaveStatePath != NULL)
205                 ConfigSetParameter(g_CoreConfig, "SaveSRAMPath", M64TYPE_STRING, pccSaveStatePath);
206         }
207     }
208
209     if (bSaveConfig)
210         ConfigSaveSection("Core");
211
212     /* set config parameters for keyboard and joystick commands */
213     return event_set_core_defaults();
214 }
215
216 void main_speeddown(int percent)
217 {
218     if (l_SpeedFactor - percent > 10)  /* 10% minimum speed */
219     {
220         l_SpeedFactor -= percent;
221         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
222         audio.setSpeedFactor(l_SpeedFactor);
223         StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
224     }
225 }
226
227 void main_speedup(int percent)
228 {
229     if (l_SpeedFactor + percent < 300) /* 300% maximum speed */
230     {
231         l_SpeedFactor += percent;
232         main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
233         audio.setSpeedFactor(l_SpeedFactor);
234         StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
235     }
236 }
237
238 static void main_speedset(int percent)
239 {
240     if (percent < 1 || percent > 1000)
241     {
242         DebugMessage(M64MSG_WARNING, "Invalid speed setting %i percent", percent);
243         return;
244     }
245     // disable fast-forward if it's enabled
246     main_set_fastforward(0);
247     // set speed
248     l_SpeedFactor = percent;
249     main_message(M64MSG_STATUS, OSD_BOTTOM_LEFT, "%s %d%%", "Playback speed:", l_SpeedFactor);
250     audio.setSpeedFactor(l_SpeedFactor);
251     StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
252 }
253
254 void main_set_fastforward(int enable)
255 {
256     static int ff_state = 0;
257     static int SavedSpeedFactor = 100;
258
259     if (enable && !ff_state)
260     {
261         ff_state = 1; /* activate fast-forward */
262         SavedSpeedFactor = l_SpeedFactor;
263         l_SpeedFactor = 250;
264         audio.setSpeedFactor(l_SpeedFactor);
265         StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
266         // set fast-forward indicator
267         l_msgFF = osd_new_message(OSD_TOP_RIGHT, "Fast Forward");
268         osd_message_set_static(l_msgFF);
269         osd_message_set_user_managed(l_msgFF);
270     }
271     else if (!enable && ff_state)
272     {
273         ff_state = 0; /* de-activate fast-forward */
274         l_SpeedFactor = SavedSpeedFactor;
275         audio.setSpeedFactor(l_SpeedFactor);
276         StateChanged(M64CORE_SPEED_FACTOR, l_SpeedFactor);
277         // remove message
278         osd_delete_message(l_msgFF);
279         l_msgFF = NULL;
280     }
281
282 }
283
284 static void main_set_speedlimiter(int enable)
285 {
286     l_MainSpeedLimit = enable ? 1 : 0;
287 }
288
289 static int main_is_paused(void)
290 {
291     return (g_EmulatorRunning && rompause);
292 }
293
294 void main_toggle_pause(void)
295 {
296     if (!g_EmulatorRunning)
297         return;
298
299     if (rompause)
300     {
301         DebugMessage(M64MSG_STATUS, "Emulation continued.");
302         if(l_msgPause)
303         {
304             osd_delete_message(l_msgPause);
305             l_msgPause = NULL;
306         }
307         StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
308     }
309     else
310     {
311         if(l_msgPause)
312             osd_delete_message(l_msgPause);
313
314         DebugMessage(M64MSG_STATUS, "Emulation paused.");
315         l_msgPause = osd_new_message(OSD_MIDDLE_CENTER, "Paused");
316         osd_message_set_static(l_msgPause);
317         osd_message_set_user_managed(l_msgPause);
318         StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
319     }
320
321     rompause = !rompause;
322     l_FrameAdvance = 0;
323 }
324
325 void main_advance_one(void)
326 {
327     l_FrameAdvance = 1;
328     rompause = 0;
329     StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
330 }
331
332 static void main_draw_volume_osd(void)
333 {
334     char msgString[64];
335     const char *volString;
336
337     // this calls into the audio plugin
338     volString = audio.volumeGetString();
339     if (volString == NULL)
340     {
341         strcpy(msgString, "Volume Not Supported.");
342     }
343     else
344     {
345         sprintf(msgString, "%s: %s", "Volume", volString);
346     }
347
348     // create a new message or update an existing one
349     if (l_msgVol != NULL)
350         osd_update_message(l_msgVol, "%s", msgString);
351     else {
352         l_msgVol = osd_new_message(OSD_MIDDLE_CENTER, "%s", msgString);
353         osd_message_set_user_managed(l_msgVol);
354     }
355 }
356
357 /* this function could be called as a result of a keypress, joystick/button movement,
358    LIRC command, or 'testshots' command-line option timer */
359 void main_take_next_screenshot(void)
360 {
361     l_TakeScreenshot = l_CurrentFrame + 1;
362 }
363
364 void main_state_set_slot(int slot)
365 {
366     if (slot < 0 || slot > 9)
367     {
368         DebugMessage(M64MSG_WARNING, "Invalid savestate slot '%i' in main_state_set_slot().  Using 0", slot);
369         slot = 0;
370     }
371
372     savestates_select_slot(slot);
373     StateChanged(M64CORE_SAVESTATE_SLOT, slot);
374 }
375
376 void main_state_inc_slot(void)
377 {
378     savestates_inc_slot();
379 }
380
381 static unsigned char StopRumble[64] = {0x23, 0x01, 0x03, 0xc0, 0x1b, 0x00, 0x00, 0x00,
382                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385                                        0, 0, 0, 0, 0, 0, 0, 0};
386
387 void main_state_load(const char *filename)
388 {
389     input.controllerCommand(0, StopRumble);
390     input.controllerCommand(1, StopRumble);
391     input.controllerCommand(2, StopRumble);
392     input.controllerCommand(3, StopRumble);
393
394     if (filename == NULL) // Save to slot
395         savestates_set_job(savestates_job_load, savestates_type_m64p, NULL);
396     else
397         savestates_set_job(savestates_job_load, savestates_type_unknown, filename);
398 }
399
400 void main_state_save(int format, const char *filename)
401 {
402     if (filename == NULL) // Save to slot
403         savestates_set_job(savestates_job_save, savestates_type_m64p, NULL);
404     else // Save to file
405         savestates_set_job(savestates_job_save, (savestates_type)format, filename);
406 }
407
408 m64p_error main_core_state_query(m64p_core_param param, int *rval)
409 {
410     switch (param)
411     {
412         case M64CORE_EMU_STATE:
413             if (!g_EmulatorRunning)
414                 *rval = M64EMU_STOPPED;
415             else if (rompause)
416                 *rval = M64EMU_PAUSED;
417             else
418                 *rval = M64EMU_RUNNING;
419             break;
420         case M64CORE_VIDEO_MODE:
421             if (!VidExt_VideoRunning())
422                 *rval = M64VIDEO_NONE;
423             else if (VidExt_InFullscreenMode())
424                 *rval = M64VIDEO_FULLSCREEN;
425             else
426                 *rval = M64VIDEO_WINDOWED;
427             break;
428         case M64CORE_SAVESTATE_SLOT:
429             *rval = savestates_get_slot();
430             break;
431         case M64CORE_SPEED_FACTOR:
432             *rval = l_SpeedFactor;
433             break;
434         case M64CORE_SPEED_LIMITER:
435             *rval = l_MainSpeedLimit;
436             break;
437         case M64CORE_VIDEO_SIZE:
438         {
439             int width, height;
440             if (!g_EmulatorRunning)
441                 return M64ERR_INVALID_STATE;
442             main_get_screen_size(&width, &height);
443             *rval = (width << 16) + height;
444             break;
445         }
446         case M64CORE_AUDIO_VOLUME:
447         {
448             if (!g_EmulatorRunning)
449                 return M64ERR_INVALID_STATE;    
450             return main_volume_get_level(rval);
451         }
452         case M64CORE_AUDIO_MUTE:
453             *rval = main_volume_get_muted();
454             break;
455         case M64CORE_INPUT_GAMESHARK:
456             *rval = event_gameshark_active();
457             break;
458         // these are only used for callbacks; they cannot be queried or set
459         case M64CORE_STATE_LOADCOMPLETE:
460         case M64CORE_STATE_SAVECOMPLETE:
461             return M64ERR_INPUT_INVALID;
462         default:
463             return M64ERR_INPUT_INVALID;
464     }
465
466     return M64ERR_SUCCESS;
467 }
468
469 m64p_error main_core_state_set(m64p_core_param param, int val)
470 {
471     switch (param)
472     {
473         case M64CORE_EMU_STATE:
474             if (!g_EmulatorRunning)
475                 return M64ERR_INVALID_STATE;
476             if (val == M64EMU_STOPPED)
477             {        
478                 /* this stop function is asynchronous.  The emulator may not terminate until later */
479                 main_stop();
480                 return M64ERR_SUCCESS;
481             }
482             else if (val == M64EMU_RUNNING)
483             {
484                 if (main_is_paused())
485                     main_toggle_pause();
486                 return M64ERR_SUCCESS;
487             }
488             else if (val == M64EMU_PAUSED)
489             {    
490                 if (!main_is_paused())
491                     main_toggle_pause();
492                 return M64ERR_SUCCESS;
493             }
494             return M64ERR_INPUT_INVALID;
495         case M64CORE_VIDEO_MODE:
496             if (!g_EmulatorRunning)
497                 return M64ERR_INVALID_STATE;
498             if (val == M64VIDEO_WINDOWED)
499             {
500                 if (VidExt_InFullscreenMode())
501                     gfx.changeWindow();
502                 return M64ERR_SUCCESS;
503             }
504             else if (val == M64VIDEO_FULLSCREEN)
505             {
506                 if (!VidExt_InFullscreenMode())
507                     gfx.changeWindow();
508                 return M64ERR_SUCCESS;
509             }
510             return M64ERR_INPUT_INVALID;
511         case M64CORE_SAVESTATE_SLOT:
512             if (val < 0 || val > 9)
513                 return M64ERR_INPUT_INVALID;
514             savestates_select_slot(val);
515             return M64ERR_SUCCESS;
516         case M64CORE_SPEED_FACTOR:
517             if (!g_EmulatorRunning)
518                 return M64ERR_INVALID_STATE;
519             main_speedset(val);
520             return M64ERR_SUCCESS;
521         case M64CORE_SPEED_LIMITER:
522             main_set_speedlimiter(val);
523             return M64ERR_SUCCESS;
524         case M64CORE_VIDEO_SIZE:
525         {
526             // the front-end app is telling us that the user has resized the video output frame, and so
527             // we should try to update the video plugin accordingly.  First, check state
528             int width, height;
529             if (!g_EmulatorRunning)
530                 return M64ERR_INVALID_STATE;
531             width = (val >> 16) & 0xffff;
532             height = val & 0xffff;
533             // then call the video plugin.  if the video plugin supports resizing, it will resize its viewport and call
534             // VidExt_ResizeWindow to update the window manager handling our opengl output window
535             gfx.resizeVideoOutput(width, height);
536             return M64ERR_SUCCESS;
537         }
538         case M64CORE_AUDIO_VOLUME:
539             if (!g_EmulatorRunning)
540                 return M64ERR_INVALID_STATE;
541             if (val < 0 || val > 100)
542                 return M64ERR_INPUT_INVALID;
543             return main_volume_set_level(val);
544         case M64CORE_AUDIO_MUTE:
545             if ((main_volume_get_muted() && !val) || (!main_volume_get_muted() && val))
546                 return main_volume_mute();
547             return M64ERR_SUCCESS;
548         case M64CORE_INPUT_GAMESHARK:
549             if (!g_EmulatorRunning)
550                 return M64ERR_INVALID_STATE;
551             event_set_gameshark(val);
552             return M64ERR_SUCCESS;
553         // these are only used for callbacks; they cannot be queried or set
554         case M64CORE_STATE_LOADCOMPLETE:
555         case M64CORE_STATE_SAVECOMPLETE:
556             return M64ERR_INPUT_INVALID;
557         default:
558             return M64ERR_INPUT_INVALID;
559     }
560 }
561
562 m64p_error main_get_screen_size(int *width, int *height)
563 {
564     gfx.readScreen(NULL, width, height, 0);
565     return M64ERR_SUCCESS;
566 }
567
568 m64p_error main_read_screen(void *pixels, int bFront)
569 {
570     int width_trash, height_trash;
571     gfx.readScreen(pixels, &width_trash, &height_trash, bFront);
572     return M64ERR_SUCCESS;
573 }
574
575 m64p_error main_volume_up(void)
576 {
577     int level = 0;
578     audio.volumeUp();
579     main_draw_volume_osd();
580     main_volume_get_level(&level);
581     StateChanged(M64CORE_AUDIO_VOLUME, level);
582     return M64ERR_SUCCESS;
583 }
584
585 m64p_error main_volume_down(void)
586 {
587     int level = 0;
588     audio.volumeDown();
589     main_draw_volume_osd();
590     main_volume_get_level(&level);
591     StateChanged(M64CORE_AUDIO_VOLUME, level);
592     return M64ERR_SUCCESS;
593 }
594
595 m64p_error main_volume_get_level(int *level)
596 {
597     *level = audio.volumeGetLevel();
598     return M64ERR_SUCCESS;
599 }
600
601 m64p_error main_volume_set_level(int level)
602 {
603     audio.volumeSetLevel(level);
604     main_draw_volume_osd();
605     level = audio.volumeGetLevel();
606     StateChanged(M64CORE_AUDIO_VOLUME, level);
607     return M64ERR_SUCCESS;
608 }
609
610 m64p_error main_volume_mute(void)
611 {
612     audio.volumeMute();
613     main_draw_volume_osd();
614     StateChanged(M64CORE_AUDIO_MUTE, main_volume_get_muted());
615     return M64ERR_SUCCESS;
616 }
617
618 int main_volume_get_muted(void)
619 {
620     return (audio.volumeGetLevel() == 0);
621 }
622
623 m64p_error main_reset(int do_hard_reset)
624 {
625     if (do_hard_reset)
626         reset_hard_job |= 1;
627     else
628         reset_soft();
629     return M64ERR_SUCCESS;
630 }
631
632 /*********************************************************************************************************
633 * global functions, callbacks from the r4300 core or from other plugins
634 */
635
636 static void video_plugin_render_callback(int bScreenRedrawn)
637 {
638     int bOSD = ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay");
639
640     // if the flag is set to take a screenshot, then grab it now
641     if (l_TakeScreenshot != 0)
642     {
643         // if the OSD is enabled, and the screen has not been recently redrawn, then we cannot take a screenshot now because
644         // it contains the OSD text.  Wait until the next redraw
645         if (!bOSD || bScreenRedrawn)
646         {
647             TakeScreenshot(l_TakeScreenshot - 1);  // current frame number +1 is in l_TakeScreenshot
648             l_TakeScreenshot = 0; // reset flag
649         }
650     }
651
652     // if the OSD is enabled, then draw it now
653     if (bOSD)
654     {
655         osd_render();
656     }
657 }
658
659 void new_frame(void)
660 {
661     if (g_FrameCallback != NULL)
662         (*g_FrameCallback)(l_CurrentFrame);
663
664     /* advance the current frame */
665     l_CurrentFrame++;
666
667     if (l_FrameAdvance) {
668         rompause = 1;
669         l_FrameAdvance = 0;
670         StateChanged(M64CORE_EMU_STATE, M64EMU_PAUSED);
671     }
672 }
673
674 void new_vi(void)
675 {
676     int Dif;
677     unsigned int CurrentFPSTime;
678     static unsigned int LastFPSTime = 0;
679     static unsigned int CounterTime = 0;
680     static unsigned int CalculatedTime ;
681     static int VI_Counter = 0;
682
683     double VILimitMilliseconds = 1000.0 / ROM_PARAMS.vilimit;
684     double AdjustedLimit = VILimitMilliseconds * 100.0 / l_SpeedFactor;  // adjust for selected emulator speed
685     int time;
686
687     start_section(IDLE_SECTION);
688     VI_Counter++;
689
690 #ifdef DBG
691     if(g_DebuggerActive) DebuggerCallback(DEBUG_UI_VI, 0);
692 #endif
693
694     if(LastFPSTime == 0)
695     {
696         LastFPSTime = CounterTime = SDL_GetTicks();
697         return;
698     }
699     CurrentFPSTime = SDL_GetTicks();
700     
701     Dif = CurrentFPSTime - LastFPSTime;
702     
703     if (Dif < AdjustedLimit) 
704     {
705         CalculatedTime = (unsigned int) (CounterTime + AdjustedLimit * VI_Counter);
706         time = (int)(CalculatedTime - CurrentFPSTime);
707         if (time > 0 && l_MainSpeedLimit)
708         {
709             DebugMessage(M64MSG_VERBOSE, "    new_vi(): Waiting %ims", time);
710             SDL_Delay(time);
711         }
712         CurrentFPSTime = CurrentFPSTime + time;
713     }
714
715     if (CurrentFPSTime - CounterTime >= 1000.0 ) 
716     {
717         CounterTime = SDL_GetTicks();
718         VI_Counter = 0 ;
719     }
720     
721     LastFPSTime = CurrentFPSTime ;
722     end_section(IDLE_SECTION);
723 }
724
725 /*********************************************************************************************************
726 * emulation thread - runs the core
727 */
728 m64p_error main_run(void)
729 {
730     /* take the r4300 emulator mode from the config file at this point and cache it in a global variable */
731     r4300emu = ConfigGetParamInt(g_CoreConfig, "R4300Emulator");
732
733     /* set some other core parameters based on the config file values */
734     savestates_set_autoinc_slot(ConfigGetParamBool(g_CoreConfig, "AutoStateSlotIncrement"));
735     savestates_select_slot(ConfigGetParamInt(g_CoreConfig, "CurrentStateSlot"));
736     no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump");
737
738     // initialize memory, and do byte-swapping if it's not been done yet
739     if (g_MemHasBeenBSwapped == 0)
740     {
741         init_memory(1);
742         g_MemHasBeenBSwapped = 1;
743     }
744     else
745     {
746         init_memory(0);
747     }
748     // Attach rom to plugins
749     if (!gfx.romOpen())
750     {
751         free_memory(); return M64ERR_PLUGIN_FAIL;
752     }
753     if (!audio.romOpen())
754     {
755         gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
756     }
757     if (!input.romOpen())
758     {
759         audio.romClosed(); gfx.romClosed(); free_memory(); return M64ERR_PLUGIN_FAIL;
760     }
761
762         
763     /* set up the SDL key repeat and event filter to catch keyboard/joystick commands for the core */
764     event_initialize();
765
766     /* initialize the on-screen display */
767     if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
768     {
769         // init on-screen display
770         int width = 640, height = 480;
771         gfx.readScreen(NULL, &width, &height, 0); // read screen to get width and height
772         osd_init(width, height);
773     }
774
775     // setup rendering callback from video plugin to the core, for screenshots and On-Screen-Display
776     gfx.setRenderingCallback(video_plugin_render_callback);
777
778 #ifdef WITH_LIRC
779     lircStart();
780 #endif // WITH_LIRC
781
782 #ifdef DBG
783     if (ConfigGetParamBool(g_CoreConfig, "EnableDebugger"))
784         init_debugger();
785 #endif
786     /* Startup message on the OSD */
787     osd_new_message(OSD_MIDDLE_CENTER, "Mupen64Plus Started...");
788     g_EmulatorRunning = 1;
789     StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
790     /* call r4300 CPU core and run the game */
791     r4300_reset_hard();
792     r4300_reset_soft();
793     r4300_execute();
794
795     /* now begin to shut down */
796 #ifdef WITH_LIRC
797     lircStop();
798 #endif // WITH_LIRC
799
800 #ifdef DBG
801     if (g_DebuggerActive)
802         destroy_debugger();
803 #endif
804
805     if (ConfigGetParamBool(g_CoreConfig, "OnScreenDisplay"))
806     {
807         osd_exit();
808     }
809
810     rsp.romClosed();
811     input.romClosed();
812     audio.romClosed();
813     gfx.romClosed();
814     free_memory();
815
816     // clean up
817     g_EmulatorRunning = 0;
818     StateChanged(M64CORE_EMU_STATE, M64EMU_STOPPED);
819
820     return M64ERR_SUCCESS;
821 }
822
823 void main_stop(void)
824 {
825     /* note: this operation is asynchronous.  It may be called from a thread other than the
826        main emulator thread, and may return before the emulator is completely stopped */
827     if (!g_EmulatorRunning)
828         return;
829
830     DebugMessage(M64MSG_STATUS, "Stopping emulation.");
831     if(l_msgPause)
832     {
833         osd_delete_message(l_msgPause);
834         l_msgPause = NULL;
835     }
836     if(l_msgFF)
837     {
838         osd_delete_message(l_msgFF);
839         l_msgFF = NULL;
840     }
841     if(l_msgVol)
842     {
843         osd_delete_message(l_msgVol);
844         l_msgVol = NULL;
845     }
846     if (rompause)
847     {
848         rompause = 0;
849         StateChanged(M64CORE_EMU_STATE, M64EMU_RUNNING);
850     }
851     stop = 1;
852 #ifdef DBG
853     if(g_DebuggerActive)
854     {
855         debugger_step();
856     }
857 #endif        
858 }
859
860 /*********************************************************************************************************
861 * main function
862 */
863 int main(int argc, char *argv[])
864 {
865     return 1;
866 }
867