1 /***********************************************************************************
2   Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 
4   (c) Copyright 1996 - 2002  Gary Henderson (gary.henderson@ntlworld.com),
5                              Jerremy Koot (jkoot@snes9x.com)
6 
7   (c) Copyright 2002 - 2004  Matthew Kendora
8 
9   (c) Copyright 2002 - 2005  Peter Bortas (peter@bortas.org)
10 
11   (c) Copyright 2004 - 2005  Joel Yliluoma (http://iki.fi/bisqwit/)
12 
13   (c) Copyright 2001 - 2006  John Weidman (jweidman@slip.net)
14 
15   (c) Copyright 2002 - 2006  funkyass (funkyass@spam.shaw.ca),
16                              Kris Bleakley (codeviolation@hotmail.com)
17 
18   (c) Copyright 2002 - 2010  Brad Jorsch (anomie@users.sourceforge.net),
19                              Nach (n-a-c-h@users.sourceforge.net),
20 
21   (c) Copyright 2002 - 2011  zones (kasumitokoduck@yahoo.com)
22 
23   (c) Copyright 2006 - 2007  nitsuja
24 
25   (c) Copyright 2009 - 2016  BearOso,
26                              OV2
27 
28 
29   BS-X C emulator code
30   (c) Copyright 2005 - 2006  Dreamer Nom,
31                              zones
32 
33   C4 x86 assembler and some C emulation code
34   (c) Copyright 2000 - 2003  _Demo_ (_demo_@zsnes.com),
35                              Nach,
36                              zsKnight (zsknight@zsnes.com)
37 
38   C4 C++ code
39   (c) Copyright 2003 - 2006  Brad Jorsch,
40                              Nach
41 
42   DSP-1 emulator code
43   (c) Copyright 1998 - 2006  _Demo_,
44                              Andreas Naive (andreasnaive@gmail.com),
45                              Gary Henderson,
46                              Ivar (ivar@snes9x.com),
47                              John Weidman,
48                              Kris Bleakley,
49                              Matthew Kendora,
50                              Nach,
51                              neviksti (neviksti@hotmail.com)
52 
53   DSP-2 emulator code
54   (c) Copyright 2003         John Weidman,
55                              Kris Bleakley,
56                              Lord Nightmare (lord_nightmare@users.sourceforge.net),
57                              Matthew Kendora,
58                              neviksti
59 
60   DSP-3 emulator code
61   (c) Copyright 2003 - 2006  John Weidman,
62                              Kris Bleakley,
63                              Lancer,
64                              z80 gaiden
65 
66   DSP-4 emulator code
67   (c) Copyright 2004 - 2006  Dreamer Nom,
68                              John Weidman,
69                              Kris Bleakley,
70                              Nach,
71                              z80 gaiden
72 
73   OBC1 emulator code
74   (c) Copyright 2001 - 2004  zsKnight,
75                              pagefault (pagefault@zsnes.com),
76                              Kris Bleakley
77                              Ported from x86 assembler to C by sanmaiwashi
78 
79   SPC7110 and RTC C++ emulator code used in 1.39-1.51
80   (c) Copyright 2002         Matthew Kendora with research by
81                              zsKnight,
82                              John Weidman,
83                              Dark Force
84 
85   SPC7110 and RTC C++ emulator code used in 1.52+
86   (c) Copyright 2009         byuu,
87                              neviksti
88 
89   S-DD1 C emulator code
90   (c) Copyright 2003         Brad Jorsch with research by
91                              Andreas Naive,
92                              John Weidman
93 
94   S-RTC C emulator code
95   (c) Copyright 2001 - 2006  byuu,
96                              John Weidman
97 
98   ST010 C++ emulator code
99   (c) Copyright 2003         Feather,
100                              John Weidman,
101                              Kris Bleakley,
102                              Matthew Kendora
103 
104   Super FX x86 assembler emulator code
105   (c) Copyright 1998 - 2003  _Demo_,
106                              pagefault,
107                              zsKnight
108 
109   Super FX C emulator code
110   (c) Copyright 1997 - 1999  Ivar,
111                              Gary Henderson,
112                              John Weidman
113 
114   Sound emulator code used in 1.5-1.51
115   (c) Copyright 1998 - 2003  Brad Martin
116   (c) Copyright 1998 - 2006  Charles Bilyue'
117 
118   Sound emulator code used in 1.52+
119   (c) Copyright 2004 - 2007  Shay Green (gblargg@gmail.com)
120 
121   S-SMP emulator code used in 1.54+
122   (c) Copyright 2016         byuu
123 
124   SH assembler code partly based on x86 assembler code
125   (c) Copyright 2002 - 2004  Marcus Comstedt (marcus@mc.pp.se)
126 
127   2xSaI filter
128   (c) Copyright 1999 - 2001  Derek Liauw Kie Fa
129 
130   HQ2x, HQ3x, HQ4x filters
131   (c) Copyright 2003         Maxim Stepin (maxim@hiend3d.com)
132 
133   NTSC filter
134   (c) Copyright 2006 - 2007  Shay Green
135 
136   GTK+ GUI code
137   (c) Copyright 2004 - 2016  BearOso
138 
139   Win32 GUI code
140   (c) Copyright 2003 - 2006  blip,
141                              funkyass,
142                              Matthew Kendora,
143                              Nach,
144                              nitsuja
145   (c) Copyright 2009 - 2016  OV2
146 
147   Mac OS GUI code
148   (c) Copyright 1998 - 2001  John Stiles
149   (c) Copyright 2001 - 2011  zones
150 
151 
152   Specific ports contains the works of other authors. See headers in
153   individual files.
154 
155 
156   Snes9x homepage: http://www.snes9x.com/
157 
158   Permission to use, copy, modify and/or distribute Snes9x in both binary
159   and source form, for non-commercial purposes, is hereby granted without
160   fee, providing that this license information and copyright notice appear
161   with all copies and any derived work.
162 
163   This software is provided 'as-is', without any express or implied
164   warranty. In no event shall the authors be held liable for any damages
165   arising from the use of this software or it's derivatives.
166 
167   Snes9x is freeware for PERSONAL USE only. Commercial users should
168   seek permission of the copyright holders first. Commercial use includes,
169   but is not limited to, charging money for Snes9x or software derived from
170   Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171   using Snes9x as a promotion for your commercial product.
172 
173   The copyright holders request that bug fixes and improvements to the code
174   should be forwarded to them so everyone can benefit from the modifications
175   in future versions.
176 
177   Super NES and Super Nintendo Entertainment System are trademarks of
178   Nintendo Co., Limited and its subsidiary companies.
179  ***********************************************************************************/
180 
181 /***********************************************************************************
182   SNES9X for Mac OS (c) Copyright John Stiles
183 
184   Snes9x for Mac OS X
185 
186   (c) Copyright 2001 - 2011  zones
187   (c) Copyright 2002 - 2005  107
188   (c) Copyright 2002         PB1400c
189   (c) Copyright 2004         Alexander and Sander
190   (c) Copyright 2004 - 2005  Steven Seeger
191   (c) Copyright 2005         Ryan Vogt
192  ***********************************************************************************/
193 
194 
195 #include "snes9x.h"
196 #include "memmap.h"
197 #include "apu.h"
198 #include "snapshot.h"
199 #include "cheats.h"
200 #include "movie.h"
201 #include "display.h"
202 
203 #include <wchar.h>
204 
205 #include "mac-prefix.h"
206 #include "mac-audio.h"
207 #include "mac-cart.h"
208 #include "mac-cheatfinder.h"
209 #include "mac-dialog.h"
210 #include "mac-file.h"
211 #include "mac-multicart.h"
212 #include "mac-os.h"
213 #include "mac-quicktime.h"
214 #include "mac-screenshot.h"
215 #include "mac-stringtools.h"
216 #include "mac-snes9x.h"
217 
218 extern wchar_t  macRecordWChar[MOVIE_MAX_METADATA];
219 
220 
SNES9X_Go(void)221 void SNES9X_Go (void)
222 {
223 	if (cartOpen)
224 		running = true;
225 }
226 
SNES9X_OpenCart(FSRef * inRef)227 bool8 SNES9X_OpenCart (FSRef *inRef)
228 {
229 	OSStatus	err;
230 	FSRef		cartRef;
231 	char		filename[PATH_MAX + 1];
232 
233 	DeinitGameWindow();
234 
235 	if (cartOpen)
236 	{
237 		SNES9X_SaveSRAM();
238 		S9xResetSaveTimer(false);
239 		S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
240 	}
241 
242 	ResetCheatFinder();
243 
244 	if (!inRef)
245 	{
246 		if (!NavOpenROMImage(&cartRef))
247 		{
248 			cartOpen = false;
249 			return (false);
250 		}
251 	}
252 	else
253 		cartRef = *inRef;
254 
255 	spcFileCount = pngFileCount = 0;
256 
257 	CheckSaveFolder(&cartRef);
258 
259 	Settings.ForceLoROM          = (romDetect        == kLoROMForce       );
260 	Settings.ForceHiROM          = (romDetect        == kHiROMForce       );
261 	Settings.ForceHeader         = (headerDetect     == kHeaderForce      );
262 	Settings.ForceNoHeader       = (headerDetect     == kNoHeaderForce    );
263 	Settings.ForceInterleaved    = (interleaveDetect == kInterleaveForce  );
264 	Settings.ForceInterleaved2   = (interleaveDetect == kInterleave2Force );
265 	Settings.ForceInterleaveGD24 = (interleaveDetect == kInterleaveGD24   );
266 	Settings.ForceNotInterleaved = (interleaveDetect == kNoInterleaveForce);
267 	Settings.ForcePAL            = (videoDetect      == kPALForce         );
268 	Settings.ForceNTSC           = (videoDetect      == kNTSCForce        );
269 
270 	GFX.InfoString = NULL;
271 	GFX.InfoStringTimeout = 0;
272 
273 	S9xResetSaveTimer(true);
274 
275 	err = FSRefMakePath(&cartRef, (unsigned char *) filename, PATH_MAX);
276 
277 	SNES9X_InitSound();
278 
279 	if (Memory.LoadROM(filename))
280 	{
281 		cartOpen = true;
282 
283 		SNES9X_LoadSRAM();
284 
285 		ChangeTypeAndCreator(filename, 'CART', '~9X~');
286 
287 		AddRecentItem(&cartRef);
288 		BuildRecentMenu();
289 
290 		ApplyNSRTHeaderControllers();
291 
292 		for (int a = 0; a < MAC_MAX_PLAYERS; a++)
293 			for (int b = 0; b < 12; b++)
294 				autofireRec[a].nextTime[b] = 0;
295 
296 		return (true);
297 	}
298 	else
299 	{
300 		cartOpen = false;
301 		return (false);
302 	}
303 }
304 
SNES9X_OpenMultiCart(void)305 bool8 SNES9X_OpenMultiCart (void)
306 {
307 	Boolean	r;
308 	char	cart[2][PATH_MAX + 1];
309 
310 	DeinitGameWindow();
311 
312 	if (cartOpen)
313 	{
314 		SNES9X_SaveSRAM();
315 		S9xResetSaveTimer(false);
316 		S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
317 	}
318 
319 	ResetCheatFinder();
320 
321 	if (!MultiCartDialog())
322 	{
323 		cartOpen = false;
324 		return (false);
325 	}
326 
327 	spcFileCount = pngFileCount = 0;
328 
329 	Settings.ForceHeader   = (headerDetect     == kHeaderForce  );
330 	Settings.ForceNoHeader = (headerDetect     == kNoHeaderForce);
331 	Settings.ForcePAL      = (videoDetect      == kPALForce     );
332 	Settings.ForceNTSC     = (videoDetect      == kNTSCForce    );
333 
334 	GFX.InfoString = NULL;
335 	GFX.InfoStringTimeout = 0;
336 
337 	S9xResetSaveTimer(true);
338 
339 	for (int i = 0; i < 2; i++)
340 	{
341 		cart[i][0] = 0;
342 		if (multiCartPath[i])
343 			r = CFStringGetCString(multiCartPath[i], cart[i], PATH_MAX, kCFStringEncodingUTF8);
344 	}
345 
346 	SNES9X_InitSound();
347 
348 	if (Memory.LoadMultiCart(cart[0], cart[1]))
349 	{
350 		cartOpen = true;
351 
352 		SNES9X_LoadSRAM();
353 
354 		for (int i = 0; i < 2; i++)
355 		{
356 			if (cart[i][0])
357 				ChangeTypeAndCreator(cart[i], 'CART', '~9X~');
358 		}
359 
360 		ApplyNSRTHeaderControllers();
361 
362 		for (int a = 0; a < MAC_MAX_PLAYERS; a++)
363 			for (int b = 0; b < 12; b++)
364 				autofireRec[a].nextTime[b] = 0;
365 
366 		return (true);
367 	}
368 	else
369 	{
370 		cartOpen = false;
371 		return (false);
372 	}
373 }
374 
SNES9X_LoadSRAM(void)375 void SNES9X_LoadSRAM (void)
376 {
377 	if (cartOpen)
378 		Memory.LoadSRAM(S9xGetFilename(".srm", SRAM_DIR));
379 }
380 
SNES9X_SaveSRAM(void)381 void SNES9X_SaveSRAM (void)
382 {
383 	const char	*sramFilename;
384 
385 	if (cartOpen)
386 	{
387 		sramFilename = S9xGetFilename(".srm", SRAM_DIR);
388 		Memory.SaveSRAM(sramFilename);
389 		ChangeTypeAndCreator(sramFilename, 'SRAM', '~9X~');
390 	}
391 }
392 
SNES9X_Reset(void)393 void SNES9X_Reset (void)
394 {
395 	if (cartOpen)
396 	{
397 		SNES9X_SaveSRAM();
398 		S9xReset();
399 		SNES9X_LoadSRAM();
400 	}
401 }
402 
SNES9X_SoftReset(void)403 void SNES9X_SoftReset (void)
404 {
405 	if (cartOpen)
406 	{
407 		SNES9X_SaveSRAM();
408 		S9xSoftReset();
409 		SNES9X_LoadSRAM();
410 	}
411 }
412 
SNES9X_Freeze(void)413 bool8 SNES9X_Freeze (void)
414 {
415 	OSStatus	err;
416 	FSRef		ref;
417 	int			which;
418     const char	*filename;
419 
420 	if (cartOpen)
421 	{
422 		MacStopSound();
423 
424 		which = PromptFreezeDefrost(true);
425 
426 		if (which >= 0)
427 		{
428 			filename = S9xGetFreezeFilename(which);
429 
430 			err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
431 			if (!err)
432 				FSDeleteObject(&ref);
433 
434 			S9xFreezeGame(filename);
435 			ChangeTypeAndCreator(filename, 'SAVE', '~9X~');
436 			err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
437 			WriteThumbnailToResourceFork(&ref, 128, 120);
438 
439 			SNES9X_Go();
440 
441 			MacStartSound();
442 			return (true);
443 		}
444 		else
445 		{
446 			MacStartSound();
447 			return (false);
448 		}
449 	}
450 	else
451 		return (false);
452 }
453 
SNES9X_Defrost(void)454 bool8 SNES9X_Defrost (void)
455 {
456 	int			which;
457 	const char	*filename;
458 
459 	if (cartOpen)
460 	{
461 		MacStopSound();
462 
463 		which = PromptFreezeDefrost(false);
464 
465 		if (which >= 0)
466 		{
467 			filename = S9xGetFreezeFilename(which);
468 			S9xUnfreezeGame(filename);
469 
470 			SNES9X_Go();
471 
472 			MacStartSound();
473 			return (true);
474 		}
475 		else
476 		{
477 			MacStartSound();
478 			return (false);
479 		}
480 	}
481 	else
482 		return (false);
483 }
484 
SNES9X_FreezeTo(void)485 bool8 SNES9X_FreezeTo (void)
486 {
487 	OSStatus	err;
488 	FSRef		ref;
489     char		filename[PATH_MAX + 1];
490 
491 	if (cartOpen)
492 	{
493 		if (NavFreezeTo(filename))
494 		{
495 			err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
496 			if (!err)
497 				FSDeleteObject(&ref);
498 
499 			S9xFreezeGame(filename);
500 			ChangeTypeAndCreator(filename, 'SAVE', '~9X~');
501 			err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
502 			WriteThumbnailToResourceFork(&ref, 128, 120);
503 
504 			return (true);
505 		}
506 	}
507 
508 	return (false);
509 }
510 
SNES9X_DefrostFrom(void)511 bool8 SNES9X_DefrostFrom (void)
512 {
513 	char	filename[PATH_MAX + 1];
514 
515 	if (cartOpen)
516 	{
517 		if (NavDefrostFrom(filename))
518 		{
519 			S9xUnfreezeGame(filename);
520 
521 			SNES9X_Go();
522 
523 			return (true);
524 		}
525 	}
526 
527 	return (false);
528 }
529 
SNES9X_RecordMovie(void)530 bool8 SNES9X_RecordMovie (void)
531 {
532 	OSStatus	err;
533 	FSRef		ref;
534     char		filename[PATH_MAX + 1];
535 
536 	if (cartOpen)
537 	{
538 		if (NavRecordMovieTo(filename))
539 		{
540 			err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
541 			if (!err)
542 				FSDeleteObject(&ref);
543 
544 			int		r;
545 			uint8   opt = 0, mask = 0;
546 
547 			for (int i = 0; i <= 4; i++)
548 				if (macRecordFlag & (1 << i))
549 					mask |= (1 << i);
550 
551 			if (macRecordFlag & (1 << 5))
552 				opt |= MOVIE_OPT_FROM_RESET;
553 			else
554 				opt |= MOVIE_OPT_FROM_SNAPSHOT;
555 
556 			r = S9xMovieCreate(filename, mask, opt, macRecordWChar, wcslen(macRecordWChar));
557 			if (r == SUCCESS)
558 			{
559 				ChangeTypeAndCreator(filename, 'SMOV', '~9X~');
560 
561 				if ((macRecordFlag & (1 << 5)) == 0)
562 				{
563 					err = FSPathMakeRef((unsigned char *) filename, &ref, NULL);
564 					WriteThumbnailToResourceFork(&ref, 128, 120);
565 				}
566 
567 				SNES9X_Go();
568 
569 				return (true);
570 			}
571 		}
572 	}
573 
574 	return (false);
575 }
576 
SNES9X_PlayMovie(void)577 bool8 SNES9X_PlayMovie (void)
578 {
579 	char	filename[PATH_MAX + 1];
580 
581 	if (cartOpen)
582 	{
583 		if (NavPlayMovieFrom(filename))
584 		{
585 			int r;
586 
587 			r = S9xMovieOpen(filename, macPlayFlag & 1);
588 			if (r == SUCCESS)
589 			{
590 				SNES9X_Go();
591 
592 				return (true);
593 			}
594 		}
595 	}
596 
597 	return (false);
598 }
599 
SNES9X_QTMovieRecord(void)600 bool8 SNES9X_QTMovieRecord (void)
601 {
602     char	filename[PATH_MAX + 1];
603 
604 	if (cartOpen)
605 	{
606 		if (NavQTMovieRecordTo(filename))
607 		{
608 			MacQTStartRecording(filename);
609 			macQTRecord = true;
610 			SNES9X_Go();
611 
612 			return (true);
613 		}
614 	}
615 
616 	macQTRecord = false;
617 
618 	return (false);
619 }
620 
SNES9X_Quit(void)621 void SNES9X_Quit (void)
622 {
623 	DeinitGameWindow();
624 
625 	if (cartOpen)
626 	{
627 		SNES9X_SaveSRAM();
628 		S9xResetSaveTimer(false);
629 		S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR));
630 	}
631 
632 	finished = true;
633 }
634 
SNES9X_InitSound(void)635 void SNES9X_InitSound (void)
636 {
637 	S9xInitSound(macSoundBuffer_ms, macSoundLagEnable ? macSoundBuffer_ms / 2 : 0);
638 }
639