diff --git a/.gitignore b/.gitignore index deef6c5b0a..cebabd2c39 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ Thumbs.db # Ignore Finder view option files created by OS X .DS_Store # Ignore autogenerated source files +Externals/mGBA/version.c Source/Core/Common/scmrev.h # Ignore files output by build /[Bb]uild*/ diff --git a/.gitmodules b/.gitmodules index 7082458311..3459dd91fb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,3 +3,8 @@ url = https://github.com/dolphin-emu/ext-win-qt.git branch = master shallow = true +[submodule "Externals/mGBA/mgba"] + path = Externals/mGBA/mgba + url = https://github.com/mgba-emu/mgba.git + branch = master + shallow = true diff --git a/CMakeLists.txt b/CMakeLists.txt index a480467b3e..d446e0b465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ option(ENABLE_LLVM "Enables LLVM support, for disassembly" ON) option(ENABLE_TESTS "Enables building the unit tests" ON) option(ENABLE_VULKAN "Enables vulkan video backend" ON) option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current game on Discord" ON) +option(USE_MGBA "Enables GBA controllers emulation using libmgba" ON) # Maintainers: if you consider blanket disabling this for your users, please # consider the following points: @@ -826,6 +827,14 @@ if(USE_DISCORD_PRESENCE) include_directories(Externals/discord-rpc/include) endif() +if(NOT ENABLE_QT) + set(USE_MGBA 0) +endif() +if(USE_MGBA) + message(STATUS "Using static libmgba from Externals") + add_subdirectory(Externals/mGBA) +endif() + find_package(SYSTEMD) if(SYSTEMD_FOUND) message(STATUS "libsystemd found, enabling traversal server watchdog support") diff --git a/Externals/ExternalsReferenceAll.props b/Externals/ExternalsReferenceAll.props index 0d7de6fecd..38ec0bd827 100644 --- a/Externals/ExternalsReferenceAll.props +++ b/Externals/ExternalsReferenceAll.props @@ -58,6 +58,9 @@ {bdb6578b-0691-4e80-a46c-df21639fd3b8} + + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} + {31643fdb-1bb8-4965-9de7-000fc88d35ae} diff --git a/Externals/licenses.md b/Externals/licenses.md index f7b20041b9..716b794fb0 100644 --- a/Externals/licenses.md +++ b/Externals/licenses.md @@ -38,6 +38,8 @@ Dolphin includes or links code of the following third-party software projects: [University of Illinois/NCSA Open Source license](http://llvm.org/docs/DeveloperPolicy.html#license) - [LZO](http://www.oberhumer.com/opensource/lzo/): [GPLv2+](http://www.oberhumer.com/opensource/gpl.html) +- [mGBA](http://mgba.io) + [MPL 2.0](https://github.com/mgba-emu/mgba/blob/master/LICENSE) - [MiniUPnPc](http://miniupnp.free.fr/): [3-clause BSD](https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/LICENSE) - [Microsoft Visual C++ Runtime Library](http://www.microsoft.com/en-us/download/details.aspx?id=40784): diff --git a/Externals/mGBA/CMakeLists.txt b/Externals/mGBA/CMakeLists.txt new file mode 100644 index 0000000000..4a87c7b58c --- /dev/null +++ b/Externals/mGBA/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LIBMGBA_ONLY ON) +set(USE_LZMA ON) +add_subdirectory(mgba EXCLUDE_FROM_ALL) + +if(NOT MSVC) + target_compile_options(mgba PRIVATE -Wno-unused-parameter -Wno-unused-result -Wno-unused-variable) +endif() + +if(ANDROID) + target_compile_definitions(mgba PRIVATE -Dfutimes=futimens) +endif() + +add_library(mGBA::mgba ALIAS mgba) diff --git a/Externals/mGBA/make_version.c.js b/Externals/mGBA/make_version.c.js new file mode 100644 index 0000000000..d52d9e9a05 --- /dev/null +++ b/Externals/mGBA/make_version.c.js @@ -0,0 +1,140 @@ +var wshShell = new ActiveXObject("WScript.Shell") +var oFS = new ActiveXObject("Scripting.FileSystemObject"); + +wshShell.CurrentDirectory += "\\mgba"; +var outfile = "../version.c"; +var cmd_commit = " describe --always --abbrev=40 --dirty"; +var cmd_commit_short = " describe --always --dirty"; +var cmd_branch = " symbolic-ref --short HEAD"; +var cmd_rev = " rev-list HEAD --count"; +var cmd_tag = " describe --tag --exact-match"; + +function GetGitExe() +{ + try + { + gitexe = wshShell.RegRead("HKCU\\Software\\GitExtensions\\gitcommand"); + wshShell.Exec(gitexe); + return gitexe; + } + catch (e) + {} + + for (var gitexe in {"git.cmd":1, "git":1, "git.bat":1}) + { + try + { + wshShell.Exec(gitexe); + return gitexe; + } + catch (e) + {} + } + + // last try - msysgit not in path (vs2015 default) + msyspath = "\\Git\\cmd\\git.exe"; + gitexe = wshShell.ExpandEnvironmentStrings("%PROGRAMFILES(x86)%") + msyspath; + if (oFS.FileExists(gitexe)) { + return gitexe; + } + gitexe = wshShell.ExpandEnvironmentStrings("%PROGRAMFILES%") + msyspath; + if (oFS.FileExists(gitexe)) { + return gitexe; + } + + WScript.Echo("Cannot find git or git.cmd, check your PATH:\n" + + wshShell.ExpandEnvironmentStrings("%PATH%")); + WScript.Quit(1); +} + +function GetFirstStdOutLine(cmd) +{ + try + { + return wshShell.Exec(cmd).StdOut.ReadLine(); + } + catch (e) + { + // catch "the system cannot find the file specified" error + WScript.Echo("Failed to exec " + cmd + " this should never happen"); + WScript.Quit(1); + } +} + +function GetFileContents(f) +{ + try + { + return oFS.OpenTextFile(f).ReadAll(); + } + catch (e) + { + // file doesn't exist + return ""; + } +} + +// get version from version.cmake +var version_cmake = GetFileContents("version.cmake"); +var version_major = version_cmake.match(/set\(LIB_VERSION_MAJOR (.*)\)/)[1]; +var version_minor = version_cmake.match(/set\(LIB_VERSION_MINOR (.*)\)/)[1]; +var version_patch = version_cmake.match(/set\(LIB_VERSION_PATCH (.*)\)/)[1]; +var version_abi = version_cmake.match(/set\(LIB_VERSION_ABI (.*)\)/)[1]; +var version_string = version_major + "." + version_minor + "." + version_patch; + +// get info from git +var gitexe = GetGitExe(); +var commit = GetFirstStdOutLine(gitexe + cmd_commit); +var commit_short = GetFirstStdOutLine(gitexe + cmd_commit_short); +var branch = GetFirstStdOutLine(gitexe + cmd_branch); +var rev = GetFirstStdOutLine(gitexe + cmd_rev); +var tag = GetFirstStdOutLine(gitexe + cmd_tag); +var binary_name = "mgba"; +var project_name = "mGBA"; + +if (!rev) + rev = -1; + +if (tag) +{ + version_string = tag; +} +else if (branch) +{ + if (branch == "master") + version_string = rev + "-" + commit_short; + else + version_string = branch + "-" + rev + "-" + commit_short; + + if (branch != version_abi) + version_string = version_abi + "-" + version_string; +} + +if (!commit) + commit = "(unknown)"; +if (!commit_short) + commit_short = "(unknown)"; +if (!branch) + branch = "(unknown)"; + +var out_contents = + "#include \n" + + "MGBA_EXPORT const char* const gitCommit = \"" + commit + "\";\n" + + "MGBA_EXPORT const char* const gitCommitShort = \"" + commit_short + "\";\n" + + "MGBA_EXPORT const char* const gitBranch = \"" + branch + "\";\n" + + "MGBA_EXPORT const int gitRevision = " + rev + ";\n" + + "MGBA_EXPORT const char* const binaryName = \"" + binary_name + "\";\n" + + "MGBA_EXPORT const char* const projectName = \"" + project_name + "\";\n" + + "MGBA_EXPORT const char* const projectVersion = \"" + version_string + "\";\n"; + +// check if file needs updating +if (out_contents == GetFileContents(outfile)) +{ + WScript.Echo(project_name + ": " + outfile + " current at " + version_string); +} +else +{ + // needs updating - writeout current info + oFS.CreateTextFile(outfile, true).Write(out_contents); + WScript.Echo(project_name + ": " + outfile + " updated to " + version_string); +} diff --git a/Externals/mGBA/mgba b/Externals/mGBA/mgba new file mode 160000 index 0000000000..9cccc5197e --- /dev/null +++ b/Externals/mGBA/mgba @@ -0,0 +1 @@ +Subproject commit 9cccc5197ed73ba0a54f584d3121c27dc97405f5 diff --git a/Externals/mGBA/mgba.vcxproj b/Externals/mGBA/mgba.vcxproj new file mode 100644 index 0000000000..2338faa0d8 --- /dev/null +++ b/Externals/mGBA/mgba.vcxproj @@ -0,0 +1,241 @@ + + + + + + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} + + + + + + + + + + + + + + mgba\include;mgba\src;mgba\src\third-party\lzma;%(AdditionalIncludeDirectories) + BUILD_STATIC;M_CORE_GB;M_CORE_GBA;USE_LZMA;_7ZIP_PPMD_SUPPPORT;HAVE_STRDUP;HAVE_SETLOCALE;HAVE_CHMOD;HAVE_UMASK;%(PreprocessorDefinitions) + + + "$(CScript)" /nologo /E:JScript "make_version.c.js" + + + + + + $(IntDir)/src/core/cache-set.c.obj + + + $(IntDir)/src/core/cheats.c.obj + + + + $(IntDir)/src/core/core.c.obj + + + + $(IntDir)/src/core/input.c.obj + + + + + $(IntDir)/src/core/lockstep.c.obj + + + + + + + + $(IntDir)/src/core/serialize.c.obj + + + + + + + $(IntDir)/src/sm83/decoder.c.obj + + + + + $(IntDir)/src/gb/audio.c.obj + + + $(IntDir)/src/gb/cheats.c.obj + + + $(IntDir)/src/gb/core.c.obj + + + + $(IntDir)/src/gb/input.c.obj + + + $(IntDir)/src/gb/io.c.obj + + + + $(IntDir)/src/gb/memory.c.obj + + + $(IntDir)/src/gb/overrides.c.obj + + + $(IntDir)/src/gb/serialize.c.obj + + + $(IntDir)/src/gb/renderers/cache-set.c.obj + + + + $(IntDir)/src/gb/sio.c.obj + + + $(IntDir)/src/gb/timer.c.obj + + + $(IntDir)/src/gb/video.c.obj + + + + + $(IntDir)/src/arm/decoder.c.obj + + + + + + $(IntDir)/src/gba/audio.c.obj + + + + + + + + $(IntDir)/src/gba/cheats.c.obj + + + + + + $(IntDir)/src/gba/core.c.obj + + + + + + $(IntDir)/src/gba/input.c.obj + + + $(IntDir)/src/gba/io.c.obj + + + $(IntDir)/src/gba/memory.c.obj + + + $(IntDir)/src/gba/overrides.c.obj + + + $(IntDir)/src/gba/renderers/cache-set.c.obj + + + + + + + + + + $(IntDir)/src/gba/serialize.c.obj + + + + $(IntDir)/src/gba/sio.c.obj + + + + + $(IntDir)/src/gba/timer.c.obj + + + $(IntDir)/src/gba/video.c.obj + + + + + + + + + + + + + + + + + + + + + + + + + + + $(IntDir)/src/platform/windows/memory.c.obj + + + + + + + + + + + + + + + + + + + + + + + + + + $(IntDir)/src/gba/sio/lockstep.c.obj + + + $(IntDir)/src/gb/sio/lockstep.c.obj + + + + + + $(IntDir)/src/gba/extra/proxy.c.obj + + + $(IntDir)/src/gb/extra/proxy.c.obj + + + + + + + + + \ No newline at end of file diff --git a/Externals/mGBA/mgba.vcxproj.filters b/Externals/mGBA/mgba.vcxproj.filters new file mode 100644 index 0000000000..b5e7b0ed6a --- /dev/null +++ b/Externals/mGBA/mgba.vcxproj.filters @@ -0,0 +1,427 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Generated sources + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Windows-specific code + + + Third-party code + + + Third-party code + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Virtual files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + {57438DCC-46E8-3FBA-90F2-185F80CEBE2C} + + + {C0CFD641-7357-3B1D-B2A3-B2477AEF3147} + + + {6C07F537-79D5-3651-A634-9E523B9936B2} + + + {AFF59D0C-C624-393F-8703-2FB3784928C8} + + + {37E5D4D5-B263-3B94-8968-21228F26DF67} + + + diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index e1066f1584..765bab1bcb 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -173,6 +173,11 @@ void Host_TitleChanged() env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnTitleChanged()); } +std::unique_ptr Host_CreateGBAHost(std::weak_ptr core) +{ + return nullptr; +} + static bool MsgAlert(const char* caption, const char* text, bool yes_no, Common::MsgType style) { // If a panic alert happens very early in the execution of a game, we can crash here with diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp index cfa5383c7c..6623b5ad8b 100644 --- a/Source/Core/AudioCommon/AudioCommon.cpp +++ b/Source/Core/AudioCommon/AudioCommon.cpp @@ -68,7 +68,8 @@ void InitSoundStream() void PostInitSoundStream() { - // This needs to be called after AudioInterface::Init where input sample rates are set + // This needs to be called after AudioInterface::Init and SerialInterface::Init (for GBA devices) + // where input sample rates are set UpdateSoundStream(); SetSoundStreamRunning(true); diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index ae8ba47d00..e50d90b32b 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -47,6 +47,8 @@ void Mixer::DoState(PointerWrap& p) m_dma_mixer.DoState(p); m_streaming_mixer.DoState(p); m_wiimote_speaker_mixer.DoState(p); + for (auto& mixer : m_gba_mixers) + mixer.DoState(p); } // Executed from sound stream thread @@ -93,20 +95,24 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples, s32 lvolume = m_LVolume.load(); s32 rvolume = m_RVolume.load(); + const auto read_buffer = [this](auto index) { + return m_little_endian ? m_buffer[index] : Common::swap16(m_buffer[index]); + }; + // TODO: consider a higher-quality resampling algorithm. for (; currentSample < numSamples * 2 && ((indexW - indexR) & INDEX_MASK) > 2; currentSample += 2) { u32 indexR2 = indexR + 2; // next sample - s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); // current - s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); // next + s16 l1 = read_buffer(indexR & INDEX_MASK); // current + s16 l2 = read_buffer(indexR2 & INDEX_MASK); // next int sampleL = ((l1 << 16) + (l2 - l1) * (u16)m_frac) >> 16; sampleL = (sampleL * lvolume) >> 8; sampleL += samples[currentSample + 1]; samples[currentSample + 1] = std::clamp(sampleL, -32767, 32767); - s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); // current - s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); // next + s16 r1 = read_buffer((indexR + 1) & INDEX_MASK); // current + s16 r2 = read_buffer((indexR2 + 1) & INDEX_MASK); // next int sampleR = ((r1 << 16) + (r2 - r1) * (u16)m_frac) >> 16; sampleR = (sampleR * rvolume) >> 8; sampleR += samples[currentSample]; @@ -122,8 +128,8 @@ unsigned int Mixer::MixerFifo::Mix(short* samples, unsigned int numSamples, // Padding short s[2]; - s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]); - s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]); + s[0] = read_buffer((indexR - 1) & INDEX_MASK); + s[1] = read_buffer((indexR - 2) & INDEX_MASK); s[0] = (s[0] * rvolume) >> 8; s[1] = (s[1] * lvolume) >> 8; for (; currentSample < numSamples * 2; currentSample += 2) @@ -158,6 +164,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples) m_dma_mixer.Mix(m_scratch_buffer.data(), available_samples, false); m_streaming_mixer.Mix(m_scratch_buffer.data(), available_samples, false); m_wiimote_speaker_mixer.Mix(m_scratch_buffer.data(), available_samples, false); + for (auto& mixer : m_gba_mixers) + mixer.Mix(m_scratch_buffer.data(), available_samples, false); if (!m_is_stretching) { @@ -172,6 +180,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples) m_dma_mixer.Mix(samples, num_samples, true); m_streaming_mixer.Mix(samples, num_samples, true); m_wiimote_speaker_mixer.Mix(samples, num_samples, true); + for (auto& mixer : m_gba_mixers) + mixer.Mix(samples, num_samples, true); m_is_stretching = false; } @@ -258,14 +268,19 @@ void Mixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_sam for (unsigned int i = 0; i < num_samples; ++i) { - samples_stereo[i * 2] = Common::swap16(samples[i]); - samples_stereo[i * 2 + 1] = Common::swap16(samples[i]); + samples_stereo[i * 2] = samples[i]; + samples_stereo[i * 2 + 1] = samples[i]; } m_wiimote_speaker_mixer.PushSamples(samples_stereo, num_samples); } } +void Mixer::PushGBASamples(int device_number, const short* samples, unsigned int num_samples) +{ + m_gba_mixers[device_number].PushSamples(samples, num_samples); +} + void Mixer::SetDMAInputSampleRate(unsigned int rate) { m_dma_mixer.SetInputSampleRate(rate); @@ -276,6 +291,11 @@ void Mixer::SetStreamInputSampleRate(unsigned int rate) m_streaming_mixer.SetInputSampleRate(rate); } +void Mixer::SetGBAInputSampleRates(int device_number, unsigned int rate) +{ + m_gba_mixers[device_number].SetInputSampleRate(rate); +} + void Mixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume) { m_streaming_mixer.SetVolume(lvolume, rvolume); @@ -286,6 +306,11 @@ void Mixer::SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume) m_wiimote_speaker_mixer.SetVolume(lvolume, rvolume); } +void Mixer::SetGBAVolume(int device_number, unsigned int lvolume, unsigned int rvolume) +{ + m_gba_mixers[device_number].SetVolume(lvolume, rvolume); +} + void Mixer::StartLogDTKAudio(const std::string& filename) { if (!m_log_dtk_audio) diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 36630c7013..2a1a62ba4f 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -30,11 +30,17 @@ public: void PushStreamingSamples(const short* samples, unsigned int num_samples); void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, unsigned int sample_rate); + void PushGBASamples(int device_number, const short* samples, unsigned int num_samples); + unsigned int GetSampleRate() const { return m_sampleRate; } + void SetDMAInputSampleRate(unsigned int rate); void SetStreamInputSampleRate(unsigned int rate); + void SetGBAInputSampleRates(int device_number, unsigned int rate); + void SetStreamingVolume(unsigned int lvolume, unsigned int rvolume); void SetWiimoteSpeakerVolume(unsigned int lvolume, unsigned int rvolume); + void SetGBAVolume(int device_number, unsigned int lvolume, unsigned int rvolume); void StartLogDTKAudio(const std::string& filename); void StopLogDTKAudio(); @@ -57,7 +63,8 @@ private: class MixerFifo final { public: - MixerFifo(Mixer* mixer, unsigned sample_rate) : m_mixer(mixer), m_input_sample_rate(sample_rate) + MixerFifo(Mixer* mixer, unsigned sample_rate, bool little_endian) + : m_mixer(mixer), m_input_sample_rate(sample_rate), m_little_endian(little_endian) { } void DoState(PointerWrap& p); @@ -71,6 +78,7 @@ private: private: Mixer* m_mixer; unsigned m_input_sample_rate; + bool m_little_endian; std::array m_buffer{}; std::atomic m_indexW{0}; std::atomic m_indexR{0}; @@ -81,9 +89,11 @@ private: u32 m_frac = 0; }; - MixerFifo m_dma_mixer{this, 32000}; - MixerFifo m_streaming_mixer{this, 48000}; - MixerFifo m_wiimote_speaker_mixer{this, 3000}; + MixerFifo m_dma_mixer{this, 32000, false}; + MixerFifo m_streaming_mixer{this, 48000, false}; + MixerFifo m_wiimote_speaker_mixer{this, 3000, true}; + std::array m_gba_mixers{MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true}, + MixerFifo{this, 48000, true}, MixerFifo{this, 48000, true}}; unsigned int m_sampleRate; bool m_is_stretching = false; diff --git a/Source/Core/Common/CommonPaths.h b/Source/Core/Common/CommonPaths.h index 4afeb698a3..55ed606517 100644 --- a/Source/Core/Common/CommonPaths.h +++ b/Source/Core/Common/CommonPaths.h @@ -34,6 +34,7 @@ // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) #define GC_USER_DIR "GC" +#define GBA_USER_DIR "GBA" #define WII_USER_DIR "Wii" #define CONFIG_DIR "Config" #define GAMESETTINGS_DIR "GameSettings" @@ -61,6 +62,7 @@ #define RESOURCES_DIR "Resources" #define THEMES_DIR "Themes" #define STYLES_DIR "Styles" +#define GBASAVES_DIR "Saves" #define ANAGLYPH_DIR "Anaglyph" #define PASSIVE_DIR "Passive" #define PIPES_DIR "Pipes" @@ -119,6 +121,9 @@ #define GC_MEMCARDB "MemoryCardB" #define GC_MEMCARD_NETPLAY "NetPlayTemp" +#define GBA_BIOS "gba_bios.bin" +#define GBA_SAVE_NETPLAY "NetPlayTemp" + #define WII_STATE "state.dat" #define WII_SDCARD "sd.raw" diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index f8814b8c02..96d72a36d7 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -977,6 +977,10 @@ static void RebuildUserDirectories(unsigned int dir_index) s_user_paths[F_MEMORYWATCHERSOCKET_IDX] = s_user_paths[D_MEMORYWATCHER_IDX] + MEMORYWATCHER_SOCKET; + s_user_paths[D_GBAUSER_IDX] = s_user_paths[D_USER_IDX] + GBA_USER_DIR DIR_SEP; + s_user_paths[D_GBASAVES_IDX] = s_user_paths[D_GBAUSER_IDX] + GBASAVES_DIR DIR_SEP; + s_user_paths[F_GBABIOS_IDX] = s_user_paths[D_GBAUSER_IDX] + GBA_BIOS; + // The shader cache has moved to the cache directory, so remove the old one. // TODO: remove that someday. File::DeleteDirRecursively(s_user_paths[D_USER_IDX] + SHADERCACHE_LEGACY_DIR DIR_SEP); diff --git a/Source/Core/Common/FileUtil.h b/Source/Core/Common/FileUtil.h index c4419fb317..1a487bbe4e 100644 --- a/Source/Core/Common/FileUtil.h +++ b/Source/Core/Common/FileUtil.h @@ -59,6 +59,8 @@ enum D_BACKUP_IDX, D_RESOURCEPACK_IDX, D_DYNAMICINPUT_IDX, + D_GBAUSER_IDX, + D_GBASAVES_IDX, F_DOLPHINCONFIG_IDX, F_GCPADCONFIG_IDX, F_WIIPADCONFIG_IDX, @@ -77,6 +79,7 @@ enum F_WIISDCARD_IDX, F_DUALSHOCKUDPCLIENTCONFIG_IDX, F_FREELOOKCONFIG_IDX, + F_GBABIOS_IDX, NUM_PATH_INDICES }; diff --git a/Source/Core/Common/SCMRevGen.vcxproj b/Source/Core/Common/SCMRevGen.vcxproj index f8c9829144..938df1c6f7 100644 --- a/Source/Core/Common/SCMRevGen.vcxproj +++ b/Source/Core/Common/SCMRevGen.vcxproj @@ -35,10 +35,6 @@ - - %windir%\System32\cscript - %windir%\Sysnative\cscript - diff --git a/Source/dolphin-emu.sln b/Source/dolphin-emu.sln index 0f31f47801..1fdc7499b3 100644 --- a/Source/dolphin-emu.sln +++ b/Source/dolphin-emu.sln @@ -73,6 +73,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "..\Externals\lib EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "..\Externals\zstd\zstd.vcxproj", "{1BEA10F3-80CE-4BC4-9331-5769372CDF99}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgba", "..\Externals\mGBA\mgba.vcxproj", "{864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -349,6 +351,14 @@ Global {1BEA10F3-80CE-4BC4-9331-5769372CDF99}.Release|ARM64.Build.0 = Release|ARM64 {1BEA10F3-80CE-4BC4-9331-5769372CDF99}.Release|x64.ActiveCfg = Release|x64 {1BEA10F3-80CE-4BC4-9331-5769372CDF99}.Release|x64.Build.0 = Release|x64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Debug|ARM64.Build.0 = Debug|ARM64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Debug|x64.ActiveCfg = Debug|x64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Debug|x64.Build.0 = Debug|x64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Release|ARM64.ActiveCfg = Release|ARM64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Release|ARM64.Build.0 = Release|ARM64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Release|x64.ActiveCfg = Release|x64 + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -379,6 +389,7 @@ Global {1D8C51D2-FFA4-418E-B183-9F42B6A6717E} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} {055A775F-B4F5-4970-9240-F6CF7661F37B} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} {1BEA10F3-80CE-4BC4-9331-5769372CDF99} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} + {864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {64B0A343-3B94-4522-9C24-6937FE5EFB22}