1 #pragma once
2 
3 #include <algorithm>
4 #include "stdafx.h"
5 #include "MessageManager.h"
6 #include "GameClient.h"
7 #include "KeyManager.h"
8 #include "../Utilities/SimpleLock.h"
9 
10 class Console;
11 
12 enum EmulationFlags : uint64_t
13 {
14 	Paused = 0x01,
15 	ShowFPS = 0x02,
16 	VerticalSync = 0x04,
17 	AllowInvalidInput = 0x08,
18 	RemoveSpriteLimit = 0x10,
19 	UseHdPacks = 0x20,
20 	HasFourScore = 0x40,
21 
22 	DisableDynamicSampleRate = 0x80,
23 
24 	PauseOnMovieEnd = 0x0100,
25 
26 	DeveloperMode = 0x0200,
27 
28 	AllowBackgroundInput = 0x0400,
29 	ReduceSoundInBackground = 0x0800,
30 	MuteSoundInBackground = 0x1000,
31 
32 	FdsFastForwardOnLoad = 0x2000,
33 	FdsAutoLoadDisk = 0x4000,
34 	Mmc3IrqAltBehavior = 0x8000,
35 
36 	SwapDutyCycles = 0x10000,
37 
38 	AutoConfigureInput = 0x40000,
39 
40 	ShowLagCounter = 0x80000,
41 
42 	SilenceTriangleHighFreq = 0x100000,
43 	ReduceDmcPopping = 0x200000,
44 
45 	DisableBackground = 0x400000,
46 	DisableSprites = 0x800000,
47 	ForceBackgroundFirstColumn = 0x1000000,
48 	ForceSpritesFirstColumn = 0x2000000,
49 	DisablePpu2004Reads = 0x4000000,
50 	DisableNoiseModeFlag = 0x8000000,
51 	DisablePaletteRead = 0x10000000,
52 	DisableOamAddrBug = 0x20000000,
53 	DisablePpuReset = 0x40000000,
54 	EnableOamDecay = 0x80000000,
55 
56 	UseNes101Hvc101Behavior = 0x100000000,
57 	ShowFrameCounter = 0x200000000,
58 	ShowGameTimer = 0x400000000,
59 
60 	FdsAutoInsertDisk = 0x800000000,
61 
62 	Rewind =  0x1000000000,
63 	Turbo = 0x2000000000,
64 	InBackground = 0x4000000000,
65 	NsfPlayerEnabled = 0x8000000000,
66 
67 	DisplayMovieIcons = 0x10000000000,
68 	HidePauseOverlay = 0x20000000000,
69 
70 	UseCustomVsPalette = 0x40000000000,
71 
72 	AdaptiveSpriteLimit = 0x80000000000,
73 
74 	DisableGameSelectionScreen = 0x200000000000,
75 
76 	ConfirmExitResetPower = 0x400000000000,
77 
78 	NsfRepeat = 0x800000000000,
79 	NsfShuffle = 0x1000000000000,
80 
81 	IntegerFpsMode = 0x2000000000000,
82 
83 	DebuggerWindowEnabled = 0x4000000000000,
84 	BreakOnCrash = 0x8000000000000,
85 
86 	AllowMismatchingSaveState = 0x10000000000000,
87 
88 	RandomizeMapperPowerOnState = 0x20000000000000,
89 
90 	UseHighResolutionTimer = 0x40000000000000,
91 	DisplayDebugInfo = 0x80000000000000,
92 
93 	ReduceSoundInFastForward = 0x100000000000000,
94 
95 	VsDualMuteMaster = 0x200000000000000,
96 	VsDualMuteSlave = 0x400000000000000,
97 
98 	ForceMaxSpeed = 0x4000000000000000,
99 	ConsoleMode = 0x8000000000000000,
100 };
101 
102 enum class AudioChannel
103 {
104 	Square1 = 0,
105 	Square2 = 1,
106 	Triangle = 2,
107 	Noise = 3,
108 	DMC = 4,
109 	FDS = 5,
110 	MMC5 = 6,
111 	VRC6 = 7,
112 	VRC7 = 8,
113 	Namco163 = 9,
114 	Sunsoft5B = 10
115 };
116 
117 enum class EqualizerFilterType
118 {
119 	None = 0,
120 	Butterworth = 1,
121 	Chebyshev1 = 2,
122 	Chebyshev2 = 3
123 };
124 
125 enum class ScaleFilterType
126 {
127 	xBRZ = 0,
128 	HQX = 1,
129 	Scale2x = 2,
130 	_2xSai = 3,
131 	Super2xSai = 4,
132 	SuperEagle = 5,
133 	Prescale = 6,
134 };
135 
136 enum class VideoFilterType
137 {
138 	None = 0,
139 	NTSC = 1,
140 	BisqwitNtscQuarterRes = 2,
141 	BisqwitNtscHalfRes = 3,
142 	BisqwitNtsc = 4,
143 	xBRZ2x = 5,
144 	xBRZ3x = 6,
145 	xBRZ4x = 7,
146 	xBRZ5x = 8,
147 	xBRZ6x = 9,
148 	HQ2x = 10,
149 	HQ3x = 11,
150 	HQ4x = 12,
151 	Scale2x = 13,
152 	Scale3x = 14,
153 	Scale4x = 15,
154 	_2xSai = 16,
155 	Super2xSai = 17,
156 	SuperEagle = 18,
157 	Prescale2x = 19,
158 	Prescale3x = 20,
159 	Prescale4x = 21,
160 	Prescale6x = 22,
161 	Prescale8x = 23,
162 	Prescale10x = 24,
163 	Raw = 25,
164 	HdPack = 999
165 };
166 
167 enum class VideoResizeFilter
168 {
169 	NearestNeighbor = 0,
170 	Bilinear = 1
171 };
172 
173 enum class VideoAspectRatio
174 {
175 	NoStretching = 0,
176 	Auto = 1,
177 	NTSC = 2,
178 	PAL = 3,
179 	Standard = 4,
180 	Widescreen = 5,
181 	Custom = 6
182 };
183 
184 struct OverscanDimensions
185 {
186 	uint32_t Left = 0;
187 	uint32_t Right = 0;
188 	uint32_t Top = 0;
189 	uint32_t Bottom = 0;
190 
GetPixelCountOverscanDimensions191 	uint32_t GetPixelCount()
192 	{
193 		return GetScreenWidth() * GetScreenHeight();
194 	}
195 
GetScreenWidthOverscanDimensions196 	uint32_t GetScreenWidth()
197 	{
198 		return 256 - Left - Right;
199 	}
200 
GetScreenHeightOverscanDimensions201 	uint32_t GetScreenHeight()
202 	{
203 		return 240 - Top - Bottom;
204 	}
205 };
206 
207 struct PictureSettings
208 {
209 	double Brightness = 0;
210 	double Contrast = 0;
211 	double Saturation = 0;
212 	double Hue = 0;
213 	double ScanlineIntensity = 0;
214 };
215 
216 struct NtscFilterSettings
217 {
218 	double Sharpness = 0;
219 	double Gamma = 0;
220 	double Resolution = 0;
221 	double Artifacts = 0;
222 	double Fringing = 0;
223 	double Bleed = 0;
224 	bool MergeFields = false;
225 	bool VerticalBlend = false;
226 	bool KeepVerticalResolution = false;
227 
228 	double YFilterLength = 0;
229 	double IFilterLength = 0;
230 	double QFilterLength = 0;
231 };
232 
233 enum class RamPowerOnState
234 {
235 	AllZeros = 0,
236 	AllOnes = 1,
237 	Random = 2
238 };
239 
240 extern const vector<string> NesModelNames;
241 enum class NesModel
242 {
243 	Auto = 0,
244 	NTSC = 1,
245 	PAL = 2,
246 	Dendy = 3,
247 };
248 
249 extern const vector<string> ConsoleTypeNames;
250 enum class ConsoleType
251 {
252 	Nes = 0,
253 	Famicom = 1
254 };
255 
256 extern const vector<string> ControllerTypeNames;
257 enum class ControllerType
258 {
259 	None = 0,
260 	StandardController = 1,
261 	Zapper = 2,
262 	ArkanoidController = 3,
263 	SnesController = 4,
264 	PowerPad = 5,
265 	SnesMouse = 6,
266 	SuborMouse = 7,
267 	VsZapper = 8
268 };
269 
270 extern const vector<string> ExpansionPortDeviceNames;
271 enum class ExpansionPortDevice
272 {
273 	None = 0,
274 	Zapper = 1,
275 	FourPlayerAdapter = 2,
276 	ArkanoidController = 3,
277 	OekaKidsTablet = 4,
278 	FamilyTrainerMat = 5,
279 	KonamiHyperShot = 6,
280 	FamilyBasicKeyboard = 7,
281 	PartyTap = 8,
282 	Pachinko = 9,
283 	ExcitingBoxing = 10,
284 	JissenMahjong = 11,
285 	SuborKeyboard = 12,
286 	BarcodeBattler = 13,
287 	HoriTrack = 14,
288 	BandaiHyperShot = 15,
289 	AsciiTurboFile = 16,
290 	BattleBox = 17,
291 };
292 
293 enum class VsInputType
294 {
295 	Default = 0,
296 	SwapControllers = 1,
297 	SwapAB = 2
298 };
299 
300 struct KeyMapping
301 {
302 	uint32_t A = 0;
303 	uint32_t B = 0;
304 	uint32_t Up = 0;
305 	uint32_t Down = 0;
306 	uint32_t Left = 0;
307 	uint32_t Right = 0;
308 	uint32_t Start = 0;
309 	uint32_t Select = 0;
310 	uint32_t TurboA = 0;
311 	uint32_t TurboB = 0;
312 	uint32_t TurboStart = 0;
313 	uint32_t TurboSelect = 0;
314 	uint32_t Microphone = 0;
315 	uint32_t LButton = 0;
316 	uint32_t RButton = 0;
317 
318 	uint32_t PowerPadButtons[12] = {};
319 	uint32_t FamilyBasicKeyboardButtons[72] = {};
320 	uint32_t PartyTapButtons[6] = {};
321 	uint32_t PachinkoButtons[2] = {};
322 	uint32_t ExcitingBoxingButtons[8] = {};
323 	uint32_t JissenMahjongButtons[21] = {};
324 	uint32_t SuborKeyboardButtons[99] = {};
325 	uint32_t BandaiMicrophoneButtons[3] = {};
326 
HasKeySetKeyMapping327 	bool HasKeySet()
328 	{
329 		if(A || B || Up || Down || Left || Right || Start || Select || TurboA || TurboB || TurboStart || TurboSelect || Microphone || LButton || RButton) {
330 			return true;
331 		}
332 
333 		bool hasKeyBinding = false;
334 		hasKeyBinding |= HasKeyBinding(PowerPadButtons, sizeof(PowerPadButtons) / sizeof(PowerPadButtons[0]));
335 		hasKeyBinding |= HasKeyBinding(FamilyBasicKeyboardButtons, sizeof(FamilyBasicKeyboardButtons) / sizeof(FamilyBasicKeyboardButtons[0]));
336 		hasKeyBinding |= HasKeyBinding(PartyTapButtons, sizeof(PartyTapButtons) / sizeof(PartyTapButtons[0]));
337 		hasKeyBinding |= HasKeyBinding(PachinkoButtons, sizeof(PachinkoButtons) / sizeof(PachinkoButtons[0]));
338 		hasKeyBinding |= HasKeyBinding(ExcitingBoxingButtons, sizeof(ExcitingBoxingButtons) / sizeof(ExcitingBoxingButtons[0]));
339 		hasKeyBinding |= HasKeyBinding(JissenMahjongButtons, sizeof(JissenMahjongButtons) / sizeof(JissenMahjongButtons[0]));
340 		hasKeyBinding |= HasKeyBinding(SuborKeyboardButtons, sizeof(SuborKeyboardButtons) / sizeof(SuborKeyboardButtons[0]));
341 		hasKeyBinding |= HasKeyBinding(BandaiMicrophoneButtons, sizeof(BandaiMicrophoneButtons) / sizeof(BandaiMicrophoneButtons[0]));
342 		return hasKeyBinding;
343 	}
344 
345 private:
HasKeyBindingKeyMapping346 	bool HasKeyBinding(uint32_t* buttons, uint32_t count)
347 	{
348 		for(uint32_t i = 0; i < count; i++) {
349 			if(buttons[i] != 0) {
350 				return true;
351 			}
352 		}
353 		return false;
354 	}
355 };
356 
357 struct KeyMappingSet
358 {
359 	KeyMapping Mapping1;
360 	KeyMapping Mapping2;
361 	KeyMapping Mapping3;
362 	KeyMapping Mapping4;
363 	uint32_t TurboSpeed = 0;
364 	bool PowerpadUseSideA = false;
365 
GetKeyMappingArrayKeyMappingSet366 	vector<KeyMapping> GetKeyMappingArray()
367 	{
368 		vector<KeyMapping> keyMappings;
369 		if(Mapping1.HasKeySet()) {
370 			keyMappings.push_back(Mapping1);
371 		}
372 		if(Mapping2.HasKeySet()) {
373 			keyMappings.push_back(Mapping2);
374 		}
375 		if(Mapping3.HasKeySet()) {
376 			keyMappings.push_back(Mapping3);
377 		}
378 		if(Mapping4.HasKeySet()) {
379 			keyMappings.push_back(Mapping4);
380 		}
381 		return keyMappings;
382 	}
383 };
384 
385 enum class EmulatorShortcut
386 {
387 	FastForward,
388 	Rewind,
389 	RewindTenSecs,
390 	RewindOneMin,
391 
392 	MoveToNextStateSlot,
393 	MoveToPreviousStateSlot,
394 	SaveState,
395 	LoadState,
396 
397 	InsertNextDisk,
398 	VsServiceButton,
399 	VsServiceButton2,
400 
401 	ToggleCheats,
402 	ToggleAudio,
403 	ToggleFastForward,
404 	ToggleRewind,
405 	ToggleKeyboardMode,
406 
407 	RunSingleFrame,
408 
409 	// Everything below this is handled UI-side
410 	SwitchDiskSide,
411 	EjectDisk,
412 
413 	InsertCoin1,
414 	InsertCoin2,
415 	InsertCoin3,
416 	InsertCoin4,
417 
418 	InputBarcode,
419 
420 	TakeScreenshot,
421 
422 	IncreaseSpeed,
423 	DecreaseSpeed,
424 	MaxSpeed,
425 
426 	Pause,
427 	Reset,
428 	PowerCycle,
429 	PowerOff,
430 	Exit,
431 
432 	SetScale1x,
433 	SetScale2x,
434 	SetScale3x,
435 	SetScale4x,
436 	SetScale5x,
437 	SetScale6x,
438 	ToggleFullscreen,
439 	ToggleFps,
440 	ToggleGameTimer,
441 	ToggleFrameCounter,
442 	ToggleLagCounter,
443 	ToggleOsd,
444 	ToggleAlwaysOnTop,
445 	ToggleSprites,
446 	ToggleBackground,
447 	ToggleDebugInfo,
448 
449 	LoadRandomGame,
450 	SaveStateSlot1,
451 	SaveStateSlot2,
452 	SaveStateSlot3,
453 	SaveStateSlot4,
454 	SaveStateSlot5,
455 	SaveStateSlot6,
456 	SaveStateSlot7,
457 	SaveStateSlot8,
458 	SaveStateSlot9,
459 	SaveStateSlot10,
460 	SaveStateToFile,
461 
462 	LoadStateSlot1,
463 	LoadStateSlot2,
464 	LoadStateSlot3,
465 	LoadStateSlot4,
466 	LoadStateSlot5,
467 	LoadStateSlot6,
468 	LoadStateSlot7,
469 	LoadStateSlot8,
470 	LoadStateSlot9,
471 	LoadStateSlot10,
472 	LoadStateSlotAuto,
473 	LoadStateFromFile,
474 
475 	LoadLastSession,
476 
477 	OpenFile,
478 	ShortcutCount
479 };
480 
481 struct KeyCombination
482 {
483 	uint32_t Key1 = 0;
484 	uint32_t Key2 = 0;
485 	uint32_t Key3 = 0;
486 
GetKeysKeyCombination487 	vector<uint32_t> GetKeys()
488 	{
489 		vector<uint32_t> result;
490 		if(Key1) {
491 			result.push_back(Key1);
492 		}
493 		if(Key2) {
494 			result.push_back(Key2);
495 		}
496 		if(Key3) {
497 			result.push_back(Key3);
498 		}
499 		return result;
500 	}
501 
IsSubsetOfKeyCombination502 	bool IsSubsetOf(KeyCombination keyCombination)
503 	{
504 		vector<uint32_t> myKeys = GetKeys();
505 		vector<uint32_t> otherKeys = keyCombination.GetKeys();
506 
507 		if(otherKeys.size() > myKeys.size()) {
508 			for(size_t i = 0; i < myKeys.size(); i++) {
509 				if(std::find(otherKeys.begin(), otherKeys.end(), myKeys[i]) == otherKeys.end()) {
510 					//Current key combination contains a key not found in the other combination, so it's not a subset
511 					return false;
512 				}
513 			}
514 			return true;
515 		}
516 		return false;
517 	}
518 };
519 
520 enum class Language
521 {
522 	//SystemDefault = 0,  //This value is never used by the C++ core
523 	English = 1,
524 	French = 2,
525 	Japanese = 3,
526 	Russian = 4,
527 	Spanish = 5,
528 	Ukrainian = 6,
529 	Portuguese = 7,
530 	Catalan = 8,
531 	Chinese = 9,
532 };
533 
534 enum class MouseDevice
535 {
536 	Unknown = 0,
537 	SnesMouse,
538 	SuborMouse,
539 	ArkanoidController,
540 	HoriTrack
541 };
542 
543 enum class StereoFilter
544 {
545 	None = 0,
546 	Delay = 1,
547 	Panning = 2,
548 	CombFilter = 3,
549 };
550 
551 struct AudioFilterSettings
552 {
553 	StereoFilter Filter = StereoFilter::None;
554 	double Angle = 0;
555 	int32_t Delay = 0;
556 	int32_t Strength = 0;
557 
558 	double ReverbDelay = 0;
559 	double ReverbStrength = 0;
560 
561 	int32_t CrossFadeRatio = 0;
562 };
563 
564 enum class InputDisplayPosition
565 {
566 	TopLeft = 0,
567 	TopRight = 1,
568 	BottomLeft = 2,
569 	BottomRight = 3
570 };
571 
572 struct InputDisplaySettings
573 {
574 	uint8_t VisiblePorts;
575 	InputDisplayPosition DisplayPosition;
576 	bool DisplayHorizontally;
577 };
578 
579 class EmulationSettings
580 {
581 private:
582 	static const vector<uint32_t> _speedValues;
583 
584 	static uint16_t _versionMajor;
585 	static uint8_t _versionMinor;
586 	static uint8_t _versionRevision;
587 	static Language _displayLanguage;
588 
589 	static SimpleLock _shortcutLock;
590 	static SimpleLock _equalizerLock;
591 	static SimpleLock _lock;
592 
593 	uint32_t _ppuPaletteArgb[11][64] = {
594 		/* 2C02 */			{ 0xFF666666, 0xFF002A88, 0xFF1412A7, 0xFF3B00A4, 0xFF5C007E, 0xFF6E0040, 0xFF6C0600, 0xFF561D00, 0xFF333500, 0xFF0B4800, 0xFF005200, 0xFF004F08, 0xFF00404D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFADADAD, 0xFF155FD9, 0xFF4240FF, 0xFF7527FE, 0xFFA01ACC, 0xFFB71E7B, 0xFFB53120, 0xFF994E00, 0xFF6B6D00, 0xFF388700, 0xFF0C9300, 0xFF008F32, 0xFF007C8D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFEFF, 0xFF64B0FF, 0xFF9290FF, 0xFFC676FF, 0xFFF36AFF, 0xFFFE6ECC, 0xFFFE8170, 0xFFEA9E22, 0xFFBCBE00, 0xFF88D800, 0xFF5CE430, 0xFF45E082, 0xFF48CDDE, 0xFF4F4F4F, 0xFF000000, 0xFF000000, 0xFFFFFEFF, 0xFFC0DFFF, 0xFFD3D2FF, 0xFFE8C8FF, 0xFFFBC2FF, 0xFFFEC4EA, 0xFFFECCC5, 0xFFF7D8A5, 0xFFE4E594, 0xFFCFEF96, 0xFFBDF4AB, 0xFFB3F3CC, 0xFFB5EBF2, 0xFFB8B8B8, 0xFF000000, 0xFF000000 },
595 		/* 2C03 */			{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 },
596 		/* 2C04-0001 */	{ 0xFFFFB6B6, 0xFFDA6DFF, 0xFFFF0000, 0xFF9191FF, 0xFF009191, 0xFF244800, 0xFF484848, 0xFFFF0091, 0xFFFFFFFF, 0xFF6D6D6D, 0xFFFFB600, 0xFFB6006D, 0xFF91006D, 0xFFDADA00, 0xFF6D4800, 0xFFFFFFFF, 0xFF6DB6FF, 0xFFDAB66D, 0xFF6D2400, 0xFF6DDA00, 0xFF91DAFF, 0xFFDAB6FF, 0xFFFFDA91, 0xFF0048FF, 0xFFFFDA00, 0xFF48FFDA, 0xFF000000, 0xFF480000, 0xFFDADADA, 0xFF919191, 0xFFFF00FF, 0xFF002491, 0xFF00006D, 0xFFB6DAFF, 0xFFFFB6FF, 0xFF00FF00, 0xFF00FFFF, 0xFF004848, 0xFF00B66D, 0xFFB600FF, 0xFF000000, 0xFF914800, 0xFFFF91FF, 0xFFB62400, 0xFF9100FF, 0xFF0000DA, 0xFFFF9100, 0xFF000000, 0xFF000000, 0xFF249100, 0xFFB6B6B6, 0xFF006D24, 0xFFB6FF48, 0xFF6D48DA, 0xFFFFFF00, 0xFFDA6D00, 0xFF004800, 0xFF006DDA, 0xFF009100, 0xFF242424, 0xFFFFFF6D, 0xFFFF6DFF, 0xFF916D00, 0xFF91FF6D },
597 		/* 2C04-0002 */	{ 0xFF000000, 0xFFFFB600, 0xFF916D00, 0xFFB6FF48, 0xFF91FF6D, 0xFFFF6DFF, 0xFF009191, 0xFFB6DAFF, 0xFFFF0000, 0xFF9100FF, 0xFFFFFF6D, 0xFFFF91FF, 0xFFFFFFFF, 0xFFDA6DFF, 0xFF91DAFF, 0xFF009100, 0xFF004800, 0xFF6DB6FF, 0xFFB62400, 0xFFDADADA, 0xFF00B66D, 0xFF6DDA00, 0xFF480000, 0xFF9191FF, 0xFF484848, 0xFFFF00FF, 0xFF00006D, 0xFF48FFDA, 0xFFDAB6FF, 0xFF6D4800, 0xFF000000, 0xFF6D48DA, 0xFF91006D, 0xFFFFDA91, 0xFFFF9100, 0xFFFFB6FF, 0xFF006DDA, 0xFF6D2400, 0xFFB6B6B6, 0xFF0000DA, 0xFFB600FF, 0xFFFFDA00, 0xFF6D6D6D, 0xFF244800, 0xFF0048FF, 0xFF000000, 0xFFDADA00, 0xFFFFFFFF, 0xFFDAB66D, 0xFF242424, 0xFF00FF00, 0xFFDA6D00, 0xFF004848, 0xFF002491, 0xFFFF0091, 0xFF249100, 0xFF000000, 0xFF00FFFF, 0xFF914800, 0xFFFFFF00, 0xFFFFB6B6, 0xFFB6006D, 0xFF006D24, 0xFF919191 },
598 		/* 2C04-0003 */	{ 0xFFB600FF, 0xFFFF6DFF, 0xFF91FF6D, 0xFFB6B6B6, 0xFF009100, 0xFFFFFFFF, 0xFFB6DAFF, 0xFF244800, 0xFF002491, 0xFF000000, 0xFFFFDA91, 0xFF6D4800, 0xFFFF0091, 0xFFDADADA, 0xFFDAB66D, 0xFF91DAFF, 0xFF9191FF, 0xFF009191, 0xFFB6006D, 0xFF0048FF, 0xFF249100, 0xFF916D00, 0xFFDA6D00, 0xFF00B66D, 0xFF6D6D6D, 0xFF6D48DA, 0xFF000000, 0xFF0000DA, 0xFFFF0000, 0xFFB62400, 0xFFFF91FF, 0xFFFFB6B6, 0xFFDA6DFF, 0xFF004800, 0xFF00006D, 0xFFFFFF00, 0xFF242424, 0xFFFFB600, 0xFFFF9100, 0xFFFFFFFF, 0xFF6DDA00, 0xFF91006D, 0xFF6DB6FF, 0xFFFF00FF, 0xFF006DDA, 0xFF919191, 0xFF000000, 0xFF6D2400, 0xFF00FFFF, 0xFF480000, 0xFFB6FF48, 0xFFFFB6FF, 0xFF914800, 0xFF00FF00, 0xFFDADA00, 0xFF484848, 0xFF006D24, 0xFF000000, 0xFFDAB6FF, 0xFFFFFF6D, 0xFF9100FF, 0xFF48FFDA, 0xFFFFDA00, 0xFF004848 },
599 		/* 2C04-0004 */	{ 0xFF916D00, 0xFF6D48DA, 0xFF009191, 0xFFDADA00, 0xFF000000, 0xFFFFB6B6, 0xFF002491, 0xFFDA6D00, 0xFFB6B6B6, 0xFF6D2400, 0xFF00FF00, 0xFF00006D, 0xFFFFDA91, 0xFFFFFF00, 0xFF009100, 0xFFB6FF48, 0xFFFF6DFF, 0xFF480000, 0xFF0048FF, 0xFFFF91FF, 0xFF000000, 0xFF484848, 0xFFB62400, 0xFFFF9100, 0xFFDAB66D, 0xFF00B66D, 0xFF9191FF, 0xFF249100, 0xFF91006D, 0xFF000000, 0xFF91FF6D, 0xFF6DB6FF, 0xFFB6006D, 0xFF006D24, 0xFF914800, 0xFF0000DA, 0xFF9100FF, 0xFFB600FF, 0xFF6D6D6D, 0xFFFF0091, 0xFF004848, 0xFFDADADA, 0xFF006DDA, 0xFF004800, 0xFF242424, 0xFFFFFF6D, 0xFF919191, 0xFFFF00FF, 0xFFFFB6FF, 0xFFFFFFFF, 0xFF6D4800, 0xFFFF0000, 0xFFFFDA00, 0xFF48FFDA, 0xFFFFFFFF, 0xFF91DAFF, 0xFF000000, 0xFFFFB600, 0xFFDA6DFF, 0xFFB6DAFF, 0xFF6DDA00, 0xFFDAB6FF, 0xFF00FFFF, 0xFF244800 },
600 		/* 2C05-01 */		{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 },
601 		/* 2C05-02 */		{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 },
602 		/* 2C05-03 */		{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 },
603 		/* 2C05-04 */		{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 },
604 		/* 2C05-05 */		{ 0xFF6D6D6D, 0xFF002491, 0xFF0000DA, 0xFF6D48DA, 0xFF91006D, 0xFFB6006D, 0xFFB62400, 0xFF914800, 0xFF6D4800, 0xFF244800, 0xFF006D24, 0xFF009100, 0xFF004848, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB6B6B6, 0xFF006DDA, 0xFF0048FF, 0xFF9100FF, 0xFFB600FF, 0xFFFF0091, 0xFFFF0000, 0xFFDA6D00, 0xFF916D00, 0xFF249100, 0xFF009100, 0xFF00B66D, 0xFF009191, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFF6DB6FF, 0xFF9191FF, 0xFFDA6DFF, 0xFFFF00FF, 0xFFFF6DFF, 0xFFFF9100, 0xFFFFB600, 0xFFDADA00, 0xFF6DDA00, 0xFF00FF00, 0xFF48FFDA, 0xFF00FFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFB6DAFF, 0xFFDAB6FF, 0xFFFFB6FF, 0xFFFF91FF, 0xFFFFB6B6, 0xFFFFDA91, 0xFFFFFF48, 0xFFFFFF6D, 0xFFB6FF48, 0xFF91FF6D, 0xFF48FFDA, 0xFF91DAFF, 0xFF000000, 0xFF000000, 0xFF000000 }
605 	};
606 
607 	bool _isFullColorPalette = false;
608 	uint32_t _userPalette[512] = { };
609 	uint32_t _currentPalette[512] = { };
610 
611 	const uint8_t _paletteLut[11][64] = {
612 		/* 2C02 */      { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 },
613 		/* 2C03 */      { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
614 		/* 2C04-0001 */ { 53,35,22,34,28,9,29,21,32,0,39,5,4,40,8,32,33,62,31,41,60,50,54,18,63,43,46,30,61,45,36,1,14,49,51,42,44,12,27,20,46,7,52,6,19,2,38,46,46,25,16,10,57,3,55,23,15,17,11,13,56,37,24,58 },
615 		/* 2C04-0002 */ { 46,39,24,57,58,37,28,49,22,19,56,52,32,35,60,11,15,33,6,61,27,41,30,34,29,36,14,43,50,8,46,3,4,54,38,51,17,31,16,2,20,63,0,9,18,46,40,32,62,13,42,23,12,1,21,25,46,44,7,55,53,5,10,45 },
616 		/* 2C04-0003 */ { 20,37,58,16,11,32,49,9,1,46,54,8,21,61,62,60,34,28,5,18,25,24,23,27,0,3,46,2,22,6,52,53,35,15,14,55,13,39,38,32,41,4,33,36,17,45,46,31,44,30,57,51,7,42,40,29,10,46,50,56,19,43,63,12 },
617 		/* 2C04-0004 */ { 24,3,28,40,46,53,1,23,16,31,42,14,54,55,11,57,37,30,18,52,46,29,6,38,62,27,34,25,4,46,58,33,5,10,7,2,19,20,0,21,12,61,17,15,13,56,45,36,51,32,8,22,63,43,32,60,46,39,35,49,41,50,44,9 },
618 		/* 2C05-01 */   { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
619 		/* 2C05-02 */   { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
620 		/* 2C05-03 */   { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
621 		/* 2C05-04 */   { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
622 		/* 2C05-05 */   { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,15,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,15,62,63 },
623 	};
624 
625 	string _pauseScreenMessage;
626 
627 	uint64_t _flags = 0;
628 
629 	bool _audioSettingsChanged = false;
630 	uint32_t _audioLatency = 50;
631 	double _channelVolume[11] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
632 	double _channelPanning[11] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
633 	EqualizerFilterType _equalizerFilterType = EqualizerFilterType::None;
634 	vector<double> _bandGains = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
635 	vector<double> _bands = { { 40,56,80,113,160,225,320,450,600,750,1000,2000,3000,4000,5000,6000,7000,10000,12500,15000 } };
636 	double _masterVolume = 1.0;
637 	double _volumeReduction = 0.75;
638 	uint32_t _sampleRate = 48000;
639 	AudioFilterSettings _audioFilterSettings;
640 
641 	NesModel _model = NesModel::Auto;
642 	PpuModel _ppuModel = PpuModel::Ppu2C02;
643 
644 	uint32_t _emulationSpeed = 100;
645 	uint32_t _turboSpeed = 300;
646 	uint32_t _rewindSpeed = 100;
647 
648 	uint32_t _rewindBufferSize = 300;
649 
650 	bool _hasOverclock = false;
651 	uint32_t _overclockRate = 100;
652 	bool _overclockAdjustApu = true;
653 	bool _disableOverclocking = false;
654 	uint32_t _extraScanlinesBeforeNmi = 0;
655 	uint32_t _extraScanlinesAfterNmi = 0;
656 	double _effectiveOverclockRate = 100;
657 
658 	OverscanDimensions _overscan;
659 	VideoFilterType _videoFilterType = VideoFilterType::None;
660 	double _videoScale = 1;
661 	VideoAspectRatio _aspectRatio = VideoAspectRatio::NoStretching;
662 	double _customAspectRatio = 1.0;
663 	VideoResizeFilter _resizeFilter = VideoResizeFilter::NearestNeighbor;
664 	PictureSettings _pictureSettings;
665 	NtscFilterSettings _ntscFilterSettings;
666 	bool _backgroundEnabled = true;
667 	bool _spritesEnabled = true;
668 	uint32_t _screenRotation = 0;
669 	uint32_t _exclusiveRefreshRate = 60;
670 
671 	ConsoleType _consoleType = ConsoleType::Nes;
672 	ExpansionPortDevice _expansionDevice = ExpansionPortDevice::None;
673 	ControllerType _controllerTypes[4] = { ControllerType::None, ControllerType::None, ControllerType::None, ControllerType::None };
674 	KeyMappingSet _controllerKeys[4] = { KeyMappingSet(), KeyMappingSet(), KeyMappingSet(), KeyMappingSet() };
675 	bool _needControllerUpdate = false;
676 	uint32_t _zapperDetectionRadius = 0;
677 	uint32_t _controllerDeadzoneSize = 2;
678 	std::unordered_map<int, double> _mouseSensitivity;
679 	int32_t _inputPollScanline = 241;
680 
681 	int32_t _nsfAutoDetectSilenceDelay = 3000;
682 	int32_t _nsfMoveToNextTrackTime = 120;
683 	bool _nsfDisableApuIrqs = true;
684 
685 	InputDisplaySettings _inputDisplaySettings = { 0, InputDisplayPosition::TopLeft, false };
686 
687 	uint32_t _autoSaveDelay = 5;
688 	bool _autoSaveNotify = false;
689 
690 	bool _keyboardModeEnabled = false;
691 
692 	std::unordered_map<uint32_t, KeyCombination> _emulatorKeys[3];
693 	std::unordered_map<uint32_t, vector<KeyCombination>> _shortcutSupersets[3];
694 
695 	RamPowerOnState _ramPowerOnState = RamPowerOnState::AllZeros;
696 	uint32_t _dipSwitches = 0;
697 
698 public:
EmulationSettings()699 	EmulationSettings()
700 	{
701 		memcpy(_userPalette, _ppuPaletteArgb, sizeof(_userPalette));
702 	}
703 
GetMesenVersion()704 	static uint32_t GetMesenVersion()
705 	{
706 		return (_versionMajor << 16) | (_versionMinor << 8) | _versionRevision;
707 	}
708 
GetMesenVersionString()709 	static string GetMesenVersionString()
710 	{
711 		return std::to_string(_versionMajor) + "." + std::to_string(_versionMinor) + "." + std::to_string(_versionRevision);
712 	}
713 
SetFlags(uint64_t flags)714 	void SetFlags(uint64_t flags)
715 	{
716 		if((_flags & flags) != flags) {
717 			//Need a lock to prevent flag changes from being ignored due to multithreaded access
718 			LockHandler lock = _lock.AcquireSafe();
719 			_flags |= flags;
720 
721 			_backgroundEnabled = !CheckFlag(EmulationFlags::DisableBackground);
722 			_spritesEnabled = !CheckFlag(EmulationFlags::DisableSprites);
723 			if(flags & EmulationFlags::UseCustomVsPalette) {
724 				UpdateCurrentPalette();
725 			}
726 		}
727 	}
728 
SetFlagState(EmulationFlags flag,bool enabled)729 	void SetFlagState(EmulationFlags flag, bool enabled)
730 	{
731 		if(enabled) {
732 			SetFlags(flag);
733 		} else {
734 			ClearFlags(flag);
735 		}
736 	}
737 
ClearFlags(uint64_t flags)738 	void ClearFlags(uint64_t flags)
739 	{
740 		if((_flags & flags) != 0) {
741 			//Need a lock to prevent flag changes from being ignored due to multithreaded access
742 			LockHandler lock = _lock.AcquireSafe();
743 			_flags &= ~flags;
744 
745 			_backgroundEnabled = !CheckFlag(EmulationFlags::DisableBackground);
746 			_spritesEnabled = !CheckFlag(EmulationFlags::DisableSprites);
747 			if(flags & EmulationFlags::UseCustomVsPalette) {
748 				UpdateCurrentPalette();
749 			}
750 		}
751 	}
752 
CheckFlag(EmulationFlags flag)753 	bool CheckFlag(EmulationFlags flag)
754 	{
755 		return (_flags & flag) == flag;
756 	}
757 
SetDisplayLanguage(Language lang)758 	static void SetDisplayLanguage(Language lang)
759 	{
760 		_displayLanguage = lang;
761 	}
762 
GetDisplayLanguage()763 	static Language GetDisplayLanguage()
764 	{
765 		return _displayLanguage;
766 	}
767 
NeedsPause()768 	bool NeedsPause()
769 	{
770 		return CheckFlag(EmulationFlags::Paused) && !CheckFlag(EmulationFlags::DebuggerWindowEnabled);
771 	}
772 
InputEnabled()773 	bool InputEnabled()
774 	{
775 		return !CheckFlag(EmulationFlags::InBackground) || CheckFlag(EmulationFlags::AllowBackgroundInput);
776 	}
777 
SetNesModel(NesModel model)778 	void SetNesModel(NesModel model)
779 	{
780 		_model = model;
781 	}
782 
GetNesModel()783 	NesModel GetNesModel()
784 	{
785 		return _model;
786 	}
787 
SetPpuModel(PpuModel ppuModel)788 	void SetPpuModel(PpuModel ppuModel)
789 	{
790 		_ppuModel = ppuModel;
791 		UpdateCurrentPalette();
792 	}
793 
GetPpuModel()794 	PpuModel GetPpuModel()
795 	{
796 		return _ppuModel;
797 	}
798 
UpdateCurrentPalette()799 	void UpdateCurrentPalette()
800 	{
801 		if(CheckFlag(EmulationFlags::UseCustomVsPalette)) {
802 			for(int i = 0; i < 64; i++) {
803 				for(int j = 0; j < 8; j++) {
804 					_currentPalette[(j << 6) | i] = _userPalette[(j << 6) | (_paletteLut[(int)_ppuModel][i])];
805 				}
806 			}
807 		} else if(_ppuModel == PpuModel::Ppu2C02) {
808 			memcpy(_currentPalette, _userPalette, sizeof(_userPalette));
809 		} else {
810 			memcpy(_currentPalette, _ppuPaletteArgb[(int)_ppuModel], sizeof(_ppuPaletteArgb[0]));
811 			GenerateFullColorPalette(_currentPalette);
812 		}
813 	}
814 
GetRgbPalette()815 	uint32_t* GetRgbPalette()
816 	{
817 		return _currentPalette;
818 	}
819 
GetUserRgbPalette(uint32_t * paletteBuffer)820 	void GetUserRgbPalette(uint32_t* paletteBuffer)
821 	{
822 		memcpy(paletteBuffer, _userPalette, sizeof(_userPalette));
823 	}
824 
825 	void SetUserRgbPalette(uint32_t* paletteBuffer, uint32_t size = 64)
826 	{
827 		if(size != 64 && size != 512) {
828 			throw new std::runtime_error("Invalid palette buffer size");
829 		}
830 
831 		memcpy(_userPalette, paletteBuffer, size * sizeof(uint32_t));
832 		if(size == 64) {
833 			GenerateFullColorPalette(_userPalette);
834 		}
835 		_isFullColorPalette = (size == 512);
836 		UpdateCurrentPalette();
837 	}
838 
IsFullColorPalette()839 	bool IsFullColorPalette()
840 	{
841 		return _isFullColorPalette;
842 	}
843 
GenerateFullColorPalette(uint32_t * paletteBuffer)844 	void GenerateFullColorPalette(uint32_t* paletteBuffer)
845 	{
846 		for(int i = 0; i < 64; i++) {
847 			for(int j = 1; j < 8; j++) {
848 				double redColor = (uint8_t)(paletteBuffer[i] >> 16);
849 				double greenColor = (uint8_t)(paletteBuffer[i] >> 8);
850 				double blueColor = (uint8_t)paletteBuffer[i];
851 				if(j & 0x01) {
852 					//Intensify red
853 					redColor *= 1.1;
854 					greenColor *= 0.9;
855 					blueColor *= 0.9;
856 				}
857 				if(j & 0x02) {
858 					//Intensify green
859 					greenColor *= 1.1;
860 					redColor *= 0.9;
861 					blueColor *= 0.9;
862 				}
863 				if(j & 0x04) {
864 					//Intensify blue
865 					blueColor *= 1.1;
866 					redColor *= 0.9;
867 					greenColor *= 0.9;
868 				}
869 
870 				uint8_t r = (uint8_t)(redColor > 255 ? 255 : redColor);
871 				uint8_t g = (uint8_t)(greenColor > 255 ? 255 : greenColor);
872 				uint8_t b = (uint8_t)(blueColor > 255 ? 255 : blueColor);
873 
874 				uint32_t color = 0xFF000000 | (r << 16) | (g << 8) | b;
875 				paletteBuffer[(j << 6) | i] = color;
876 			}
877 		}
878 	}
879 
880 	//0: Muted, 0.5: Default, 1.0: Max volume
SetChannelVolume(AudioChannel channel,double volume)881 	void SetChannelVolume(AudioChannel channel, double volume)
882 	{
883 		_channelVolume[(int)channel] = volume;
884 		_audioSettingsChanged = true;
885 	}
886 
887 	void SetMasterVolume(double volume, double volumeReduction = -1.0)
888 	{
889 		_masterVolume = volume;
890 		if(volumeReduction >= 0) {
891 			_volumeReduction = volumeReduction;
892 		}
893 		_audioSettingsChanged = true;
894 	}
895 
SetChannelPanning(AudioChannel channel,double panning)896 	void SetChannelPanning(AudioChannel channel, double panning)
897 	{
898 		_channelPanning[(int)channel] = panning;
899 		_audioSettingsChanged = true;
900 	}
901 
GetBandGains()902 	vector<double> GetBandGains()
903 	{
904 		auto lock = _equalizerLock.AcquireSafe();
905 		return _bandGains;
906 	}
907 
SetBandGain(int band,double gain)908 	void SetBandGain(int band, double gain)
909 	{
910 		auto lock = _equalizerLock.AcquireSafe();
911 		if(band < (int)_bandGains.size()) {
912 			_bandGains[band] = gain;
913 			_audioSettingsChanged = true;
914 		}
915 	}
916 
GetEqualizerBands()917 	vector<double> GetEqualizerBands()
918 	{
919 		auto lock = _equalizerLock.AcquireSafe();
920 		return _bands;
921 	}
922 
SetEqualizerBands(double * bands,uint32_t bandCount)923 	void SetEqualizerBands(double *bands, uint32_t bandCount)
924 	{
925 		auto lock = _equalizerLock.AcquireSafe();
926 		_bands.clear();
927 		_bandGains.clear();
928 		for(uint32_t i = 0; i < bandCount; i++) {
929 			_bands.push_back(bands[i]);
930 			_bandGains.push_back(0);
931 		}
932 	}
933 
GetEqualizerFilterType()934 	EqualizerFilterType GetEqualizerFilterType()
935 	{
936 		return _equalizerFilterType;
937 	}
938 
SetEqualizerFilterType(EqualizerFilterType filter)939 	void SetEqualizerFilterType(EqualizerFilterType filter)
940 	{
941 		_equalizerFilterType = filter;
942 		_audioSettingsChanged = true;
943 	}
944 
SetSampleRate(uint32_t sampleRate)945 	void SetSampleRate(uint32_t sampleRate)
946 	{
947 		_sampleRate = sampleRate;
948 		_audioSettingsChanged = true;
949 	}
950 
GetSampleRate()951 	uint32_t GetSampleRate()
952 	{
953 		return _sampleRate;
954 	}
955 
SetAudioLatency(uint32_t msLatency)956 	void SetAudioLatency(uint32_t msLatency)
957 	{
958 		_audioLatency = msLatency;
959 		_audioSettingsChanged = true;
960 	}
961 
SetAudioFilterSettings(AudioFilterSettings settings)962 	void SetAudioFilterSettings(AudioFilterSettings settings)
963 	{
964 		_audioFilterSettings = settings;
965 		_audioSettingsChanged = true;
966 	}
967 
GetAudioFilterSettings()968 	AudioFilterSettings GetAudioFilterSettings()
969 	{
970 		return _audioFilterSettings;
971 	}
972 
NeedAudioSettingsUpdate()973 	bool NeedAudioSettingsUpdate()
974 	{
975 		bool value = _audioSettingsChanged;
976 		if(value) {
977 			_audioSettingsChanged = false;
978 		}
979 		return value;
980 	}
981 
982 	//0: No limit, Number: % of default speed (50/60fps)
983 	void SetEmulationSpeed(uint32_t emulationSpeed, bool displaySpeed = false)
984 	{
985 		if(_emulationSpeed != emulationSpeed) {
986 			_emulationSpeed = emulationSpeed;
987 			if(displaySpeed) {
988 				MessageManager::DisplayMessage("EmulationSpeed", _emulationSpeed == 0 ? "EmulationMaximumSpeed" : "EmulationSpeedPercent", std::to_string(_emulationSpeed));
989 			}
990 		}
991 	}
992 
IncreaseEmulationSpeed()993 	void IncreaseEmulationSpeed()
994 	{
995 		if(_emulationSpeed == _speedValues.back()) {
996 			SetEmulationSpeed(0, true);
997 		} else if(_emulationSpeed != 0) {
998 			for(size_t i = 0; i < _speedValues.size(); i++) {
999 				if(_speedValues[i] > _emulationSpeed) {
1000 					SetEmulationSpeed(_speedValues[i], true);
1001 					break;
1002 				}
1003 			}
1004 		}
1005 	}
1006 
DecreaseEmulationSpeed()1007 	void DecreaseEmulationSpeed()
1008 	{
1009 		if(_emulationSpeed == 0) {
1010 			SetEmulationSpeed(_speedValues.back(), true);
1011 		} else if(_emulationSpeed > _speedValues.front()) {
1012 			for(int i = (int)_speedValues.size() - 1; i >= 0; i--) {
1013 				if(_speedValues[i] < _emulationSpeed) {
1014 					SetEmulationSpeed(_speedValues[i], true);
1015 					break;
1016 				}
1017 			}
1018 		}
1019 	}
1020 
SetTurboRewindSpeed(uint32_t turboSpeed,uint32_t rewindSpeed)1021 	void SetTurboRewindSpeed(uint32_t turboSpeed, uint32_t rewindSpeed)
1022 	{
1023 		_turboSpeed = turboSpeed;
1024 		_rewindSpeed = rewindSpeed;
1025 	}
1026 
GetRewindSpeed()1027 	uint32_t GetRewindSpeed()
1028 	{
1029 		return _rewindSpeed;
1030 	}
1031 
SetRewindBufferSize(uint32_t seconds)1032 	void SetRewindBufferSize(uint32_t seconds)
1033 	{
1034 		_rewindBufferSize = seconds;
1035 	}
1036 
GetRewindBufferSize()1037 	uint32_t GetRewindBufferSize()
1038 	{
1039 		return _rewindBufferSize;
1040 	}
1041 
1042 	uint32_t GetEmulationSpeed(bool ignoreTurbo = false);
1043 
UpdateEffectiveOverclockRate()1044 	void UpdateEffectiveOverclockRate()
1045 	{
1046 		if(_disableOverclocking) {
1047 			_effectiveOverclockRate = 100;
1048 		} else {
1049 			_effectiveOverclockRate = _overclockRate;
1050 		}
1051 		_hasOverclock = _effectiveOverclockRate != 100;
1052 		_audioSettingsChanged = true;
1053 	}
1054 
DisableOverclocking(bool disabled)1055 	void DisableOverclocking(bool disabled)
1056 	{
1057 		if(_disableOverclocking != disabled) {
1058 			_disableOverclocking = disabled;
1059 			UpdateEffectiveOverclockRate();
1060 		}
1061 	}
1062 
GetOverclockRateSetting()1063 	uint32_t GetOverclockRateSetting()
1064 	{
1065 		return _overclockRate;
1066 	}
1067 
HasOverclock()1068 	bool HasOverclock()
1069 	{
1070 		return _hasOverclock;
1071 	}
1072 
GetOverclockRate()1073 	double GetOverclockRate()
1074 	{
1075 		return _effectiveOverclockRate;
1076 	}
1077 
GetOverclockAdjustApu()1078 	bool GetOverclockAdjustApu()
1079 	{
1080 		return _overclockAdjustApu;
1081 	}
1082 
SetOverclockRate(uint32_t overclockRate,bool adjustApu)1083 	void SetOverclockRate(uint32_t overclockRate, bool adjustApu)
1084 	{
1085 		if(_overclockRate != overclockRate || _overclockAdjustApu != adjustApu) {
1086 			_overclockRate = overclockRate;
1087 			_overclockAdjustApu = adjustApu;
1088 
1089 			UpdateEffectiveOverclockRate();
1090 
1091 			MessageManager::DisplayMessage("ClockRate", std::to_string((uint32_t)GetOverclockRate()) + "%");
1092 		}
1093 	}
1094 
GetPpuExtraScanlinesBeforeNmi()1095 	uint32_t GetPpuExtraScanlinesBeforeNmi()
1096 	{
1097 		return _disableOverclocking ? 0 : _extraScanlinesBeforeNmi;
1098 	}
1099 
GetPpuExtraScanlinesAfterNmi()1100 	uint32_t GetPpuExtraScanlinesAfterNmi()
1101 	{
1102 		return _disableOverclocking ? 0 : _extraScanlinesAfterNmi;
1103 	}
1104 
SetPpuNmiConfig(uint32_t extraScanlinesBeforeNmi,uint32_t extraScanlinesAfterNmi)1105 	void SetPpuNmiConfig(uint32_t extraScanlinesBeforeNmi, uint32_t extraScanlinesAfterNmi)
1106 	{
1107 		if(_extraScanlinesBeforeNmi != extraScanlinesBeforeNmi || _extraScanlinesAfterNmi != extraScanlinesAfterNmi) {
1108 			if(extraScanlinesBeforeNmi > 0 || extraScanlinesAfterNmi > 0) {
1109 				MessageManager::DisplayMessage("PPU", "ScanlineTimingWarning");
1110 			}
1111 
1112 			_extraScanlinesBeforeNmi = extraScanlinesBeforeNmi;
1113 			_extraScanlinesAfterNmi = extraScanlinesAfterNmi;
1114 
1115 			UpdateEffectiveOverclockRate();
1116 		}
1117 	}
1118 
SetOverscanDimensions(uint8_t left,uint8_t right,uint8_t top,uint8_t bottom)1119 	void SetOverscanDimensions(uint8_t left, uint8_t right, uint8_t top, uint8_t bottom)
1120 	{
1121 		if(_overscan.Left != left || _overscan.Right != right || _overscan.Top != top || _overscan.Bottom != bottom) {
1122 			_overscan.Left = left;
1123 			_overscan.Right = right;
1124 			_overscan.Top = top;
1125 			_overscan.Bottom = bottom;
1126 		}
1127 	}
1128 
GetOverscanDimensions()1129 	OverscanDimensions GetOverscanDimensions()
1130 	{
1131 		return _overscan;
1132 	}
1133 
GetChannelVolume(AudioChannel channel)1134 	double GetChannelVolume(AudioChannel channel)
1135 	{
1136 		return _channelVolume[(int)channel];
1137 	}
1138 
GetMasterVolume()1139 	double GetMasterVolume()
1140 	{
1141 		return _masterVolume;
1142 	}
1143 
GetVolumeReduction()1144 	double GetVolumeReduction()
1145 	{
1146 		return _volumeReduction;
1147 	}
1148 
GetChannelPanning(AudioChannel channel)1149 	double GetChannelPanning(AudioChannel channel)
1150 	{
1151 		return _channelPanning[(int)channel];
1152 	}
1153 
GetAudioLatency()1154 	uint32_t GetAudioLatency()
1155 	{
1156 		return _audioLatency;
1157 	}
1158 
SetVideoFilterType(VideoFilterType videoFilterType)1159 	void SetVideoFilterType(VideoFilterType videoFilterType)
1160 	{
1161 		_videoFilterType = videoFilterType;
1162 	}
1163 
GetVideoFilterType()1164 	VideoFilterType GetVideoFilterType()
1165 	{
1166 		return _videoFilterType;
1167 	}
1168 
SetVideoResizeFilter(VideoResizeFilter videoResizeFilter)1169 	void SetVideoResizeFilter(VideoResizeFilter videoResizeFilter)
1170 	{
1171 		_resizeFilter = videoResizeFilter;
1172 	}
1173 
GetVideoResizeFilter()1174 	VideoResizeFilter GetVideoResizeFilter()
1175 	{
1176 		return _resizeFilter;
1177 	}
1178 
SetVideoAspectRatio(VideoAspectRatio aspectRatio,double customRatio)1179 	void SetVideoAspectRatio(VideoAspectRatio aspectRatio, double customRatio)
1180 	{
1181 		_aspectRatio = aspectRatio;
1182 		_customAspectRatio = customRatio;
1183 	}
1184 
GetBackgroundEnabled()1185 	bool GetBackgroundEnabled()
1186 	{
1187 		return _backgroundEnabled;
1188 	}
1189 
GetSpritesEnabled()1190 	bool GetSpritesEnabled()
1191 	{
1192 		return _spritesEnabled;
1193 	}
1194 
SetPictureSettings(double brightness,double contrast,double saturation,double hue,double scanlineIntensity)1195 	void SetPictureSettings(double brightness, double contrast, double saturation, double hue, double scanlineIntensity)
1196 	{
1197 		_pictureSettings.Brightness = brightness;
1198 		_pictureSettings.Contrast = contrast;
1199 		_pictureSettings.Saturation = saturation;
1200 		_pictureSettings.Hue = hue;
1201 		_pictureSettings.ScanlineIntensity = scanlineIntensity;
1202 	}
1203 
GetPictureSettings()1204 	PictureSettings GetPictureSettings()
1205 	{
1206 		return _pictureSettings;
1207 	}
1208 
SetNtscFilterSettings(double artifacts,double bleed,double fringing,double gamma,double resolution,double sharpness,bool mergeFields,double yFilterLength,double iFilterLength,double qFilterLength,bool verticalBlend,bool keepVerticalResolution)1209 	void SetNtscFilterSettings(double artifacts, double bleed, double fringing, double gamma, double resolution, double sharpness, bool mergeFields, double yFilterLength, double iFilterLength, double qFilterLength, bool verticalBlend, bool keepVerticalResolution)
1210 	{
1211 		_ntscFilterSettings.Artifacts = artifacts;
1212 		_ntscFilterSettings.Bleed = bleed;
1213 		_ntscFilterSettings.Fringing = fringing;
1214 		_ntscFilterSettings.Gamma = gamma;
1215 		_ntscFilterSettings.Resolution = resolution;
1216 		_ntscFilterSettings.Sharpness = sharpness;
1217 
1218 		_ntscFilterSettings.MergeFields = mergeFields;
1219 
1220 		_ntscFilterSettings.YFilterLength = yFilterLength;
1221 		_ntscFilterSettings.IFilterLength = iFilterLength;
1222 		_ntscFilterSettings.QFilterLength = qFilterLength;
1223 
1224 		_ntscFilterSettings.VerticalBlend = verticalBlend;
1225 		_ntscFilterSettings.KeepVerticalResolution = keepVerticalResolution;
1226 	}
1227 
GetNtscFilterSettings()1228 	NtscFilterSettings GetNtscFilterSettings()
1229 	{
1230 		return _ntscFilterSettings;
1231 	}
1232 
1233 	double GetAspectRatio(shared_ptr<Console> console);
1234 	void InitializeInputDevices(GameInputType inputType, GameSystem system, bool silent);
1235 
SetVideoScale(double scale)1236 	void SetVideoScale(double scale)
1237 	{
1238 		if(_videoScale != scale) {
1239 			_videoScale = scale;
1240 		}
1241 	}
1242 
GetVideoScale()1243 	double GetVideoScale()
1244 	{
1245 		return _videoScale;
1246 	}
1247 
SetScreenRotation(uint32_t angle)1248 	void SetScreenRotation(uint32_t angle)
1249 	{
1250 		_screenRotation = angle;
1251 	}
1252 
GetScreenRotation()1253 	uint32_t GetScreenRotation()
1254 	{
1255 		return _screenRotation;
1256 	}
1257 
SetExclusiveRefreshRate(uint32_t refreshRate)1258 	void SetExclusiveRefreshRate(uint32_t refreshRate)
1259 	{
1260 		_exclusiveRefreshRate = refreshRate;
1261 	}
1262 
GetExclusiveRefreshRate()1263 	uint32_t GetExclusiveRefreshRate()
1264 	{
1265 		return _exclusiveRefreshRate;
1266 	}
1267 
SetExpansionDevice(ExpansionPortDevice expansionDevice)1268 	void SetExpansionDevice(ExpansionPortDevice expansionDevice)
1269 	{
1270 		_expansionDevice = expansionDevice;
1271 		_needControllerUpdate = true;
1272 	}
1273 
GetExpansionDevice()1274 	ExpansionPortDevice GetExpansionDevice()
1275 	{
1276 		return _expansionDevice;
1277 	}
1278 
SetConsoleType(ConsoleType type)1279 	void SetConsoleType(ConsoleType type)
1280 	{
1281 		_consoleType = type;
1282 		_needControllerUpdate = true;
1283 	}
1284 
GetConsoleType()1285 	ConsoleType GetConsoleType()
1286 	{
1287 		return _consoleType;
1288 	}
1289 
SetControllerType(uint8_t port,ControllerType type)1290 	void SetControllerType(uint8_t port, ControllerType type)
1291 	{
1292 		_controllerTypes[port] = type;
1293 		_needControllerUpdate = true;
1294 	}
1295 
GetControllerType(uint8_t port)1296 	ControllerType GetControllerType(uint8_t port)
1297 	{
1298 		return _controllerTypes[port];
1299 	}
1300 
SetControllerKeys(uint8_t port,KeyMappingSet keyMappings)1301 	void SetControllerKeys(uint8_t port, KeyMappingSet keyMappings)
1302 	{
1303 		_controllerKeys[port] = keyMappings;
1304 		_needControllerUpdate = true;
1305 	}
1306 
GetControllerKeys(uint8_t port)1307 	KeyMappingSet GetControllerKeys(uint8_t port)
1308 	{
1309 		return _controllerKeys[port];
1310 	}
1311 
ClearShortcutKeys()1312 	void ClearShortcutKeys()
1313 	{
1314 		auto lock = _shortcutLock.AcquireSafe();
1315 		_emulatorKeys[0].clear();
1316 		_emulatorKeys[1].clear();
1317 		_emulatorKeys[2].clear();
1318 		_shortcutSupersets[0].clear();
1319 		_shortcutSupersets[1].clear();
1320 		_shortcutSupersets[2].clear();
1321 
1322 		//Add Alt-F4 as a fake shortcut to prevent Alt-F4 from triggering Alt or F4 key bindings. (e.g load save state 4)
1323 		KeyCombination keyComb;
1324 		keyComb.Key1 = KeyManager::GetKeyCode("Alt");
1325 		keyComb.Key2 = KeyManager::GetKeyCode("F4");
1326 		SetShortcutKey(EmulatorShortcut::Exit, keyComb, 2);
1327 	}
1328 
SetShortcutKey(EmulatorShortcut shortcut,KeyCombination keyCombination,int keySetIndex)1329 	void SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex)
1330 	{
1331 		auto lock = _shortcutLock.AcquireSafe();
1332 		_emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination;
1333 
1334 		for(int i = 0; i < 3; i++) {
1335 			for(std::pair<const uint32_t, KeyCombination> &kvp : _emulatorKeys[i]) {
1336 				if(keyCombination.IsSubsetOf(kvp.second)) {
1337 					_shortcutSupersets[keySetIndex][(uint32_t)shortcut].push_back(kvp.second);
1338 				} else if(kvp.second.IsSubsetOf(keyCombination)) {
1339 					_shortcutSupersets[i][kvp.first].push_back(keyCombination);
1340 				}
1341 			}
1342 		}
1343 	}
1344 
GetShortcutKey(EmulatorShortcut shortcut,int keySetIndex)1345 	KeyCombination GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex)
1346 	{
1347 		auto lock = _shortcutLock.AcquireSafe();
1348 		auto result = _emulatorKeys[keySetIndex].find((int)shortcut);
1349 		if(result != _emulatorKeys[keySetIndex].end()) {
1350 			return result->second;
1351 		}
1352 		return {};
1353 	}
1354 
GetShortcutSupersets(EmulatorShortcut shortcut,int keySetIndex)1355 	vector<KeyCombination> GetShortcutSupersets(EmulatorShortcut shortcut, int keySetIndex)
1356 	{
1357 		auto lock = _shortcutLock.AcquireSafe();
1358 		return _shortcutSupersets[keySetIndex][(uint32_t)shortcut];
1359 	}
1360 
NeedControllerUpdate()1361 	bool NeedControllerUpdate()
1362 	{
1363 		if(_needControllerUpdate) {
1364 			_needControllerUpdate = false;
1365 			return true;
1366 		} else {
1367 			return false;
1368 		}
1369 	}
1370 
SetMouseSensitivity(MouseDevice device,double sensitivity)1371 	void SetMouseSensitivity(MouseDevice device, double sensitivity)
1372 	{
1373 		_mouseSensitivity[(int)device] = sensitivity;
1374 	}
1375 
GetMouseSensitivity(MouseDevice device)1376 	double GetMouseSensitivity(MouseDevice device)
1377 	{
1378 		auto result = _mouseSensitivity.find((int)device);
1379 		if(result != _mouseSensitivity.end()) {
1380 			return result->second;
1381 		} else {
1382 			return 1.0;
1383 		}
1384 	}
1385 
SetControllerDeadzoneSize(uint32_t deadzoneSize)1386 	void SetControllerDeadzoneSize(uint32_t deadzoneSize)
1387 	{
1388 		_controllerDeadzoneSize = deadzoneSize;
1389 	}
1390 
GetControllerDeadzoneRatio()1391 	double GetControllerDeadzoneRatio()
1392 	{
1393 		switch(_controllerDeadzoneSize) {
1394 			case 0: return 0.5;
1395 			case 1: return 0.75;
1396 			case 2: return 1;
1397 			case 3: return 1.25;
1398 			case 4: return 1.5;
1399 		}
1400 		return 1;
1401 	}
1402 
SetZapperDetectionRadius(uint32_t detectionRadius)1403 	void SetZapperDetectionRadius(uint32_t detectionRadius)
1404 	{
1405 		_zapperDetectionRadius = detectionRadius;
1406 	}
1407 
GetZapperDetectionRadius()1408 	uint32_t GetZapperDetectionRadius()
1409 	{
1410 		return _zapperDetectionRadius;
1411 	}
1412 
SetInputPollScanline(int32_t scanline)1413 	void SetInputPollScanline(int32_t scanline)
1414 	{
1415 		_inputPollScanline = scanline;
1416 	}
1417 
GetInputPollScanline()1418 	int32_t GetInputPollScanline()
1419 	{
1420 		return _inputPollScanline;
1421 	}
1422 
HasZapper()1423 	bool HasZapper()
1424 	{
1425 		return _controllerTypes[0] == ControllerType::Zapper || _controllerTypes[1] == ControllerType::Zapper || (_consoleType == ConsoleType::Famicom && _expansionDevice == ExpansionPortDevice::Zapper);
1426 	}
1427 
HasArkanoidPaddle()1428 	bool HasArkanoidPaddle()
1429 	{
1430 		return _controllerTypes[0] == ControllerType::ArkanoidController || _controllerTypes[1] == ControllerType::ArkanoidController || (_consoleType == ConsoleType::Famicom && _expansionDevice == ExpansionPortDevice::ArkanoidController);
1431 	}
1432 
SetNsfConfig(int32_t autoDetectSilence,int32_t moveToNextTrackTime,bool disableApuIrqs)1433 	void SetNsfConfig(int32_t autoDetectSilence, int32_t moveToNextTrackTime, bool disableApuIrqs)
1434 	{
1435 		_nsfAutoDetectSilenceDelay = autoDetectSilence;
1436 		_nsfMoveToNextTrackTime = moveToNextTrackTime;
1437 		_nsfDisableApuIrqs = disableApuIrqs;
1438 	}
1439 
GetNsfAutoDetectSilenceDelay()1440 	int32_t GetNsfAutoDetectSilenceDelay()
1441 	{
1442 		return _nsfAutoDetectSilenceDelay;
1443 	}
1444 
GetNsfMoveToNextTrackTime()1445 	int32_t GetNsfMoveToNextTrackTime()
1446 	{
1447 		return _nsfMoveToNextTrackTime;
1448 	}
1449 
GetNsfDisableApuIrqs()1450 	bool GetNsfDisableApuIrqs()
1451 	{
1452 		return _nsfDisableApuIrqs;
1453 	}
1454 
SetInputDisplaySettings(uint8_t visiblePorts,InputDisplayPosition displayPosition,bool displayHorizontally)1455 	void SetInputDisplaySettings(uint8_t visiblePorts, InputDisplayPosition displayPosition, bool displayHorizontally)
1456 	{
1457 		_inputDisplaySettings = { visiblePorts, displayPosition, displayHorizontally };
1458 	}
1459 
GetInputDisplaySettings()1460 	InputDisplaySettings GetInputDisplaySettings()
1461 	{
1462 		return _inputDisplaySettings;
1463 	}
1464 
SetRamPowerOnState(RamPowerOnState state)1465 	void SetRamPowerOnState(RamPowerOnState state)
1466 	{
1467 		_ramPowerOnState = state;
1468 	}
1469 
GetRamPowerOnState()1470 	RamPowerOnState GetRamPowerOnState()
1471 	{
1472 		return _ramPowerOnState;
1473 	}
1474 
SetAutoSaveOptions(uint32_t delayInMinutes,bool showMessage)1475 	void SetAutoSaveOptions(uint32_t delayInMinutes, bool showMessage)
1476 	{
1477 		_autoSaveDelay = delayInMinutes;
1478 		_autoSaveNotify = showMessage;
1479 	}
1480 
GetAutoSaveDelay(bool & showMessage)1481 	uint32_t GetAutoSaveDelay(bool &showMessage)
1482 	{
1483 		showMessage = _autoSaveNotify;
1484 		return _autoSaveDelay;
1485 	}
1486 
SetDipSwitches(uint32_t dipSwitches)1487 	void SetDipSwitches(uint32_t dipSwitches)
1488 	{
1489 		_dipSwitches = dipSwitches;
1490 	}
1491 
GetDipSwitches()1492 	uint32_t GetDipSwitches()
1493 	{
1494 		return _dipSwitches;
1495 	}
1496 
IsKeyboardMode()1497 	bool IsKeyboardMode()
1498 	{
1499 		return _keyboardModeEnabled;
1500 	}
1501 
EnableKeyboardMode()1502 	void EnableKeyboardMode()
1503 	{
1504 		if(!_keyboardModeEnabled) {
1505 			_keyboardModeEnabled = true;
1506 			MessageManager::DisplayMessage("Input", "KeyboardModeEnabled");
1507 		}
1508 	}
1509 
DisableKeyboardMode()1510 	void DisableKeyboardMode()
1511 	{
1512 		if(_keyboardModeEnabled) {
1513 			_keyboardModeEnabled = false;
1514 			MessageManager::DisplayMessage("Input", "KeyboardModeDisabled");
1515 		}
1516 	}
1517 
SetPauseScreenMessage(string message)1518 	void SetPauseScreenMessage(string message)
1519 	{
1520 		_pauseScreenMessage = message;
1521 	}
1522 
GetPauseScreenMessage()1523 	string GetPauseScreenMessage()
1524 	{
1525 		return _pauseScreenMessage;
1526 	}
1527 };
1528