Compare commits

...

103 Commits

Author SHA1 Message Date
Fabrice de Gans
ffa53e4706 [Test] Add tests for widgets code
This creates a vbam-wx-widgets target for the custom widgets code and
adds tests for them.
2024-05-25 17:59:23 -07:00
Fabrice de Gans
f646c3848c [Test] Change assert to custom CHECK macros
This changes the way we handle asserts to use a set of custom macros.
This greatly speeds up crashing, especially on Windows, and provides
assertions in release mode too.
2024-05-21 18:47:50 +00:00
Fabrice de Gans
09433875bc [CI] Remove workaround for MSVC CI
Upstream GitHub actions now uses a single toolchain version.
Fixes #1297
2024-05-19 16:14:22 -07:00
Fabrice de Gans
05c09ff506 [Build] Add devkitpro-based libretro targets to CI 2024-05-10 13:36:05 -07:00
Rafael Kitover
7f78fbb3c5 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-10 03:00:24 +00:00
Rafael Kitover
261e26f488 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-10 02:00:25 +00:00
Rafael Kitover
ed820708af translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-10 01:00:27 +00:00
Fabrice de Gans
5b8b6a0b47 [Test] Add tests for the EmulatedGamepad class 2024-05-09 17:48:48 -07:00
Fabrice de Gans
8809ce26b3 [Test] Add tests for the Bindings class
In addition to fixing a couple of minor bugs, this also creates some
utility functions to access the cmdtab data.

Finally, this disables tests on MSYS2 as they can be flaky.
2024-05-09 13:15:16 -07:00
Fabrice de Gans
a48625855b [Build] Share wx-related targets configuration
Breaking the main wx target down to multiple libraries had the side
effect that many build options were not properly applied to libraries.
This fixes the issue by having a common configuration function in CMake
to share most of the configuration between all of the wx-related
targets.
2024-05-09 12:28:05 -07:00
Rafael Kitover
55c1477d69 build: disable FAudio for 32 bit Windows builds
Disable FAudio for 32 bit Windows builds because it uses libraries that
Windows XP does not have.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-09 02:34:25 +00:00
Rafael Kitover
2d7a1ea25b build: fix faudio linkage regression on MSVC+vcpkg
Followup on 244149c0 (build: fix faudio static linkage, 2024-05-09)
which broke linking faudio on MSVC+vcpkg, go back to using the
FAudio::FAudio cmake target for MSVC.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-09 01:38:44 +00:00
Rafael Kitover
244149c00e build: fix faudio static linkage
Use "faudio" and dependent dlls on Windows instead of the FAudio::FAudio
cmake target, because the cmake target always links the faudio dll.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-09 01:25:05 +00:00
Fabrice de Gans
c0bcf3bfdf [Test] Add tests for many config classes
This also fixes a coupld of minor issues that were found while adding
tests.
2024-05-08 13:08:07 -07:00
Fabrice de Gans
13756bcbf9 [Test] Replace doctest with googletest
* Convert the only existing test (strutils) to googletest.
* Create a test target for vbam-wx-config.
* Add necessary fakes for the test binary.
* Add tests to CI.
2024-05-08 13:00:56 -07:00
Rafael Kitover
fc82e06270 build: do not build SDL bin on Windows or macOS
Stop enabling the SDL binary by default on Windows or macOS because it
usually only of interest to Linux users.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-08 12:53:52 +00:00
Rafael Kitover
df89beb256 build: disable gpg signatures by default
Add the GPG_SIGNATURES cmake option to control creating gpg clearsign
signatures for the translations and exe zips for UPSTREAM_RELEASE,
defaulting to OFF.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-07 02:59:17 +00:00
Rafael Kitover
82eda48e8f translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-06 06:00:30 +00:00
Rafael Kitover
b47787b317 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-06 06:00:12 +00:00
Fabrice de Gans
c9668d9a88 [config] Create the vbam-wx-config target
Circular dependencies between the config sub-module and the rest of the
wx frontend have been removed. This change separates the config code to
its own submodule.

This is a preliminary change to improve testing coverage.
2024-05-05 22:57:47 -07:00
Fabrice de Gans
90a56c6937 [config] Move strutils to src/config/
This removes circular dependencies between the main wx target and the
config/ sub-directory.
2024-05-05 21:38:14 -07:00
Fabrice de Gans
d377f7abff [CI] Install only one MSVC toolchain
A change in GitHub Actions broke our MSVC build flow due to different
toolchains being used at different steps of the build process. While the
upstream issue will eventually be fixed, we need to explicitly specify
the toolchain version for now.

Bug: #1297
2024-05-05 14:54:58 -07:00
Rafael Kitover
1fac129746 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 15:00:20 +00:00
Rafael Kitover
af7d5f7b89 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 14:00:21 +00:00
Rafael Kitover
28f7c2010b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 10:00:20 +00:00
Rafael Kitover
486330f23d Activate GitHub Sponsors
Add .github/FUNDING.yml with my username to activate GitHub Sponsors for
this repository.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 01:27:11 +00:00
Rafael Kitover
1ae78a04a8 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 00:00:26 +00:00
Rafael Kitover
c776da7120 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-05-05 00:00:08 +00:00
Fabrice de Gans
d543784a3d [UserInput] Filter key events globally
This changes key events to be filtered globally by the application,
preventing any widget from accessing them. Widgets should instead use
the new VBAM_USER_INPUT_EVENT event.

In addition, this explicitly removes accelerator handling from wxWidgets
main menu, allowing us to populate joystick options in the menu without
firing wxWidgets assertions.
2024-05-04 16:07:25 -07:00
Fabrice de Gans
902c6c8e4b [UserInput] Only process shortcut commands once
This modifies the UserInputEvent class to fire a vector of events at
once, rather than individual down/up events for each UserInput. This
simplifies handling of the global event filter and prevents the firing
of spurious events.

This also fixes a bug when pressing "Ctrl+1" would trigger the command
for both the command assigned to "Ctrl+1" and to "1". Now, only the
"Ctrl+1" command will fire.
2024-05-04 13:38:43 -07:00
Fabrice de Gans
d32be9ddbe Move cmdtab and command enable flags to config/
* Moves cmdtab to config/. This removes the dependency on the wxvbam.h
  header from the config/ directory.
* Fixes a number of issues in the shortcuts configuration window:
  * The "Remove" command was not working properly due to an incorrect
    refactor.
  * The window is now fully expandable.
2024-05-04 10:44:06 -07:00
Fabrice de Gans
b776509287 [bindings] Set default shortcut for recent file 3
This was lost in translation between 2 refactors.
2024-05-03 17:30:51 -07:00
Rafael Kitover
56eb97c846 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-29 13:00:23 +00:00
Rafael Kitover
9f46c575fd translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-29 10:00:21 +00:00
Rafael Kitover
e0402a9b0b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-28 20:00:23 +00:00
Rafael Kitover
3e30f54d5f translations: fix strings starting with lowercase
Fix translated strings that start with lowercase to start with
uppercase.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-28 19:16:26 +00:00
Rafael Kitover
d73085a88c translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-25 08:00:21 +00:00
Rafael Kitover
8eb6a6900f translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-25 04:00:20 +00:00
Rafael Kitover
3615137c12 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-24 19:00:20 +00:00
Rafael Kitover
bbd5b76f2a translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-24 02:00:25 +00:00
Rafael Kitover
bb3604f333 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-24 02:00:07 +00:00
Fabrice de Gans
18a0067ca7 [Input] Unify command handling
This unifies command handling between game and shortcut commands. Both
types of commands are now handled in a common manner and the binding
configuration is shared. In particular, this prevents assigning the same
user input (joypad or keyboard) to a game command or a shortcut command.

Bug: #745
2024-04-23 18:02:25 -07:00
Fabrice de Gans
cfdbdc4ec2 [Input] Move input configuration objects to app
Previously, some input-related configuration objects were either owned
by `gopts` or global values. This moves these objects to be owned by the
app object instead.

Rather than directly accessing the app object, other objects (like
dialogs) that need to access the input-related configuration objects are
passed a `ConfigurationObjectProvider` function. This will make it
easier to test these objects independently down the line.

Bug: #745
2024-04-23 15:38:39 -07:00
Rafael Kitover
32ca2ae42f translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-23 22:00:25 +00:00
Rafael Kitover
bad96cf91e translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-23 22:00:07 +00:00
Fabrice de Gans
62294702e4 [Input] Remove transitional key, mod, joy triplet
Originally, UserInput was built around the key, mod, joy triplet values
to maintain compatibility with other parts of the code base that made
use of these values. Since the UserInput class was introduced, all use
cases have been transitioned off these values in favor of treating the
UserInput as an abstract input.

UserInput is now a simple wrapper around either a KeyboardInput or a
JoyInput structure that only contain data pertinent to their input type.

This concludes the transition to the UserInput type.

Bug: #745
2024-04-23 14:26:59 -07:00
Rafael Kitover
72c4f33d63 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-23 19:00:27 +00:00
Rafael Kitover
3fe57f540d translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-23 19:00:07 +00:00
Fabrice de Gans
1e1a369c8d [Input] Unify UserInput event handling
This adds a custom UserInputEvent for handling joypad and keyboard input
for both accelerators and emulator control configuration.

These changes fix a number of issues with the wxWidgets implementation
of key down / up event handling. In particular, every "down" event now
has a corresponding "up" event. All of the special handling that was
done in multiple places to handle shortcuts is now done in a new class,
`UserInputEventSender`, simplifying multiple call sites.

This is another step towards complete unification of UserInput handling,
which will prevent double assignment between shortcuts and emulator
controls.

Bug: #745
2024-04-23 11:30:20 -07:00
Squall Leonhart
cc65ef2849 doc: add system requirements to README.md
Add system requirements and a link to the DirectX redist for Windows to
the README.md.
2024-04-18 09:13:39 +00:00
Fabrice de Gans
32627f6b85 [Dialogs] Save and restore dialog positions
This changes most dialogs in the wx frontend to use a common base
abstraction, `dialogs::BaseDialog`. This base class sets up common
style options for every dialog and automatically saves and restores the
dialog position.

In addition, this moves the first time show position of the dialog to be
slightly to the bottom and right of the main window, even if the main
window is on a screen other than the main screen.
2024-04-18 09:02:08 +00:00
Rafael Kitover
41952d0625 build: update macOS linker tool to 1.5
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-18 08:02:51 +00:00
Rafael Kitover
0c39a5ba7a build: override FindGettext to not update po files
Copy the cmake 3.28.3 FindGettext.cmake to cmake/ and comment out the
line that updates the po file from the pot. Because we download po files
from transifex we don't want this.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-16 22:12:46 +00:00
Rafael Kitover
1b77d6594c build: update macOS build to ffmpeg 7.0
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-16 16:59:28 +00:00
Rafael Kitover
8d08223dbc build: fix compatibility with older ffmpeg
Check LIBAVCODEC_VERSION_MAJOR and use the older channel_layout API if
it's below 60.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-16 16:19:12 +00:00
Rafael Kitover
af6028a9dd build: fix build for nix on macOS
Add the NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM env var to the macOS CI as
faudio has not been marked compatible with macOS yet.

Remove FindGettext.cmake as it is a core cmake module that is available
in the versions of cmake we support now.

Add support for nix to MacPackageManagers.cmake and add brew gettext to
CMAKE_IGNORE_PATH when not using brew. Also update the cmake style.

Add faudio, libintl and the System framework to buildInputs in
default.nix.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-16 15:30:30 +00:00
Rafael Kitover
ff3b5ee042 build: update mac link tool to 1.4
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-16 02:13:37 +00:00
Rafael Kitover
b52edf52ff build: fix building on macOS with Homebrew
Move setting up the environment for macOS Homebrew earlier in
Options.cmake, as well as finding pkgconfig.

Update gcc/clang toolchain to not pass a gcc-specific option to clang.

Add faudio to list of brew packages to get in installdeps.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-15 23:30:34 +00:00
Rafael Kitover
6766b9ca54 build: fix ffmpeg 7.x compat
Update from the channels/channel_layout API to the new ch_layout API,
assume two channel stereo always.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-15 23:28:56 +00:00
Rafael Kitover
8eae2e5b90 build: add FAudio to nix deps
Add faudio to nix dependencies for both macOS and Linux.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-14 10:15:54 +00:00
Rafael Kitover
50d17363ea build: fail finding FAudio silently
Change the find_package() call for FAudio to QUIET to not show a giant
warning when it's not available.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-14 10:09:37 +00:00
Rafael Kitover
795f25bb85 build: fix nix deps for OpenGL
Change Linux nix dependencies in default.nix for OpenGL from mesa to
libGL and libGLU, also fixing the compile error for the SDL binary.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-14 10:06:54 +00:00
Ruben
647be137f6 gba: set cpsr=spsr when switching to FIQ mode
The CPSR register needs to be restored from SPSR when switching modes.
This is currently being done for all mode switches /except/ for FIQ,
which is very likely just an oversight rather than intended behaviour.

This fixes the random crashing in OpenLara, as well as fixing random
glitching of my own project that uses FIQ mode switches. The issue
happens "at random" because it requires an interrupt to occur while in
FIQ mode, and it must also fire inside a section of code that relies on
the status flags (or the CPSR register in general): When exiting the
interrupt exception, the CPSR register is supposed to be restored from
SPSR, but this isn't being done when switching from IRQ mode back to FIQ
mode, which results in CPSR (and thus the status flags) being corrupted.
For example, SUBS r0, #1; [interrupt]; BNE 1b would trigger the bug, but
[interrupt]; SUBS r0, #1; BNE 1b wouldn't, and neither would
SUBS r0,#1; BNE 1b; [interrupt].
2024-04-12 15:49:45 +00:00
Rafael Kitover
8abe3e79da build: remove -lgcc from static link flags
Remove -lgcc from static link flags for gcc/clang, clang does not
support this and -static-libgcc is enough.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-12 15:44:27 +00:00
Rafael Kitover
710ffeb1b2 build: update mac build
Update dists for gettext and gsed to get around new compile errors from
clang.

Update SDL and ffmpeg and add FAudio.

Make some other minor adjustments for recent changes.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-10 22:52:35 +00:00
Rafael Kitover
a855ff54f4 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-10 16:00:21 +00:00
Rafael Kitover
dbb5e534e4 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-10 00:00:21 +00:00
Rafael Kitover
753956963c translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-09 07:00:21 +00:00
Rafael Kitover
b00e23f5b5 build: enable FAudio on non-Windows
Enable FAudio on non-Windows too if the cmake support is found.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-08 04:02:48 +00:00
Fabrice de Gans
8ef9a66b74 [FAudio] Switch to portable condition_variable
This removes remaining dependencies on Windows in the FAudio code by
removing the device notification code and switching to portable
`condition_variable` for the buffer end notification event.
2024-04-07 16:33:22 -07:00
Rafael Kitover
0e503a525e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-07 11:00:30 +00:00
Rafael Kitover
b4b020401c translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-07 11:00:07 +00:00
Fabrice de Gans
f4835674ed [Audio] Rework audio devices enumeration
This moves all of the audio code in the wx frontend to the
`src/wx/audio` folder and simplifies many call sites by having one
generic API to enumerate audio devices and create the audio driver.

In addition, this fixes many corner cases in device enumerations and
moves handling of the default device to the respective audio backends,
rather than pushing it to the UI.

Finally, this changes the `Sound/AudioDevice` setting to use the
underlying device ID, rather than the user-facing name.
2024-04-07 03:51:39 -07:00
Rafael Kitover
4104a3d179 build: fix codesigning Windows bins with signtool
Pass `/fd certHash /td certHash` to signtool as they are required
arguments.

signtool comes with Visual Studio and now works and we don't need to
require osslsigncode anymore.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-06 23:45:14 +00:00
Rafael Kitover
1e1ec2e330 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-06 18:00:20 +00:00
Rafael Kitover
ff21f8da21 build: enable FAudio sound driver on Windows
Enable FAudio on Windows if cmake can find it.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-06 11:22:20 +00:00
Rafael Kitover
775a571f75 build: fix detecting Visual Studio default vcpkg
Make the regular expression against VCPKG_ROOT less specific for
detecting the default Visual Studio vcpkg, for some reason it stopped
working.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-06 11:09:34 +00:00
Fabrice de Gans
64abd3e8dc [Audio] Remove manual memory allocations
* Remove explicit calls to new or malloc in favor of owned objects.
* Move AudioSdl to the sdl frontend, it is no longer used by the wx
  frontend.
2024-04-06 03:42:33 -07:00
Rafael Kitover
56320ec6d1 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-06 08:00:20 +00:00
Zach Bacon
311b232ee5 FAudio: Implement and have functional FAudio output
Corrected the current FAudio output code, FAudio api wasn't
a direct 1 for 1 code replacement. Adjusted the existing
code structure so that FAudioVoiceCallBack struct
was being properly called on.

Signed-off-by: Zach Bacon <zachbacon@vba-m.com>
2024-04-05 15:37:39 -07:00
Rafael Kitover
0e13cc9346 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-05 02:00:21 +00:00
Rafael Kitover
b455de01c6 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-04 22:00:27 +00:00
Rafael Kitover
c3053d3819 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-04 22:00:08 +00:00
Fabrice de Gans
c8106573d8 [Dialogs] Move SoundConfig dialog to its own class
This fixes a number of issues with the current implementation. Namely,
some options were not properly saved and the audio driver was not
properly reloaded when some options were changed.
In addition, this moves most sound-related options to `g_owned_opts` and
simplifies many call sites.
2024-04-04 14:22:23 -07:00
Fabrice de Gans
047ad27777 [Dialogs] Prevent viewers from causing a crash
Some of the viewers dialogs were not properly set up and were causing a
crash at runtime.
2024-04-04 12:10:44 -07:00
Rafael Kitover
ecd16a21dc translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-03 14:00:25 +00:00
Rafael Kitover
1594fda1b6 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-03 13:00:22 +00:00
Rafael Kitover
de9b3a211b translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-03 12:00:22 +00:00
Rafael Kitover
045c98d8fa build: only use -Werror=lto-type-mismatch on gcc
Only pass -Werror=lto-type-mismatch to gcc, clang does not have this
option and throws a warning.

Also quote some barewords in if() statements.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-03 10:30:04 +00:00
Fabrice de Gans
4ace296b3a [Build] Improve the TRANSLATIONS_ONLY build speed
* Move CMake dependencies checkout to `cmake/Dependencies.cmake`.
* Disable most dependencies checkout from the `TRANSLATIONS_ONLY` build.
* Remove the debug/translations_only GitHub Action.
2024-04-02 11:56:19 -07:00
Rafael Kitover
011adce23e translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-02 17:00:21 +00:00
Rafael Kitover
cc99ec0c14 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-02 13:00:37 +00:00
Rafael Kitover
1d652edf83 translations: rebuild source .pot
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-02 13:00:07 +00:00
Fabrice de Gans
db08ca93af [Build] Improve CI build coverage
This reworks the CI coverage to add `TRANSLATIONS_ONLY=ON` and libretro
builds to GitHub Actions.
2024-04-01 23:28:20 -07:00
Rafael Kitover
3518dc6a05 build: fix LTO on Linux
Add -Werror=odr -Werror=lto-type-mismatch -Werror=strict-aliasing to
compile and link options for gcc/clang always.

Rename struct yy_buffer_state in src/sdl/expr-lex.cpp to struct
yy_buffer_state_sdl because it breaks when linking the SDL binary with
-Werror=odr.

Fix #1260

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-01 21:40:35 -07:00
Rafael Kitover
cc9a03ce48 Add toggle: SDL GameController mode for joysticks
Add a toggle for SDL GameController Mode in the game key configuration
dialog, default enabled.

On check or uncheck, change the option and reinitialize joysticks, not
using GameController mode if it is disabled.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-01 21:21:53 -07:00
Fabrice de Gans
8576733c0d [Build] Remove lingering references to OpenAl
OpenAl is now required to build.
2024-04-01 21:14:51 -07:00
Rafael Kitover
c6da7e384e build: add faudio to list of optional vcpkg deps
Add faudio to list of optional vcpkg deps linked to ENABLE_FAUDIO.

This codepath is not used right now as we are using binary packages.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-04-01 14:17:48 +00:00
Rafael Kitover
98abb8c2e8 translations: transifex pull
Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-03-31 02:00:22 +00:00
Rafael Kitover
0556192238 build: fix MSYS2 check
Fix cmake logic for detecting MSYS2 "$ENV{MSYSTEM_PREFIX}".

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-03-31 01:16:36 +00:00
Rafael Kitover
d9432ebb14 build: fix build on MINGW{64,32}/UCRT64 on MSYS2
Pass -Wno-deprecated-copy only for C++, gcc gives a warning for C.

Pass -Wno-unused-command-line-argument for clang only, gcc gives a
warning about it.

Add a failsafe for gcc/clang static link flags if libstdc++ or
libpthread is not available as a static library.

Move link command adjustment script invocations to src/wx, the target is
not yet defined in the toolchain.

Add -lws2_32 to the end of the link command for gcc on Windows because
of link order issues with those symbols.

Disable LTO for gcc on Windows, as it is broken.

Don't install extra-cmake-modules on MINGW32, that package is not
available there.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-03-30 20:14:32 +00:00
Rafael Kitover
f57cad67c4 build: fix static linking on MSYS2 CLANG64
Bring back setting the MSYS variable under MSYS2, it's still being used
in a few places.

Link the SDL2::SDL2-static target for static builds.

Add -static-libgcc and -static-libstdc++ to the gcc/clang toolchain for
static builds.

Edit wxWidgets_LIBRARIES under MSYS2 to specify liblzma.a explicitly
because for some reason it's not being linked statically by default for
static builds.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-03-30 18:06:25 +00:00
Rafael Kitover
ce7cc4e223 build: add FAudio to MSYS2 deps
In preparation for FAudio support, add the dependency to ./installdeps
for MSYS2 toolchains.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
2024-03-30 17:37:20 +00:00
213 changed files with 49220 additions and 42985 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: rkitover

33
.github/workflows/devkitpro-build.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Libretro Devkitpro
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
target_name: [ngc, wii, wiiu, switch]
build_type: [release, debug]
include:
- libretro_build: 'DEBUG=0'
build_type: release
- libretro_build: 'DEBUG=1'
build_type: debug
- devkit_container: 'devkitpro/devkitppc:latest'
target_name: ngc
- devkit_container: 'devkitpro/devkitppc:latest'
target_name: wii
- devkit_container: 'devkitpro/devkitppc:latest'
target_name: wiiu
- devkit_container: 'devkitpro/devkita64:latest'
target_name: switch
runs-on: ubuntu-latest
container: ${{ matrix.devkit_container }}
steps:
- name: Checkout the code
uses: actions/checkout@v4
with:
submodules: recursive
# Libretro build
- name: Build libretro core
run: make -C src/libretro ${{ matrix.libretro_build }} platform=${{ matrix.target_name }}

View File

@@ -1,27 +1,63 @@
name: macOS Latest Build
name: macOS Latest
on: [push, pull_request]
#on: workflow_dispatch
jobs:
build:
strategy:
matrix:
cmake_build: ['-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_BUILD_TYPE=Debug']
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
build_type: [release, debug]
build_options: [default, link_off, translations_only, libretro]
include:
- cmake_build: '-DCMAKE_BUILD_TYPE=Release'
build_type: release
- cmake_build: '-DCMAKE_BUILD_TYPE=Debug'
build_type: debug
- cmake_options: '-DENABLE_LINK=OFF'
build_options: link_off
- cmake_options: '-DTRANSLATIONS_ONLY=ON'
build_options: translations_only
- libretro_build: 'DEBUG=0'
build_type: release
build_options: libretro
- libretro_build: 'DEBUG=1'
build_type: debug
build_options: libretro
exclude:
# Exclude debug/translations_only build
- build_type: debug
build_options: translations_only
runs-on: macos-latest
env:
NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM: 1
steps:
- name: Checkout the code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install nix
uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-unstable
- name: Configure
# Cmake build
- if: matrix.build_options != 'libretro'
name: Configure CMake
run: >-
nix-shell --command 'cmake -B build -G Ninja ${{ matrix.cmake_build }} -DENABLE_LTO=OFF ${{ matrix.cmake_options }}'
- name: Build
- if: matrix.build_options != 'libretro'
name: Build
run: >-
nix-shell --command 'ninja -C build'
# Libretro build
- if: matrix.build_options == 'libretro'
name: Build libretro core
run: >-
nix-shell --command 'make -C src/libretro ${{ matrix.libretro_build }}'
# Run tests
- if: matrix.build_options == 'default'
name: Run tests
run: >-
nix-shell --command 'cd build && ctest -j --output-on-failure'

View File

@@ -1,12 +1,31 @@
name: MSYS2 Build
name: MSYS2
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
cmake_build: ['-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_BUILD_TYPE=Debug']
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
build_type: [release, debug]
build_options: [default, link_off, translations_only, libretro]
include:
- cmake_build: '-DCMAKE_BUILD_TYPE=Release'
build_type: release
- cmake_build: '-DCMAKE_BUILD_TYPE=Debug'
build_type: debug
- cmake_options: '-DENABLE_LINK=OFF'
build_options: link_off
- cmake_options: '-DTRANSLATIONS_ONLY=ON'
build_options: translations_only
- libretro_build: 'DEBUG=0'
build_type: release
build_options: libretro
- libretro_build: 'DEBUG=1'
build_type: debug
build_options: libretro
exclude:
# Exclude debug/translations_only build
- build_type: debug
build_options: translations_only
runs-on: windows-latest
env:
MSYSTEM: CLANG64
@@ -16,7 +35,7 @@ jobs:
steps:
- name: Checkout the code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup msys2
@@ -27,11 +46,19 @@ jobs:
- name: Install deps
run: >-
bash installdeps
- name: Configure
run: >-
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug ${{ matrix.cmake_build }} ${{ matrix.cmake_options }}
- name: Build
run: ninja -C build
- name: Install
# CMake build
- if: matrix.build_options != 'libretro'
name: Configure CMake
run: cmake -B build -G Ninja ${{ matrix.cmake_build }} -DENABLE_LTO=OFF ${{ matrix.cmake_options }}
- if: matrix.build_options != 'libretro'
name: Build
run: ninja -C build
- if: matrix.build_options != 'libretro'
name: Install
run: ninja -C build install
# Libretro build
- if: matrix.build_options == 'libretro'
name: Build libretro core
run: make -C src/libretro ${{ matrix.libretro_build }} CC=clang CXX=clang++

View File

@@ -1,30 +1,71 @@
name: Ubuntu Latest Build
name: Ubuntu Latest
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
cmake_compiler: ['-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++', '-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++']
cmake_build: ['-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_BUILD_TYPE=Debug']
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
build_compiler: [gcc, clang]
build_type: [release, debug]
build_options: [default, link_off, translations_only, libretro]
include:
- cmake_compiler: '-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++'
build_compiler: gcc
- cmake_compiler: '-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++'
build_compiler: clang
- cmake_build: '-DCMAKE_BUILD_TYPE=Release'
build_type: release
- cmake_build: '-DCMAKE_BUILD_TYPE=Debug'
build_type: debug
- cmake_options: '-DENABLE_LINK=OFF'
build_options: link_off
- cmake_options: '-DTRANSLATIONS_ONLY=ON'
build_options: translations_only
- libretro_build: 'DEBUG=0'
build_type: release
build_options: libretro
- libretro_build: 'DEBUG=1'
build_type: debug
build_options: libretro
exclude:
# Exclude debug/translations_only build
- build_type: debug
build_options: translations_only
- build_type: release
build_options: translations_only
build_compiler: clang
runs-on: ubuntu-latest
steps:
- name: Checkout the code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Dependencies
run: >-
bash installdeps; if [ "${{ matrix.compiler }}" = clang ]; then sudo apt -y install clang; fi
bash installdeps; if [ "${{ matrix.build_compiler }}" = clang ]; then sudo apt -y install clang; fi
- name: Configure
- name: Install xvfb
run: sudo apt -y install xvfb
# CMake build
- if: matrix.build_options != 'libretro'
name: Configure CMake
run: >-
cmake -B build -G Ninja ${{ matrix.cmake_compiler }} ${{ matrix.cmake_build }} ${{ matrix.cmake_options }}
- name: Build
- if: matrix.build_options != 'libretro'
name: Build
run: ninja -C build
- name: Install
- if: matrix.build_options != 'libretro'
name: Install
run: sudo ninja -C build install
# Libretro build
- if: matrix.build_options == 'libretro'
name: Build libretro core
run: make -C src/libretro ${{ matrix.libretro_build }}
# Run tests
- if: matrix.build_options == 'default'
name: Run tests
run: cd build && xvfb-run ctest -j --output-on-failure

View File

@@ -1,36 +1,60 @@
name: Visual Studio Build
name: Visual Studio
on: [push, pull_request]
jobs:
build:
strategy:
matrix:
msvc_arch: ['x64', 'x64_x86']
msvc_arch: ['x64', 'amd64_x86', 'amd64_arm64']
# TODO: Re-add "Visual Studio 17 2022" once it's working.
cmake_generator: ['Ninja']
# cmake_generator: ['Ninja', '"Visual Studio 17 2022"']
cmake_build: ['-DCMAKE_BUILD_TYPE=Release', '-DCMAKE_BUILD_TYPE=Debug']
cmake_options: ['', '-DENABLE_LINK=OFF', '-DENABLE_SDL=ON']
build_type: [release, debug]
build_options: [default, link_off, translations_only]
include:
- cmake_build: '-DCMAKE_BUILD_TYPE=Release'
build_type: release
- cmake_build: '-DCMAKE_BUILD_TYPE=Debug'
build_type: debug
- cmake_options: '-DENABLE_LINK=OFF'
build_options: link_off
- cmake_options: '-DTRANSLATIONS_ONLY=ON'
build_options: translations_only
- cmake_vcpkg_triplet: 'x64-windows-static'
msvc_arch: x64
- cmake_vcpkg_triplet: 'x86-windows-static'
msvc_arch: amd64_x86
- cmake_vcpkg_triplet: 'arm64-windows-static'
msvc_arch: amd64_arm64
exclude:
# Exclude debug/translations_only build
- build_type: debug
build_options: translations_only
- build_type: release
build_options: translations_only
msvc_arch: amd64_x86
- build_type: release
build_options: translations_only
msvc_arch: amd64_arm64
runs-on: windows-latest
steps:
- name: Checkout the code
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
submodules: recursive
- name: Prepare Visual Studio environment
uses: ilammy/msvc-dev-cmd@v1.12.0
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: ${{ matrix.msvc_arch }}
- name: Configure (x64)
if: matrix.msvc_arch == 'x64'
- name: Configure
run: >-
cmake -B build -G ${{ matrix.cmake_generator }} -DVCPKG_TARGET_TRIPLET=x64-windows-static ${{ matrix.cmake_build }} ${{ matrix.cmake_options }}
- name: Configure (x86)
if: matrix.msvc_arch == 'x64_x86'
run: >-
cmake -B build -G ${{ matrix.cmake_generator }} -DVCPKG_TARGET_TRIPLET=x86-windows-static ${{ matrix.cmake_build }} ${{ matrix.cmake_options }}
cmake -B build -G ${{ matrix.cmake_generator }} -DVCPKG_TARGET_TRIPLET=${{ matrix.cmake_vcpkg_triplet }} ${{ matrix.cmake_build }} ${{ matrix.cmake_options }}
- name: Build
run: cmake --build build
# Run tests
- if: matrix.build_options == 'default' && matrix.msvc_arch != 'amd64_arm64'
name: Run tests
run: cd build && ctest -j --output-on-failure

View File

@@ -20,6 +20,7 @@ set(VCPKG_DEPS pkgconf zlib pthreads "sdl2[samplerate]" gettext wxwidgets)
set(VCPKG_DEPS_OPTIONAL
sfml ENABLE_LINK
ffmpeg ENABLE_FFMPEG
faudio ENABLE_FAUDIO
)
if(WIN32)
@@ -49,7 +50,7 @@ endif()
find_package(Git)
# Make sure we pull in the submodules on windows and mingw.
if(GIT_FOUND AND (WIN32 OR MINGW))
if(GIT_FOUND AND WIN32)
# Win32 deps submodule
set(SUBMODULE_MANUAL_UPDATE FALSE)
@@ -76,7 +77,25 @@ set(CMAKE_C_STANDARD_REQUIRED True)
project(VBA-M C CXX)
find_package(PkgConfig)
include(CTest)
include(FetchContent)
include(GNUInstallDirs)
include(Architecture)
include(Options)
include(Toolchain)
include(Dependencies)
# Configure gtest
if(BUILD_TESTING)
FetchContent_Declare(googletest
URL https://github.com/google/googletest/archive/2d16ed055d09c3689d44b272adc097393de948a0.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
endif()
if(NOT CMAKE_PREFIX_PATH AND (NOT ("$ENV{CMAKE_PREFIX_PATH}" STREQUAL "")))
set(CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}")
@@ -93,34 +112,9 @@ if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO "Debug")
endif()
include(CTest)
if(BUILD_TESTING)
enable_testing()
endif()
include(GNUInstallDirs)
include(Options)
include(Architecture)
include(Toolchain)
#Output all binaries at top level
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
if(NOT HTTPS)
add_compile_definitions(NO_HTTPS)
endif()
if(ENABLE_GBA_LOGGING)
add_compile_definitions(GBA_LOGGING )
endif()
if(ENABLE_MMX)
add_compile_definitions(MMX)
endif()
# The SDL port can't be built without debugging support
if(NOT ENABLE_DEBUGGER AND ENABLE_SDL)
message(SEND_ERROR "The SDL port can't be built without debugging support")
set(MSYS OFF)
if(NOT "$ENV{MSYSTEM_PREFIX}" STREQUAL "")
set(MSYS ON)
endif()
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
@@ -179,155 +173,8 @@ if(NOT VBAM_VERSION)
changelog_version(VBAM_VERSION VBAM_REVISION VBAM_VERSION_RELEASE)
endif()
# We do not support amd64 asm yet
if(X86_64 AND (ENABLE_ASM_CORE OR ENABLE_ASM_SCALERS OR ENABLE_MMX))
message(FATAL_ERROR "The options ASM_CORE, ASM_SCALERS and MMX are not supported on X86_64 yet.")
endif()
# Look for some dependencies using CMake scripts
find_package(ZLIB REQUIRED)
set(OpenGL_GL_PREFERENCE GLVND)
if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
set(OpenGL_GL_PREFERENCE LEGACY)
endif()
find_package(OpenGL REQUIRED)
find_package(SDL2 REQUIRED)
# Add libsamplerate to SDL2 with vcpkg
unset(SDL2_LIBRARY_TEMP)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
if(WIN32)
unset(arch_suffix)
unset(path_prefix)
if(VCPKG_TARGET_TRIPLET MATCHES -static)
set(arch_suffix -static)
endif()
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
set(path_prefix debug)
endif()
set(installed_prefix ${_VCPKG_INSTALLED_DIR}/${WINARCH}-windows${arch_suffix}/${path_prefix})
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${installed_prefix}/lib/samplerate.lib)
else()
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} -lsamplerate)
endif()
endif()
set(VBAM_SDL2_LIBS SDL2::SDL2 ${SDL2_LIBRARY_TEMP})
set(VBAM_GENERATED_DIR ${CMAKE_BINARY_DIR}/generated)
# Set up "src" and generated directory as a global include directory.
include_directories(
${CMAKE_SOURCE_DIR}/src
${VBAM_GENERATED_DIR}
)
if(ENABLE_FFMPEG)
if(NOT FFMPEG_LIBRARIES)
message(FATAL_ERROR "ENABLE_FFMPEG was specified, but required versions of ffmpeg libraries cannot be found!")
endif()
if(APPLE)
list(APPEND FFMPEG_LDFLAGS "SHELL:-framework CoreText" "SHELL:-framework ApplicationServices")
if(UPSTREAM_RELEASE)
list(APPEND FFMPEG_LDFLAGS -lbz2 -ltiff "SHELL:-framework DiskArbitration" -lfreetype -lfontconfig -llzma -lxml2 -lharfbuzz)
endif()
elseif(WIN32)
set(WIN32_MEDIA_FOUNDATION_LIBS dxva2 evr mf mfplat mfplay mfreadwrite mfuuid amstrmid)
list(APPEND FFMPEG_LIBRARIES secur32 bcrypt ${WIN32_MEDIA_FOUNDATION_LIBS})
if(MSYS AND VBAM_STATIC)
foreach(lib tiff jbig lzma)
cygpath(lib "$ENV{MSYSTEM_PREFIX}/lib/lib${lib}.a")
list(APPEND FFMPEG_LIBRARIES "${lib}")
endforeach()
endif()
endif()
else()
add_compile_definitions(NO_FFMPEG)
endif()
if(NOT ENABLE_ONLINEUPDATES)
add_compile_definitions(NO_ONLINEUPDATES)
endif()
# C defines
add_compile_definitions(HAVE_NETINET_IN_H HAVE_ARPA_INET_H HAVE_ZLIB_H FINAL_VERSION SDL USE_OPENGL SYSCONF_INSTALL_DIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}")
add_compile_definitions(PKGDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/vbam")
add_compile_definitions(__STDC_FORMAT_MACROS)
if(ENABLE_LINK)
# IPC linking code needs sem_timedwait which can be either in librt or pthreads
if(NOT WIN32)
find_library(RT_LIB rt)
if(RT_LIB)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${RT_LIB})
set(VBAMCORE_LIBS ${VBAMCORE_LIBS} ${RT_LIB})
endif()
endif()
include(CheckFunctionExists)
check_function_exists(sem_timedwait SEM_TIMEDWAIT)
if(SEM_TIMEDWAIT)
add_compile_definitions(HAVE_SEM_TIMEDWAIT)
endif()
else()
add_compile_definitions(NO_LINK)
endif()
# The debugger is enabled by default
if(ENABLE_DEBUGGER)
add_compile_definitions(VBAM_ENABLE_DEBUGGER)
endif()
# The ASM core is disabled by default because we don't know on which platform we are
if(NOT ENABLE_ASM_CORE)
add_compile_definitions(C_CORE)
endif()
# Enable internationalization
set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale)
add_compile_definitions(LOCALEDIR="${LOCALEDIR}")
# for now, only GBALink.cpp uses gettext() directly
if(APPLE)
# use Homebrew gettext if available
if(EXISTS "/usr/local/opt/gettext")
set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/usr/local/opt/gettext/include")
set(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/usr/local/opt/gettext/lib")
set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/usr/local/opt/gettext/bin")
endif()
endif()
if(ENABLE_LINK OR ENABLE_WX)
find_path(LIBINTL_INC libintl.h)
find_library(LIBINTL_LIB NAMES libintl intl)
find_library(LIBICONV_LIB NAMES libiconv iconv)
find_library(LIBCHARSET_LIB NAMES libcharset charset)
if(LIBINTL_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBINTL_LIB})
list(APPEND NLS_LIBS ${LIBINTL_LIB})
endif()
if(LIBICONV_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBICONV_LIB})
list(APPEND NLS_LIBS ${LIBICONV_LIB})
endif()
if(LIBCHARSET_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_LIB})
list(APPEND NLS_LIBS ${LIBCHARSET_LIB})
endif()
include(CheckFunctionExists)
check_function_exists(gettext GETTEXT_FN)
if(NOT (LIBINTL_INC OR GETTEXT_FN))
message(FATAL_ERROR "NLS requires libintl/gettext")
endif()
endif()
if(NOT TRANSLATIONS_ONLY)
add_subdirectory(third_party/include/nonstd)

View File

@@ -3,6 +3,7 @@
- [Visual Boy Advance - M](#visual-boy-advance---m)
- [System Requirements](#system-requirements)
- [Building](#building)
- [Building a Libretro core](#building-a-libretro-core)
- [Visual Studio Support](#visual-studio-support)
@@ -56,6 +57,17 @@ the `translations.zip` to the same directory as the executable.
If you are having issues, try resetting the config file first, go to `Help ->
Factory Reset`.
## System Requirements
Windows 7, 8.1 or 10/11, Linux distro's or macOS.
2Ghz x86(or x86-64) Intel Core 2 or AMD Athlon processor with SSE, Snapdragon 835
or newer cpu compatible with Arm for Windows.
- Just a guideline, lower clock speeds and Celeron processors may be able to run at full
speed on lower settings, and Linux based ARM Operating systems have wider cpu support.
DirectX June 2010 Redist [Full](https://www.microsoft.com/en-au/download/details.aspx?id=8109) / [Websetup](https://www.microsoft.com/en-au/download/details.aspx?id=35) for Xaudio (Remember to uncheck Bing on the websetup)
## Building
The basic formula to build vba-m is:
@@ -217,7 +229,6 @@ Here is the complete list:
| ENABLE_GBA_LOGGING | Enable extended GBA logging | ON |
| ENABLE_DIRECT3D | Direct3D rendering for wxWidgets (Windows, **NOT IMPLEMENTED!!!**) | ON |
| ENABLE_XAUDIO2 | Enable xaudio2 sound output for wxWidgets (Windows only) | ON |
| ENABLE_OPENAL | Enable OpenAL for the wxWidgets port | AUTO |
| ENABLE_ASAN | Enable libasan sanitizers (by default address, only in debug mode) | OFF |
| UPSTREAM_RELEASE | Do some release tasks, like codesigning, making zip and gpg sigs. | OFF |
| BUILD_TESTING | Build the tests and enable ctest support. | ON |

View File

@@ -1,3 +1,7 @@
if(TRANSLATIONS_ONLY)
return()
endif()
if(NOT CMAKE_SYSTEM_PROCESSOR)
if(NOT CMAKE_TOOLCHAIN_FILE AND CMAKE_HOST_SYSTEM_PROCESSOR)
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
@@ -63,3 +67,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "[aA][aA][rR][cC][hH]|[aA][rR][mM]")
set(CMAKE_CROSSCOMPILING TRUE)
endif()
endif()
# We do not support amd64 asm yet
if(X86_64 AND (ENABLE_ASM_CORE OR ENABLE_ASM_SCALERS OR ENABLE_MMX))
message(FATAL_ERROR "The options ASM_CORE, ASM_SCALERS and MMX are not supported on X86_64 yet.")
endif()

122
cmake/Dependencies.cmake Normal file
View File

@@ -0,0 +1,122 @@
if(TRANSLATIONS_ONLY)
return()
endif()
# Look for some dependencies using CMake scripts
find_package(ZLIB REQUIRED)
set(OpenGL_GL_PREFERENCE GLVND)
if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
set(OpenGL_GL_PREFERENCE LEGACY)
endif()
find_package(OpenGL REQUIRED)
find_package(SDL2 REQUIRED)
# Add libsamplerate to SDL2 with vcpkg
unset(SDL2_LIBRARY_TEMP)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
if(WIN32)
unset(arch_suffix)
unset(path_prefix)
if(VCPKG_TARGET_TRIPLET MATCHES -static)
set(arch_suffix -static)
endif()
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
set(path_prefix debug)
endif()
set(installed_prefix ${_VCPKG_INSTALLED_DIR}/${WINARCH}-windows${arch_suffix}/${path_prefix})
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${installed_prefix}/lib/samplerate.lib)
else()
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} -lsamplerate)
endif()
endif()
if(VBAM_STATIC)
set(VBAM_SDL2_LIBS SDL2::SDL2-static ${SDL2_LIBRARY_TEMP})
else()
set(VBAM_SDL2_LIBS SDL2::SDL2 ${SDL2_LIBRARY_TEMP})
endif()
if(ENABLE_FFMPEG)
if(NOT FFMPEG_LIBRARIES)
message(FATAL_ERROR "ENABLE_FFMPEG was specified, but required versions of ffmpeg libraries cannot be found!")
endif()
if(APPLE)
list(APPEND FFMPEG_LDFLAGS "SHELL:-framework CoreText" "SHELL:-framework ApplicationServices")
if(UPSTREAM_RELEASE)
list(APPEND FFMPEG_LDFLAGS -lbz2 -ltiff "SHELL:-framework DiskArbitration" -lfreetype -lfontconfig -llzma -lxml2 -lharfbuzz)
endif()
elseif(WIN32)
set(WIN32_MEDIA_FOUNDATION_LIBS dxva2 evr mf mfplat mfplay mfreadwrite mfuuid amstrmid)
list(APPEND FFMPEG_LIBRARIES secur32 bcrypt ${WIN32_MEDIA_FOUNDATION_LIBS})
if(MSYS AND VBAM_STATIC)
foreach(lib tiff jbig lzma)
cygpath(lib "$ENV{MSYSTEM_PREFIX}/lib/lib${lib}.a")
list(APPEND FFMPEG_LIBRARIES "${lib}")
endforeach()
endif()
endif()
else()
add_compile_definitions(NO_FFMPEG)
endif()
if(ENABLE_LINK)
# IPC linking code needs sem_timedwait which can be either in librt or pthreads
if(NOT WIN32)
find_library(RT_LIB rt)
if(RT_LIB)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${RT_LIB})
set(VBAMCORE_LIBS ${VBAMCORE_LIBS} ${RT_LIB})
endif()
endif()
include(CheckFunctionExists)
check_function_exists(sem_timedwait SEM_TIMEDWAIT)
if(SEM_TIMEDWAIT)
add_compile_definitions(HAVE_SEM_TIMEDWAIT)
endif()
else()
add_compile_definitions(NO_LINK)
endif()
# for now, only GBALink.cpp uses gettext() directly
if(APPLE)
# use Homebrew gettext if available
if(EXISTS "/usr/local/opt/gettext")
set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH};/usr/local/opt/gettext/include")
set(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH};/usr/local/opt/gettext/lib")
set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};/usr/local/opt/gettext/bin")
endif()
endif()
if(ENABLE_LINK OR ENABLE_WX)
find_path(LIBINTL_INC libintl.h)
find_library(LIBINTL_LIB NAMES libintl intl)
find_library(LIBICONV_LIB NAMES libiconv iconv)
find_library(LIBCHARSET_LIB NAMES libcharset charset)
if(LIBINTL_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBINTL_LIB})
list(APPEND NLS_LIBS ${LIBINTL_LIB})
endif()
if(LIBICONV_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBICONV_LIB})
list(APPEND NLS_LIBS ${LIBICONV_LIB})
endif()
if(LIBCHARSET_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${LIBCHARSET_LIB})
list(APPEND NLS_LIBS ${LIBCHARSET_LIB})
endif()
include(CheckFunctionExists)
check_function_exists(gettext GETTEXT_FN)
if(NOT (LIBINTL_INC OR GETTEXT_FN))
message(FATAL_ERROR "NLS requires libintl/gettext")
endif()
endif()

View File

@@ -1,231 +1,232 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindGettext
# -----------
#
# Find GNU gettext tools
#
# This module looks for the GNU gettext tools. This module defines the
# following values:
#
# ::
#
# GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
# GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
# GETTEXT_FOUND: True if gettext has been found.
# GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8)
#
#
#
# Additionally it provides the following macros:
#
# GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN )
#
# ::
#
# This will create a target "translations" which will convert the
# given input po files into the binary output mo file. If the
# ALL option is used, the translations will also be created when
# building the default target.
#
# GETTEXT_PROCESS_POT_FILE( <potfile> [ALL] [INSTALL_DESTINATION <destdir>]
# LANGUAGES <lang1> <lang2> ... )
#
# ::
#
# Process the given pot file to mo files.
# If INSTALL_DESTINATION is given then automatically install rules will
# be created, the language subdirectory will be taken into account
# (by default use share/locale/).
# If ALL is specified, the pot file is processed when building the all traget.
# It creates a custom target "potfile".
#
# GETTEXT_PROCESS_PO_FILES( <lang> [ALL] [INSTALL_DESTINATION <dir>]
# PO_FILES <po1> <po2> ... )
#
# ::
#
# Process the given po files to mo files for the given language.
# If INSTALL_DESTINATION is given then automatically install rules will
# be created, the language subdirectory will be taken into account
# (by default use share/locale/).
# If ALL is specified, the po files are processed when building the all traget.
# It creates a custom target "pofiles".
#
# .. note::
# If you wish to use the Gettext library (libintl), use :module:`FindIntl`.
#[=======================================================================[.rst:
FindGettext
-----------
Find GNU gettext tools
This module looks for the GNU gettext tools. This module defines the
following values:
::
GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
GETTEXT_FOUND: True if gettext has been found.
GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8)
Additionally it provides the following macros:
GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN )
::
This will create a target "translations" which will convert the
given input po files into the binary output mo file. If the
ALL option is used, the translations will also be created when
building the default target.
GETTEXT_PROCESS_POT_FILE( <potfile> [ALL] [INSTALL_DESTINATION <destdir>]
LANGUAGES <lang1> <lang2> ... )
::
Process the given pot file to mo files.
If INSTALL_DESTINATION is given then automatically install rules will
be created, the language subdirectory will be taken into account
(by default use share/locale/).
If ALL is specified, the pot file is processed when building the all target.
It creates a custom target "potfile".
GETTEXT_PROCESS_PO_FILES( <lang> [ALL] [INSTALL_DESTINATION <dir>]
PO_FILES <po1> <po2> ... )
::
Process the given po files to mo files for the given language.
If INSTALL_DESTINATION is given then automatically install rules will
be created, the language subdirectory will be taken into account
(by default use share/locale/).
If ALL is specified, the po files are processed when building the all target.
It creates a custom target "pofiles".
.. versionadded:: 3.2
If you wish to use the Gettext library (libintl), use :module:`FindIntl`.
#]=======================================================================]
find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
if(GETTEXT_MSGMERGE_EXECUTABLE)
execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
OUTPUT_VARIABLE gettext_version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
if (gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
endif()
unset(gettext_version)
unset(msgmerge_name)
unset(msgmerge_namewe)
get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
if (gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
endif()
unset(gettext_version)
unset(msgmerge_name)
unset(msgmerge_namewe)
endif()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext
REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE
VERSION_VAR GETTEXT_VERSION_STRING)
function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
if(NOT currentCounter)
set(currentCounter 1)
endif()
set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
math(EXPR currentCounter "${currentCounter} + 1")
set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
if(NOT currentCounter)
set(currentCounter 1)
endif()
set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
math(EXPR currentCounter "${currentCounter} + 1")
set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()
macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg)
# make it a real variable, so we can modify it here
set(_firstPoFile "${_firstPoFileArg}")
# make it a real variable, so we can modify it here
set(_firstPoFile "${_firstPoFileArg}")
set(_gmoFiles)
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
set(_gmoFiles)
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
set(_addToAll)
if(${_firstPoFile} STREQUAL "ALL")
set(_addToAll "ALL")
set(_firstPoFile)
endif()
set(_addToAll)
if(${_firstPoFile} STREQUAL "ALL")
set(_addToAll "ALL")
set(_firstPoFile)
endif()
foreach (_currentPoFile ${_firstPoFile} ${ARGN})
get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
get_filename_component(_abs_PATH ${_absFile} PATH)
string(REGEX REPLACE "^.*/([^/]+)(\\.[^.]+)$" "\\1" _lang ${_absFile})
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
foreach (_currentPoFile ${_firstPoFile} ${ARGN})
get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
get_filename_component(_abs_PATH ${_absFile} PATH)
get_filename_component(_lang ${_absFile} NAME_WE)
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
add_custom_command(
OUTPUT ${_gmoFile}
#COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
DEPENDS ${_absPotFile} ${_absFile}
)
add_custom_command(
OUTPUT ${_gmoFile}
# COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
DEPENDS ${_absPotFile} ${_absFile}
)
install(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
set(_gmoFiles ${_gmoFiles} ${_gmoFile})
install(FILES ${_gmoFile} DESTINATION share/locale/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
set(_gmoFiles ${_gmoFiles} ${_gmoFile})
endforeach ()
endforeach ()
if(NOT TARGET translations)
add_custom_target(translations)
endif()
if(NOT TARGET translations)
add_custom_target(translations)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName)
add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
add_dependencies(translations ${uniqueTargetName})
add_dependencies(translations ${uniqueTargetName})
endmacro()
function(GETTEXT_PROCESS_POT_FILE _potFile)
set(_gmoFiles)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs LANGUAGES)
set(_gmoFiles)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs LANGUAGES)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
foreach (_lang ${_parsedArguments_LANGUAGES})
set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
foreach (_lang ${_parsedArguments_LANGUAGES})
set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
add_custom_command(
OUTPUT "${_poFile}"
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
DEPENDS ${_absPotFile}
)
add_custom_command(
OUTPUT "${_poFile}"
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
DEPENDS ${_absPotFile}
)
add_custom_command(
OUTPUT "${_gmoFile}"
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
DEPENDS ${_absPotFile} ${_poFile}
)
add_custom_command(
OUTPUT "${_gmoFile}"
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
DEPENDS ${_absPotFile} ${_poFile}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach ()
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach ()
if(NOT TARGET potfiles)
add_custom_target(potfiles)
add_custom_target(potfiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(potfiles ${uniqueTargetName})
add_dependencies(potfiles ${uniqueTargetName})
endfunction()
function(GETTEXT_PROCESS_PO_FILES _lang)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs PO_FILES)
set(_gmoFiles)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs PO_FILES)
set(_gmoFiles)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
get_filename_component(_name ${_current_PO_FILE} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
add_custom_command(OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS ${_current_PO_FILE}
)
foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
get_filename_component(_name ${_current_PO_FILE} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
add_custom_command(OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS ${_current_PO_FILE}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach()
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach()
if(NOT TARGET pofiles)
add_custom_target(pofiles)
add_custom_target(pofiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(pofiles ${uniqueTargetName})
add_dependencies(pofiles ${uniqueTargetName})
endfunction()

View File

@@ -11,8 +11,8 @@
# In addition, the following commands are called with the package manager's
# paths:
#
# INCLUDE_DIRECTORIES()
# LINK_DIRECTORIES()
# include_directories()
# link_directories()
#
# The paths of package managers not currently in $ENV{PATH} are added to
# CMAKE_IGNORE_PATH .
@@ -41,68 +41,75 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
IF(NOT APPLE)
RETURN()
ENDIF()
if(NOT APPLE)
return()
endif()
IF(EXISTS /usr/local/bin/brew AND $ENV{PATH} MATCHES "(^|:)/usr/local/bin/?(:|$)")
MESSAGE("-- Configuring for Mac Homebrew")
if(NOT "$ENV{IN_NIX_SHELL}" STREQUAL "")
message(STATUS "Configuring for Nix")
SET(MAC_HOMEBREW ON)
set(NIX ON)
SET(CMAKE_IGNORE_PATH /opt/local /opt/local/bin /opt/local/include /opt/local/Library/Frameworks /opt/local/lib ${CMAKE_IGNORE_PATH})
SET(CMAKE_IGNORE_PATH /sw /sw/bin /sw/include /sw/Library/Frameworks /sw/lib ${CMAKE_IGNORE_PATH})
set(CMAKE_IGNORE_PATH /opt/local /opt/local/bin /opt/local/include /opt/local/Library/Frameworks /opt/local/lib ${CMAKE_IGNORE_PATH})
set(CMAKE_IGNORE_PATH /sw /sw/bin /sw/include /sw/Library/Frameworks /sw/lib ${CMAKE_IGNORE_PATH})
elseif(EXISTS /usr/local/bin/brew AND $ENV{PATH} MATCHES "(^|:)/usr/local/bin/?(:|$)")
message(STATUS "Configuring for Mac Homebrew")
SET(CMAKE_FRAMEWORK_PATH /usr/local/Frameworks ${CMAKE_FRAMEWORK_PATH})
set(MAC_HOMEBREW ON)
SET(CMAKE_INCLUDE_PATH /usr/local/include ${CMAKE_INCLUDE_PATH})
INCLUDE_DIRECTORIES("/usr/local/include")
set(CMAKE_IGNORE_PATH /opt/local /opt/local/bin /opt/local/include /opt/local/Library/Frameworks /opt/local/lib ${CMAKE_IGNORE_PATH})
set(CMAKE_IGNORE_PATH /sw /sw/bin /sw/include /sw/Library/Frameworks /sw/lib ${CMAKE_IGNORE_PATH})
SET(CMAKE_LIBRARY_PATH /usr/local/lib ${CMAKE_LIBRARY_PATH})
LINK_DIRECTORIES("/usr/local/lib")
set(CMAKE_FRAMEWORK_PATH /usr/local/Frameworks ${CMAKE_FRAMEWORK_PATH})
SET(CMAKE_PROGRAM_PATH /usr/local/bin ${CMAKE_PROGRAM_PATH})
set(CMAKE_INCLUDE_PATH /usr/local/include ${CMAKE_INCLUDE_PATH})
include_directories("/usr/local/include")
set(CMAKE_LIBRARY_PATH /usr/local/lib ${CMAKE_LIBRARY_PATH})
link_directories("/usr/local/lib")
set(CMAKE_PROGRAM_PATH /usr/local/bin ${CMAKE_PROGRAM_PATH})
set(ZLIB_ROOT /usr/local/opt/zlib)
ELSEIF(EXISTS /opt/local/bin/port AND $ENV{PATH} MATCHES "(^|:)/opt/local/bin/?(:|$)")
MESSAGE("-- Configuring for MacPorts")
elseif(EXISTS /opt/local/bin/port AND $ENV{PATH} MATCHES "(^|:)/opt/local/bin/?(:|$)")
message(STATUS "Configuring for MacPorts")
SET(MACPORTS ON)
set(MACPORTS ON)
SET(CMAKE_IGNORE_PATH /sw /sw/bin /sw/include /sw/Library/Frameworks /sw/lib ${CMAKE_IGNORE_PATH})
set(CMAKE_IGNORE_PATH /sw /sw/bin /sw/include /sw/Library/Frameworks /sw/lib ${CMAKE_IGNORE_PATH})
SET(CMAKE_FRAMEWORK_PATH /opt/local/Library/Frameworks ${CMAKE_FRAMEWORK_PATH})
set(CMAKE_FRAMEWORK_PATH /opt/local/Library/Frameworks ${CMAKE_FRAMEWORK_PATH})
SET(CMAKE_INCLUDE_PATH /opt/local/include ${CMAKE_INCLUDE_PATH})
INCLUDE_DIRECTORIES("/opt/local/include")
set(CMAKE_INCLUDE_PATH /opt/local/include ${CMAKE_INCLUDE_PATH})
include_directories("/opt/local/include")
SET(CMAKE_LIBRARY_PATH /opt/local/lib ${CMAKE_LIBRARY_PATH})
LINK_DIRECTORIES("/opt/local/lib")
set(CMAKE_LIBRARY_PATH /opt/local/lib ${CMAKE_LIBRARY_PATH})
link_directories("/opt/local/lib")
SET(CMAKE_PROGRAM_PATH /opt/local/bin ${CMAKE_PROGRAM_PATH})
ELSEIF(EXISTS /sw/bin/fink AND $ENV{PATH} MATCHES "(^|:)/sw/bin/?(:|$)")
MESSAGE("-- Configuring for Fink")
set(CMAKE_PROGRAM_PATH /opt/local/bin ${CMAKE_PROGRAM_PATH})
elseif(EXISTS /sw/bin/fink AND $ENV{PATH} MATCHES "(^|:)/sw/bin/?(:|$)")
message(STATUS "Configuring for Fink")
SET(FINK ON)
set(FINK ON)
SET(CMAKE_IGNORE_PATH /opt/local /opt/local/bin /opt/local/include /opt/local/Library/Frameworks /opt/local/lib ${CMAKE_IGNORE_PATH})
set(CMAKE_IGNORE_PATH /opt/local /opt/local/bin /opt/local/include /opt/local/Library/Frameworks /opt/local/lib ${CMAKE_IGNORE_PATH})
SET(CMAKE_FRAMEWORK_PATH /sw/Library/Frameworks ${CMAKE_FRAMEWORK_PATH})
set(CMAKE_FRAMEWORK_PATH /sw/Library/Frameworks ${CMAKE_FRAMEWORK_PATH})
SET(CMAKE_INCLUDE_PATH /sw/include ${CMAKE_INCLUDE_PATH})
INCLUDE_DIRECTORIES("/sw/include")
set(CMAKE_INCLUDE_PATH /sw/include ${CMAKE_INCLUDE_PATH})
include_directories("/sw/include")
SET(CMAKE_LIBRARY_PATH /sw/lib ${CMAKE_LIBRARY_PATH})
LINK_DIRECTORIES("/sw/lib")
set(CMAKE_LIBRARY_PATH /sw/lib ${CMAKE_LIBRARY_PATH})
link_directories("/sw/lib")
SET(CMAKE_PROGRAM_PATH /sw/bin ${CMAKE_PROGRAM_PATH})
ELSE()
set(CMAKE_PROGRAM_PATH /sw/bin ${CMAKE_PROGRAM_PATH})
else()
# no package manager found or active, do nothing
RETURN()
ENDIF()
return()
endif()
# only ignore /usr/local if brew is installed and not in the PATH
# in other cases, it is the user's personal installations
IF(NOT MAC_HOMEBREW AND EXISTS /usr/local/bin/brew)
SET(CMAKE_IGNORE_PATH /usr/local /usr/local/bin /usr/local/include /usr/local/Library/Frameworks /usr/local/lib ${CMAKE_IGNORE_PATH})
ENDIF()
if(NOT MAC_HOMEBREW AND EXISTS /usr/local/bin/brew)
set(CMAKE_IGNORE_PATH /usr/local /usr/local/bin /usr/local/include /usr/local/Library/Frameworks /usr/local/lib /usr/local/opt/gettext/bin /usr/local/opt/gettext/lib ${CMAKE_IGNORE_PATH})
endif()

View File

@@ -8,7 +8,12 @@ else()
set(BUILD_DEFAULT ON)
endif()
option(ENABLE_SDL "Build the SDL port" ${BUILD_DEFAULT})
set(ENABLE_SDL_DEFAULT ${BUILD_DEFAULT})
if(WIN32 OR APPLE)
set(ENABLE_SDL_DEFAULT OFF)
endif()
option(ENABLE_SDL "Build the SDL port" ${ENABLE_SDL_DEFAULT})
option(ENABLE_WX "Build the wxWidgets port" ${BUILD_DEFAULT})
option(ENABLE_DEBUGGER "Enable the debugger" ON)
option(ENABLE_ASAN "Enable -fsanitize=address by default. Requires debug build with GCC/Clang" OFF)
@@ -17,7 +22,7 @@ option(ENABLE_ASAN "Enable -fsanitize=address by default. Requires debug build w
set(VBAM_STATIC_DEFAULT OFF)
if(VCPKG_TARGET_TRIPLET MATCHES -static OR CMAKE_TOOLCHAIN_FILE MATCHES "mxe|-static")
set(VBAM_STATIC_DEFAULT ON)
elseif(MINGW OR (NOT "$ENV{MSYSTEM_PREFIX}" STREQUAL ""))
elseif(MINGW OR MSYS)
# Default to static builds on MinGW and all MSYS2 envs.
set(VBAM_STATIC_DEFAULT ON)
endif()
@@ -54,18 +59,30 @@ cmake_dependent_option(ENABLE_MMX "Enable MMX" ${MMX_DEFAULT} "ENABLE_ASM_SCALER
option(ENABLE_LIRC "Enable LIRC support" OFF)
# Link / SFML
find_package(SFML 2.4 COMPONENTS network system)
if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
if(SFML_STATIC_LIBRARIES AND SFML_NETWORK_LIBRARY_STATIC_DEBUG AND SFML_SYSTEM_LIBRARY_STATIC_DEBUG)
set(SFML_LIBRARIES ${SFML_NETWORK_LIBRARY_STATIC_DEBUG} ${SFML_SYSTEM_LIBRARY_STATIC_DEBUG})
elseif(SFML_NETWORK_LIBRARY_DYNAMIC_DEBUG AND SFML_SYSTEM_LIBRARY_DYNAMIC_DEBUG)
set(SFML_LIBRARIES ${SFML_NETWORK_LIBRARY_DYNAMIC_DEBUG} ${SFML_SYSTEM_LIBRARY_DYNAMIC_DEBUG})
endif()
# Add support for Homebrew, MacPorts and Fink on macOS
option(DISABLE_MACOS_PACKAGE_MANAGERS "Set to TRUE to disable support for macOS Homebrew, MacPorts and Fink." FALSE)
if(APPLE AND NOT DISABLE_MACOS_PACKAGE_MANAGERS)
include(MacPackageManagers)
endif()
set(ENABLE_LINK_DEFAULT OFF)
if(SFML_FOUND)
set(ENABLE_LINK_DEFAULT ON)
find_package(PkgConfig)
# Link / SFML
if(TRANSLATIONS_ONLY)
set(ENABLE_LINK_DEFAULT OFF)
else()
find_package(SFML 2.4 COMPONENTS network system)
if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
if(SFML_STATIC_LIBRARIES AND SFML_NETWORK_LIBRARY_STATIC_DEBUG AND SFML_SYSTEM_LIBRARY_STATIC_DEBUG)
set(SFML_LIBRARIES ${SFML_NETWORK_LIBRARY_STATIC_DEBUG} ${SFML_SYSTEM_LIBRARY_STATIC_DEBUG})
elseif(SFML_NETWORK_LIBRARY_DYNAMIC_DEBUG AND SFML_SYSTEM_LIBRARY_DYNAMIC_DEBUG)
set(SFML_LIBRARIES ${SFML_NETWORK_LIBRARY_DYNAMIC_DEBUG} ${SFML_SYSTEM_LIBRARY_DYNAMIC_DEBUG})
endif()
endif()
set(ENABLE_LINK_DEFAULT OFF)
if(SFML_FOUND)
set(ENABLE_LINK_DEFAULT ON)
endif()
endif()
option(ENABLE_LINK "Enable GBA linking functionality" ${ENABLE_LINK_DEFAULT})
@@ -74,7 +91,7 @@ set(FFMPEG_DEFAULT OFF)
set(FFMPEG_COMPONENTS AVCODEC AVFORMAT SWSCALE AVUTIL SWRESAMPLE)
set(FFMPEG_COMPONENT_VERSIONS AVCODEC>=58.18.100 AVFORMAT>=58.12.100 SWSCALE>=5.1.100 AVUTIL>=56.14.100 SWRESAMPLE>=3.1.100)
if(NOT DEFINED ENABLE_FFMPEG OR ENABLE_FFMPEG)
if(NOT TRANSLATIONS_ONLY AND NOT DEFINED ENABLE_FFMPEG OR ENABLE_FFMPEG)
set(FFMPEG_DEFAULT ON)
find_package(FFmpeg COMPONENTS ${FFMPEG_COMPONENTS})
@@ -115,12 +132,6 @@ option(ENABLE_LTO "Compile with Link Time Optimization" ${LTO_DEFAULT})
option(ENABLE_GBA_LOGGING "Enable extended GBA logging" ON)
# Add support for Homebrew, MacPorts and Fink on macOS
option(DISABLE_MACOS_PACKAGE_MANAGERS "Set to TRUE to disable support for macOS Homebrew, MacPorts and Fink." FALSE)
if(APPLE AND NOT DISABLE_MACOS_PACKAGE_MANAGERS)
include(MacPackageManagers)
endif()
option(UPSTREAM_RELEASE "do some optimizations and release automation tasks" OFF)
if(WIN32)
@@ -136,6 +147,25 @@ if(WIN32)
option(ENABLE_XAUDIO2 "Enable xaudio2 sound output for the wxWidgets port" ${XAUDIO2_DEFAULT})
endif()
option(ENABLE_FAUDIO "Enable FAudio sound output for the wxWidgets port" OFF)
set(ENABLE_FAUDIO_DEFAULT OFF)
find_package(FAudio QUIET)
if(FAudio_FOUND AND NOT (MINGW AND X86))
set(ENABLE_FAUDIO_DEFAULT ON)
endif()
option(ENABLE_FAUDIO "Enable FAudio sound output for the wxWidgets port" ${ENABLE_FAUDIO_DEFAULT})
option(ZIP_SUFFIX [=[suffix for release zip files, e.g. "-somebranch".zip]=] OFF)
# The SDL port can't be built without debugging support
if(NOT ENABLE_DEBUGGER AND ENABLE_SDL)
message(FATAL_ERROR "The SDL port can't be built without debugging support")
endif()
if(TRANSLATIONS_ONLY AND (ENABLE_SDL OR ENABLE_WX))
message(FATAL_ERROR "The SDL and wxWidgets ports can't be built when TRANSLATIONS_ONLY is enabled")
endif()
option(GPG_SIGNATURES "Create GPG signatures for release files" OFF)

View File

@@ -1,3 +1,7 @@
if(TRANSLATIONS_ONLY)
return()
endif()
if(NOT DEFINED VCPKG_TARGET_TRIPLET)
if(NOT WIN32)
return()
@@ -47,9 +51,31 @@ if(NOT DEFINED VCPKG_TARGET_TRIPLET)
message(STATUS "Inferred VCPKG_TARGET_TRIPLET=${VCPKG_TARGET_TRIPLET}")
endif()
function(vcpkg_seconds)
if(CMAKE_HOST_SYSTEM MATCHES Windows OR ((NOT DEFINED CMAKE_HOST_SYSTEM) AND WIN32))
execute_process(
COMMAND cmd /c echo %TIME:~0,8%
OUTPUT_VARIABLE time
)
else()
execute_process(
COMMAND date +%H:%M:%S
OUTPUT_VARIABLE time
)
endif()
string(SUBSTRING "${time}" 0 2 hours)
string(SUBSTRING "${time}" 3 2 minutes)
string(SUBSTRING "${time}" 6 2 secs)
math(EXPR seconds "(${hours} * 60 * 60) + (${minutes} * 60) + ${secs}")
set(seconds ${seconds} PARENT_SCOPE)
endfunction()
function(vcpkg_check_git_status git_status)
# The VS vcpkg component cannot be written to without elevation.
if(NOT git_status EQUAL 0 AND NOT VCPKG_ROOT MATCHES "^C:/Program Files/Microsoft Visual Studio/")
if(NOT git_status EQUAL 0 AND NOT VCPKG_ROOT MATCHES "Visual Studio")
message(FATAL_ERROR "Error updating vcpkg from git, please make sure git for windows is installed correctly, it can be installed from Visual Studio components")
endif()
endfunction()
@@ -116,7 +142,7 @@ function(vcpkg_is_installed vcpkg_exe pkg_name pkg_ver pkg_triplet powershell ou
string(REPLACE "-" "." pkg_ver ${pkg_ver})
if(NOT DEFINED VCPKG_INSTALLED_COUNT)
if(VCPKG_ROOT MATCHES "^C:/Program Files/Microsoft Visual Studio/")
if(VCPKG_ROOT MATCHES "Visual Studio")
execute_process(
COMMAND ${powershell}
-executionpolicy bypass -noprofile

View File

@@ -2,27 +2,33 @@ if(X86_32 OR X86_64)
add_compile_options(-mfpmath=sse -msse2)
endif()
if(X86_64)
# Require and optimize for Core2 level support, tune for generic.
add_compile_options(-march=core2 -mtune=generic)
elseif(X86_32)
# Optimize for pentium-mmx and tune for generic for older builds.
add_compile_options(-march=pentium-mmx -mtune=generic)
if(UPSTREAM_RELEASE)
if(X86_64)
# Require and optimize for Core2 level support, tune for generic.
add_compile_options(-march=core2 -mtune=generic)
elseif(X86_32)
# Optimize for pentium-mmx and tune for generic for older builds.
add_compile_options(-march=pentium-mmx -mtune=generic)
endif()
endif()
# Common flags.
add_compile_options(
-pipe
-Wno-unused-command-line-argument
-Wno-deprecated-copy
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-copy>
-Wformat
-Wformat-security
-feliminate-unused-debug-types
-fdiagnostics-color=always
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wno-unused-command-line-argument)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-feliminate-unused-debug-types)
endif()
# check if ssp flags are supported.
if(CMAKE_BUILD_TYPE STREQUAL Debug)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
check_cxx_compiler_flag(-fstack-protector-strong STACK_PROTECTOR_SUPPORTED)
if(STACK_PROTECTOR_SUPPORTED)
@@ -39,13 +45,30 @@ if(NOT ENABLE_ASM) # inline asm is not allowed with -fPIC
add_compile_options(-fPIC)
endif()
if(CMAKE_BUILD_TYPE STREQUAL Debug)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-ggdb3 -Og -fno-omit-frame-pointer -Wall -Wextra)
else()
add_compile_options(-Ofast -fomit-frame-pointer)
endif()
# for some reason this is necessary
if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
include_directories(/usr/local/include)
endif()
if(VBAM_STATIC)
if(APPLE)
add_link_options(-static-libstdc++)
else()
add_link_options(-static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread)
endif()
endif()
# To support LTO, this must always fail.
add_compile_options(-Werror=odr -Werror=strict-aliasing)
add_link_options( -Werror=odr -Werror=strict-aliasing)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Werror=lto-type-mismatch)
add_link_options( -Werror=lto-type-mismatch)
endif()

View File

@@ -6,23 +6,5 @@ endif()
include_directories("${CMAKE_SOURCE_DIR}/dependencies/mingw-include")
include_directories("${CMAKE_SOURCE_DIR}/dependencies/mingw-xaudio/include")
# link libgcc/libstdc++ statically on GCC/mingw
# and adjust link command when making a static binary
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND VBAM_STATIC)
# some dists don't have a static libpthread
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread ")
if(WIN32)
add_custom_command(
TARGET visualboyadvance-m PRE_LINK
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/msys-link-static.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
else()
add_custom_command(
TARGET visualboyadvance-m PRE_LINK
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/link-static.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
endif()
endif()
# Add Winsock as the last library linked because of broken link precedence.
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lws2_32")

View File

@@ -1,13 +1,23 @@
if(TRANSLATIONS_ONLY)
return()
endif()
# Compiler stuff
include(CheckCXXCompilerFlag)
include(ProcessorCount)
ProcessorCount(num_cpus)
if (ENABLE_LTO)
if(ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_SUPPORTED)
if (LTO_SUPPORTED)
# MINGW64 does not support LTO
if(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(LTO_SUPPORTED FALSE)
endif()
if(LTO_SUPPORTED)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
message(WARNING "LTO is not supported by the compiler, diasabling LTO")
@@ -15,6 +25,49 @@ if (ENABLE_LTO)
endif()
endif()
# Output all binaries at top level
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
if(NOT HTTPS)
add_compile_definitions(NO_HTTPS)
endif()
if(ENABLE_GBA_LOGGING)
add_compile_definitions(GBA_LOGGING )
endif()
if(ENABLE_MMX)
add_compile_definitions(MMX)
endif()
if(NOT ENABLE_ONLINEUPDATES)
add_compile_definitions(NO_ONLINEUPDATES)
endif()
# The debugger is enabled by default
if(ENABLE_DEBUGGER)
add_compile_definitions(VBAM_ENABLE_DEBUGGER)
endif()
# The ASM core is disabled by default because we don't know on which platform we are
if(NOT ENABLE_ASM_CORE)
add_compile_definitions(C_CORE)
endif()
# Set up "src" and generated directory as a global include directory.
set(VBAM_GENERATED_DIR ${CMAKE_BINARY_DIR}/generated)
include_directories(
${CMAKE_SOURCE_DIR}/src
${VBAM_GENERATED_DIR}
)
# C defines
add_compile_definitions(HAVE_NETINET_IN_H HAVE_ARPA_INET_H HAVE_ZLIB_H FINAL_VERSION SDL USE_OPENGL SYSCONF_INSTALL_DIR="${CMAKE_INSTALL_FULL_SYSCONFDIR}")
add_compile_definitions(PKGDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/vbam")
add_compile_definitions(__STDC_FORMAT_MACROS)
add_compile_definitions(LOCALEDIR="${LOCALEDIR}")
# Common compiler settings.
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(DEBUG)

View File

@@ -1,175 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
doctest
-----
This module defines a function to help use the doctest test framework.
The :command:`doctest_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each doctest test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the doctest name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: doctest_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
doctest_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
)
``doctest_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-cases`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the doctest executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the doctest executable with the ``--list-test-cases`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``doctest_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``doctest_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``doctest_discover_tests()``.
Note that this variable is only available in CTest.
#]=======================================================================]
#------------------------------------------------------------------------------
function(doctest_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT CMAKE_VERSION VERSION_LESS 3.10)
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if(NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_DOCTEST_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/doctestAddTests.cmake
)

View File

@@ -1,81 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
if("${spec}" MATCHES .)
set(spec "--test-case=${spec}")
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-cases
OUTPUT_VARIABLE output
RESULT_VARIABLE result
)
if(NOT ${result} EQUAL 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Parse output
foreach(line ${output})
if("${line}" STREQUAL "===============================================================================" OR "${line}" MATCHES [==[^\[doctest\] ]==])
continue()
endif()
set(test ${line})
# use escape commas to handle properly test cases with commas inside the name
string(REPLACE "," "\\," test_name ${test})
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"--test-case=${test_name}"
${extra_args}
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")

View File

@@ -2,7 +2,7 @@ with import <nixpkgs> {};
stdenv.mkDerivation {
name = "visualboyadvance-m";
buildInputs = if stdenv.isDarwin then
[ ninja cmake gcc nasm gettext pkg-config zip sfml zlib openal ffmpeg wxGTK32 SDL2 pcre pcre2 darwin.apple_sdk.frameworks.IOKit darwin.apple_sdk.frameworks.Carbon darwin.apple_sdk.frameworks.Cocoa darwin.apple_sdk.frameworks.QuartzCore darwin.apple_sdk.frameworks.AudioToolbox darwin.apple_sdk.frameworks.OpenGL darwin.apple_sdk.frameworks.OpenAL llvmPackages_latest.clang llvmPackages_latest.bintools ]
[ ninja cmake gcc nasm faudio gettext libintl pkg-config zip sfml zlib openal ffmpeg wxGTK32 SDL2 pcre pcre2 darwin.apple_sdk.frameworks.System darwin.apple_sdk.frameworks.IOKit darwin.apple_sdk.frameworks.Carbon darwin.apple_sdk.frameworks.Cocoa darwin.apple_sdk.frameworks.QuartzCore darwin.apple_sdk.frameworks.AudioToolbox darwin.apple_sdk.frameworks.OpenGL darwin.apple_sdk.frameworks.OpenAL llvmPackages_latest.clang llvmPackages_latest.bintools ]
else
[ ninja cmake gcc nasm gettext pkg-config zip sfml zlib openal ffmpeg wxGTK32 mesa glfw SDL2 gtk3-x11 pcre pcre2 util-linuxMinimal libselinux libsepol libthai libdatrie xorg.libXdmcp xorg.libXtst libxkbcommon epoxy dbus at-spi2-core ];
[ ninja cmake gcc nasm faudio gettext libintl pkg-config zip sfml zlib openal ffmpeg wxGTK32 libGL libGLU glfw SDL2 gtk3-x11 pcre pcre2 util-linuxMinimal libselinux libsepol libthai libdatrie xorg.libXdmcp xorg.libXtst libxkbcommon epoxy dbus at-spi2-core ];
}

View File

@@ -2,8 +2,6 @@
Developer Information File
==========================
Known preprocessor switches:
- SDL: Defined for the SDL version
- GBA_LOGGING: Enables logging for the GBA core
@@ -13,47 +11,18 @@ Known preprocessor switches:
- RGB555: Use 16bit colors with 5bit green instead of 6bit green in hq3x/4x filters (C++ version)
- NO_OGL: Exclude OpenGL code
- NO_D3D: Exclude Direct3D code
- NO_OAL: Exclude OpenAL code
- NO_XAUDIO2: Exclude XAudio2 code (the XAudio2 interface is DirectSound's successor)
- VBAM_ENABLE_XAUDIO2: Enable XAudio2 code (the XAudio2 interface is DirectSound's successor)
- VBAM_ENABLE_FAUDIO: Enable FAudio code (the FAudio interface is an open source multiplatform re-implementation of XAudio2)
- NO_LINK: Exclude linking code (joybus, multilink, ...)
- WIN64: This macro is only defined for 64 bit builds
Download locations:
NASM: http://nasm.us/
DirectX SDK: http://msdn.microsoft.com/en-us/xna/aa937788.aspx
OpenAL SDK: http://connect.creativelabs.com/openal/default.aspx
OpenGL files: http://www.opengl.org/registry/
zlib: http://zlib.net/
libpng: http://libpng.org/pub/png/libpng.html
You can find pre-built versions of zlib & libpng at:
http://spacy51.sp.funpic.de/VBA-M/libs/
Just extract them somewhere and point Visual C++ 2008 to the include & lib folders.
They are built with the static C runtime (this is what the release builds use).
###########################
# --- Build Systems --- #
###########################
===Win32/MFC===
This is the full-featured Windows build using the MFC GUI.
The project files are located in /project/vc2008_mfc (VBA2008.sln) and /project/vs2010_mfc (VBA2010.sln).
Anyone distributing builds should be using MSVC 2010 SP1, the unpatched release has a bug where it applies SSE2 updates to mov and other instructions resulting in illegal instruction errors on cpu's only supporting SSE.
You also have to install Microsoft's DirectX SDK for Direct3D, DirectInput & XAudio2.
If you want to enable OpenAL sound output, install the OpenAL SDK. If you do not want it, add NO_OAL to the VBA-M project's preprocessor definitions.
SubWCRev.exe is used to append the svn versioning to the output executable, this as of TortoiseSVN 1.7, is only available by installing TortoiseSVN.
All other dependencies for MSVC builds may be found in the ../dependencies directory (above /trunk).
Normally, Windows users will want to checkout the root of the repository instead of just the trunk directory. Afterwards, simply opening the .sln of choice, setting preprocessor definitions, and hitting build is all that's required.
===*nix/GTK===
===src/sdl===
This is the standard build configuration on non-Windows.
Running cmake will inform you of any packages you need to install.
===*/wxw===
The wxWidgets interface is an in-development frontend meant to be more cross-platform friendly than MFC and GTK.
===src/wx===
The wxWidgets interface is an in-development frontend meant to be more cross-platform friendly than MFC and SDL.
Running cmake will inform you of any packages you need to install.
NOTE: In addition to what cmake currently checks for, you will also need the wxrc tool and libgdiplus.

View File

@@ -1,7 +1,6 @@
#!/bin/sh
CMAKE=cmake
ENABLE_OPENAL=1
ENABLE_FFMPEG=1
main() {
@@ -25,10 +24,6 @@ check_command_line_args() {
usage
quit 0
;;
--no-openal)
ENABLE_OPENAL=
shift
;;
--no-ffmpeg)
ENABLE_FFMPEG=
shift
@@ -355,9 +350,8 @@ debian_installdeps() {
;;
esac
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build"
pkgs="build-essential g++ nasm cmake ccache gettext zlib1g-dev libgl1-mesa-dev libgettextpo-dev libsdl2-dev $sdl_lib libglu1-mesa-dev libglu1-mesa libgles2-mesa-dev libsfml-dev $sfml_libs $glew_lib $wx_libs libgtk2.0-dev libgtk-3-dev ccache zip ninja-build libopenal-dev"
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs libopenal-dev"
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs libavcodec-dev libavformat-dev libswscale-dev libavutil-dev $libswresample_dev"
check sudo apt-get -qy install $pkgs
@@ -407,8 +401,7 @@ debian_installdeps() {
fi
fi
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets"
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
deps="gcc zlib ffmpeg gettext sdl2 sfml openal wxwidgets openal"
[ -n "$ENABLE_FFMPEG" ] && deps="$deps ffmpeg"
set --
@@ -510,9 +503,6 @@ fedora_installdeps() {
*ffmpeg*)
[ -z "$ENABLE_FFMPEG" ] && continue
;;
*openal*)
[ -z "$ENABLE_OPENAL" ] && continue
;;
esac
pkg_arch=
@@ -601,15 +591,9 @@ fedora_installdeps() {
;;
esac
# install static deps
for pkg in zlib gettext SDL2 wxWidgets3; do
for pkg in zlib gettext SDL2 wxWidgets3 openal-soft; do
set -- "$@" "${target}-${pkg}-static"
done
# install deps that are not available as static
if [ -n "$ENABLE_OPENAL" ]; then
for pkg in openal-soft; do
set -- "$@" "${target}-${pkg}"
done
fi
# get the necessary win32 headers
git submodule update --init --remote --recursive
@@ -707,9 +691,6 @@ rhel_installdeps() {
*ffmpeg*)
[ -z "$ENABLE_FFMPEG" ] && continue
;;
*openal*)
[ -z "$ENABLE_OPENAL" ] && continue
;;
esac
if [ -n "$amd64" ]; then
@@ -790,15 +771,9 @@ rhel_installdeps() {
;;
esac
# install static deps
for pkg in zlib gettext SDL2 wxWidgets; do
for pkg in zlib gettext SDL2 wxWidgets openal-soft; do
set -- "$@" "${target}-${pkg}-static"
done
# install deps that are not available as static
if [ -n "$ENABLE_OPENAL" ]; then
for pkg in openal-soft; do
set -- "$@" "${target}-${pkg}"
done
fi
# get the necessary win32 headers
git submodule update --init --remote --recursive
@@ -824,9 +799,8 @@ suse_installdeps() {
tools="make cmake ccache nasm gettext-tools pkg-config ccache zip sfml2-devel ninja"
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel" # ffmpeg-devel
libs="gcc gcc-c++ libSDL2-devel wxWidgets-3_0-devel openal-soft-devel" # ffmpeg-devel
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal-soft-devel"
# ffmpeg requires packman repos
if [ "$target" = m32 ]; then
@@ -894,9 +868,8 @@ archlinux_installdeps() {
$pacman -Q gtk3-classic >/dev/null 2>&1 && gtk=gtk3-classic
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml"
libs="zlib mesa gettext sdl2 wxgtk3 $gtk sfml openal"
[ -n "$ENABLE_OPENAL" ] && libs="$libs openal"
[ -n "$ENABLE_FFMPEG" ] && libs="$libs ffmpeg"
if [ -z "$target" -o "$target" = m32 ]; then
@@ -991,9 +964,7 @@ EOF
fi
done
deps="zlib gettext pkg-config sdl2 wxmsw"
[ -n "$ENABLE_OPENAL" ] && deps="$deps openal"
deps="zlib gettext pkg-config sdl2 wxmsw openal"
# and the actual deps
for p in $deps; do
@@ -1024,9 +995,7 @@ solus_installdeps() {
check sudo eopkg -y install -c system.devel
check sudo eopkg -y install git ccache ninja
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel
[ -n "$ENABLE_OPENAL" ] && set -- "$@" openal-soft-devel
set -- sdl2-devel wxwidgets-devel libgtk-2-devel libgtk-3-devel libglu-devel openal-soft-devel
if [ -n "$amd64" -a "$target" = m32 ]; then
info_msg 'Calculating dependencies, this will take a while..'
@@ -1102,14 +1071,13 @@ gentoo_installdeps() {
sys-devel/binutils \
media-libs/libsdl2 \
media-libs/libsfml \
media-libs/openal \
x11-libs/wxGTK:$wx_slot \
sys-libs/zlib \
dev-util/pkgconf \
dev-lang/nasm \
dev-build/ninja"
[ -n "$ENABLE_OPENAL" ] && ebuilds="$ebuilds media-libs/openal"
[ -n "$ENABLE_FFMPEG" ] && ebuilds="$ebuilds media-video/ffmpeg"
check sudo emerge -vna $ebuilds
@@ -1152,9 +1120,14 @@ windows_installdeps() {
;;
esac
pkgs="$pkgs SDL2 sfml wxWidgets3.2 zlib binutils cmake crt-git extra-cmake-modules headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache"
pkgs="$pkgs SDL2 sfml FAudio wxWidgets3.2 zlib binutils cmake crt-git headers-git make pkgconf tools-git windows-default-manifest libmangle-git ninja gdb ccache openal"
case "$target" in
*x86_64)
pkgs="$pkgs extra-cmake-modules"
;;
esac
[ -n "$ENABLE_OPENAL" ] && pkgs="$pkgs openal"
[ -n "$ENABLE_FFMPEG" ] && pkgs="$pkgs ffmpeg"
set --
@@ -1219,7 +1192,7 @@ brew_installdeps() {
check brew -v update
brews="nasm cmake ccache gettext pkg-config sdl2 wxwidgets ccache ninja"
brews="nasm cmake ccache gettext pkg-config sdl2 wxwidgets faudio ccache ninja zlib"
[ -n "$ENABLE_FFMPEG" ] && brews="$brews ffmpeg"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3877
po/wxvbam/ja_JP.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3820
po/wxvbam/ur_PK.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,6 @@ parts:
- libopenal-dev
- libwxgtk3.0-gtk3-dev
cmake-parameters:
- -DENABLE_OPENAL=ON
- -DENABLE_SDL=OFF
- -DCMAKE_INSTALL_PREFIX=/usr

View File

@@ -1,4 +1,3 @@
add_subdirectory(audio_sdl)
add_subdirectory(av_recording)
add_subdirectory(draw_text)
add_subdirectory(filters)

View File

@@ -1,14 +0,0 @@
add_library(vbam-components-audio-sdl OBJECT)
target_sources(vbam-components-audio-sdl
PRIVATE audio_sdl.cpp
PUBLIC audio_sdl.h
)
target_include_directories(vbam-components-audio-sdl
PUBLIC ${SDL2_INCLUDE_DIRS}
)
target_link_libraries(vbam-components-audio-sdl
PUBLIC vbam-core-base ${VBAM_SDL2_LIBS}
)

View File

@@ -137,18 +137,12 @@ recording::MediaRet recording::MediaRecorder::setup_audio_stream()
}
}
if (!isSupported && acodec->supported_samplerates) return MRET_ERR_NOCODEC;
aenc->channels = av_get_channel_layout_nb_channels(aenc->channel_layout);
#if LIBAVCODEC_VERSION_MAJOR >= 60
av_channel_layout_from_mask(&(aenc->ch_layout), AV_CH_LAYOUT_STEREO);
#else
aenc->channel_layout = AV_CH_LAYOUT_STEREO;
if (acodec->channel_layouts)
{
aenc->channel_layout = acodec->channel_layouts[0];
for (int i = 0; acodec->channel_layouts[i]; ++i)
{
if (acodec->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
aenc->channel_layout = AV_CH_LAYOUT_STEREO;
}
}
aenc->channels = av_get_channel_layout_nb_channels(aenc->channel_layout);
aenc->channels = 2;
#endif
aenc->time_base = { 1, aenc->sample_rate };
ast->time_base = { 1, STREAM_FRAME_RATE };
// open and use codec on stream
@@ -169,7 +163,11 @@ recording::MediaRet recording::MediaRecorder::setup_audio_stream()
audioframeTmp = av_frame_alloc();
if (!audioframeTmp) return MRET_ERR_BUFSIZE;
audioframeTmp->format = IN_SOUND_FORMAT;
audioframeTmp->channel_layout = aenc->channel_layout;
#if LIBAVCODEC_VERSION_MAJOR >= 60
audioframeTmp->ch_layout = aenc->ch_layout;
#else
audioframeTmp->channel_layout = AV_CH_LAYOUT_STEREO;
#endif
audioframeTmp->sample_rate = aenc->sample_rate;
audioframeTmp->nb_samples = nb_samples;
if (nb_samples)
@@ -181,7 +179,11 @@ recording::MediaRet recording::MediaRecorder::setup_audio_stream()
audioframe = av_frame_alloc();
if (!audioframe) return MRET_ERR_BUFSIZE;
audioframe->format = aenc->sample_fmt;
audioframe->channel_layout = aenc->channel_layout;
#if LIBAVCODEC_VERSION_MAJOR >= 60
audioframe->ch_layout = aenc->ch_layout;
#else
audioframe->channel_layout = AV_CH_LAYOUT_STEREO;
#endif
audioframe->sample_rate = aenc->sample_rate;
audioframe->nb_samples = nb_samples;
if (nb_samples)
@@ -195,10 +197,15 @@ recording::MediaRet recording::MediaRecorder::setup_audio_stream()
{
return MRET_ERR_BUFSIZE;
}
av_opt_set_int (swr, "in_channel_count", aenc->channels, 0);
#if LIBAVCODEC_VERSION_MAJOR >= 60
av_opt_set_chlayout (swr, "in_chlayout", &(aenc->ch_layout),0);
av_opt_set_chlayout (swr, "out_chlayout", &(aenc->ch_layout),0);
#else
av_opt_set_int (swr, "in_channel_count", 2, 0);
av_opt_set_int (swr, "out_channel_count", 2, 0);
#endif
av_opt_set_int (swr, "in_sample_rate", aenc->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", IN_SOUND_FORMAT, 0);
av_opt_set_int (swr, "out_channel_count", aenc->channels, 0);
av_opt_set_int (swr, "out_sample_rate", aenc->sample_rate, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", aenc->sample_fmt, 0);
if (swr_init(swr) < 0)
@@ -207,8 +214,8 @@ recording::MediaRet recording::MediaRecorder::setup_audio_stream()
return MRET_ERR_BUFSIZE;
}
// auxiliary buffer for setting up frames for encode
audioBufferSize = nb_samples * aenc->channels * sizeof(uint16_t);
audioBuffer = (uint16_t *) calloc(nb_samples * aenc->channels, sizeof(uint16_t));
audioBufferSize = nb_samples * 2 * sizeof(uint16_t);
audioBuffer = (uint16_t *) calloc(nb_samples * 2, sizeof(uint16_t));
if (!audioBuffer) return MRET_ERR_BUFSIZE;
samplesInAudioBuffer = 0;
posInAudioBuffer = 0;
@@ -565,7 +572,7 @@ recording::MediaRet recording::MediaRecorder::AddFrame(const uint16_t *aud, int
{
if (!isRecording) return MRET_OK;
AVCodecContext *c = aenc;
int samples_size = av_samples_get_buffer_size(NULL, c->channels, audioframeTmp->nb_samples, IN_SOUND_FORMAT, 1);
int samples_size = av_samples_get_buffer_size(NULL, 2, audioframeTmp->nb_samples, IN_SOUND_FORMAT, 1);
int realLength = length / sizeof *aud;
bool isMissing = false;
@@ -606,7 +613,7 @@ recording::MediaRet recording::MediaRecorder::AddFrame(const uint16_t *aud, int
pkt->data = NULL;
pkt->size = 0;
if (avcodec_fill_audio_frame(audioframeTmp, c->channels, IN_SOUND_FORMAT, (const uint8_t *)audioBuffer, samples_size, 1) < 0)
if (avcodec_fill_audio_frame(audioframeTmp, 2, IN_SOUND_FORMAT, (const uint8_t *)audioBuffer, samples_size, 1) < 0)
{
return MRET_ERR_RECORDING;
}

View File

@@ -136,3 +136,5 @@ if(ENABLE_LINK)
PRIVATE ${NLS_LIBS}
)
endif()
add_subdirectory(test)

View File

@@ -5,7 +5,9 @@
# Generate version_gen.h
string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+).*" "\\1,\\2,\\3,0" VBAM_WIN_VERSION "${VBAM_VERSION}")
set(VBAM_GENERATED_VERSION_H ${VBAM_GENERATED_DIR}/core/base/version_gen.h)
add_custom_target(vbam-core-base-generated
add_custom_command(
OUTPUT
${VBAM_GENERATED_VERSION_H}
COMMAND ${CMAKE_COMMAND}
-DVBAM_GENERATED_VERSION_H=${VBAM_GENERATED_VERSION_H}
-DVBAM_VERSION=${VBAM_VERSION}
@@ -13,8 +15,6 @@ add_custom_target(vbam-core-base-generated
-DVBAM_VERSION_RELEASE=${VBAM_VERSION_RELEASE}
-DVBAM_WIN_VERSION=${VBAM_WIN_VERSION}
-P ${CMAKE_CURRENT_SOURCE_DIR}/build-version.cmake
BYPRODUCTS
${VBAM_GENERATED_VERSION_H}
DEPENDS
version_gen.h.in
build-version.cmake
@@ -22,8 +22,6 @@ add_custom_target(vbam-core-base-generated
add_library(vbam-core-base OBJECT)
add_dependencies(vbam-core-base vbam-core-base-generated)
target_sources(vbam-core-base
PRIVATE
file_util_common.cpp
@@ -37,6 +35,7 @@ target_sources(vbam-core-base
version.cpp
PUBLIC
check.h
array.h
file_util.h
image_util.h
@@ -48,6 +47,8 @@ target_sources(vbam-core-base
sound_driver.h
system.h
version.h
# Generated file.
${VBAM_GENERATED_VERSION_H}
)
target_include_directories(vbam-core-base

62
src/core/base/check.h Normal file
View File

@@ -0,0 +1,62 @@
#ifndef VBAM_CORE_BASE_CHECK_H_
#define VBAM_CORE_BASE_CHECK_H_
// This header defines a number of macros for checking conditions and crashing
// the program if they are not met.
// * VBAM_CHECK(condition) - crashes the program if the condition is not met.
// * VBAM_NOTREACHED() - crashes the program if this line of code is reached.
// In release builds, this macro also tells the compiler that this code path
// is unreachable, which can help the compiler generate better code.
// * VBAM_STRINGIFY(x) - converts the argument to a string literal.
// While a number of other macros are defined in this file, they are not
// intended for general use and should be avoided.
#if defined(__GNUC__) || defined(__clang__)
// GCC/Clang.
#define VBAM_IMMEDIATE_CRASH_DETAIL() __builtin_trap()
#define VBAM_INTRINSIC_UNREACHABLE_DETAIL() __builtin_unreachable()
#elif defined(_MSC_VER) // defined(__GNUC__) || defined(__clang__)
// MSVC.
#define VBAM_IMMEDIATE_CRASH_DETAIL() __debugbreak()
#define VBAM_INTRINSIC_UNREACHABLE_DETAIL() __assume(0)
#else // defined(__GNUC__) || defined(__clang__)
#error "Unsupported compiler"
#endif // defined(__GNUC__) || defined(__clang__)
#define VBAM_STRINGIFY_DETAIL(x) #x
#define VBAM_STRINGIFY(x) VBAM_STRINGIFY_DETAIL(x)
#define VBAM_REQUIRE_SEMICOLON_DETAIL() \
static_assert(true, "Require a semicolon after macros invocation.")
#define VBAM_CHECK(condition) \
if (!(condition)) { \
fputs("CHECK failed at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) ": " #condition "\n", stderr); \
VBAM_IMMEDIATE_CRASH_DETAIL(); \
} \
VBAM_REQUIRE_SEMICOLON_DETAIL()
#define VBAM_NOTREACHED_MESSAGE_DETAIL() \
fputs("NOTREACHED code reached at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) "\n", stderr)
#if defined(DEBUG)
#define VBAM_NOTREACHED() \
VBAM_NOTREACHED_MESSAGE_DETAIL(); \
VBAM_IMMEDIATE_CRASH_DETAIL()
#else // defined(DEBUG)
#define VBAM_NOTREACHED() \
VBAM_NOTREACHED_MESSAGE_DETAIL(); \
VBAM_INTRINSIC_UNREACHABLE_DETAIL()
#endif // defined(DEBUG)
#endif // VBAM_CORE_BASE_CHECK_H_

View File

@@ -2,8 +2,9 @@
#define VBAM_CORE_BASE_SYSTEM_H_
#include <cstdint>
#include <memory>
class SoundDriver;
#include "core/base/sound_driver.h"
enum IMAGE_TYPE {
IMAGE_UNKNOWN = -1,
@@ -89,7 +90,7 @@ extern bool systemReadJoypads();
extern uint32_t systemReadJoypad(int);
extern uint32_t systemGetClock();
extern void systemSetTitle(const char*);
extern SoundDriver* systemSoundInit();
extern std::unique_ptr<SoundDriver> systemSoundInit();
extern void systemOnWriteDataToSoundBuffer(const uint16_t* finalWave, int length);
extern void systemOnSoundShutdown();
extern void systemScreenMessage(const char*);

View File

@@ -1,4 +1,7 @@
#include "core/base/version.h"
#include "core/base/version_gen.h"
const std::string kVbamMainVersion = VBAM_CURRENT_VERSION;
const std::string kVbamNameAndSubversion = VBAM_NAME_AND_SUBVERSION;
const std::string kVbamVersion = VBAM_VERSION;

View File

@@ -3,7 +3,9 @@
#include <string>
#include "core/base/version_gen.h"
// Main version information, generated by the build system.
// e.g. "2.1.9"
extern const std::string kVbamMainVersion;
// Full version information, generated by the build system.
// e.g. "VisualBoyAdvance-M 2.1.9-316e4a43 msvc-316e4a43"

View File

@@ -1,13 +1,13 @@
#include "core/gb/gb.h"
#include <array>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "core/base/check.h"
#include "core/base/file_util.h"
#include "core/base/message.h"
#include "core/base/sizes.h"
@@ -291,8 +291,7 @@ bool gbInitializeRom(size_t romSize) {
switch (g_gbCartData.validity()) {
case gbCartData::Validity::kValid:
case gbCartData::Validity::kUninitialized:
// Unreachable.
assert(false);
VBAM_NOTREACHED();
break;
case gbCartData::Validity::kSizeTooSmall:
systemMessage(MSG_UNSUPPORTED_ROM_SIZE,

View File

@@ -2,8 +2,8 @@
#include <algorithm>
#include <array>
#include <cassert>
#include "core/base/check.h"
#include "core/base/sizes.h"
namespace {
@@ -62,7 +62,7 @@ char byte_to_char(uint8_t byte) {
} else if (byte < 16) {
return 'A' + (byte - 10);
} else {
assert(false);
VBAM_NOTREACHED();
return '\0';
}
}
@@ -98,7 +98,7 @@ bool is_valid_manufacturer_code(const std::string& manufacturer_code) {
constexpr size_t kHeaderGlobalChecksumAdress = 0x14e;
uint16_t get_rom_checksum(const uint8_t* romData, size_t romDataSize) {
assert(romData);
VBAM_CHECK(romData);
uint16_t checksum = 0;
for (size_t i = 0; i < romDataSize; i++) {
@@ -160,7 +160,7 @@ constexpr size_t kHeaderChecksumEndAdress = 0x14c;
} // namespace
gbCartData::gbCartData(const uint8_t* romData, size_t romDataSize) {
assert(romData);
VBAM_CHECK(romData);
if (romDataSize < sizeof(gbRomHeader)) {
validity_ = Validity::kSizeTooSmall;

View File

@@ -1936,6 +1936,7 @@ void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
reg[13].I = reg[R13_FIQ].I;
reg[14].I = reg[R14_FIQ].I;
reg[16].I = SPSR;
if (saveState)
reg[17].I = CPSR;
else

View File

@@ -34,7 +34,7 @@
#define NR51 0x81
#define NR52 0x84
SoundDriver* soundDriver = 0;
std::unique_ptr<SoundDriver> soundDriver;
extern bool stopState; // TODO: silence sound when true
@@ -469,10 +469,7 @@ static void remake_stereo_buffer()
void soundShutdown()
{
if (soundDriver) {
delete soundDriver;
soundDriver = 0;
}
soundDriver.reset();
systemOnSoundShutdown();

View File

@@ -0,0 +1,13 @@
# This defines the `vbam-core-fake` library, which is used for providing a fake
# implementation of the core library for testing purposes.
if(NOT BUILD_TESTING)
return()
endif()
add_library(vbam-core-fake OBJECT)
target_sources(vbam-core-fake
PRIVATE
fake_core.cpp
)

View File

@@ -0,0 +1,94 @@
#include "core/base/system.h"
void systemMessage(int, const char*, ...) {}
void log(const char*, ...) {}
bool systemPauseOnFrame() {
return false;
}
void systemGbPrint(uint8_t*, int, int, int, int, int) {}
void systemScreenCapture(int) {}
void systemDrawScreen() {}
void systemSendScreen() {}
bool systemReadJoypads() {
return false;
}
uint32_t systemReadJoypad(int) {
return 0;
}
uint32_t systemGetClock() {
return 0;
}
void systemSetTitle(const char*) {}
std::unique_ptr<SoundDriver> systemSoundInit() {
return nullptr;
}
void systemOnWriteDataToSoundBuffer(const uint16_t* /*finalWave*/, int /*length*/) {}
void systemOnSoundShutdown() {}
void systemScreenMessage(const char*) {}
void systemUpdateMotionSensor() {}
int systemGetSensorX() {
return 0;
}
int systemGetSensorY() {
return 0;
}
int systemGetSensorZ() {
return 0;
}
uint8_t systemGetSensorDarkness() {
return 0;
}
void systemCartridgeRumble(bool) {}
void systemPossibleCartridgeRumble(bool) {}
void updateRumbleFrame() {}
bool systemCanChangeSoundQuality() {
return false;
}
void systemShowSpeed(int) {}
void system10Frames() {}
void systemFrame() {}
void systemGbBorderOn() {}
void (*dbgOutput)(const char* s, uint32_t addr);
void (*dbgSignal)(int sig, int number);
uint16_t systemColorMap16[0x10000];
uint32_t systemColorMap32[0x10000];
uint16_t systemGbPalette[24];
int systemRedShift;
int systemGreenShift;
int systemBlueShift;
int systemColorDepth;
int systemVerbose;
int systemFrameSkip;
int systemSaveUpdateCounter;
int systemSpeed;
int emulating = 0;

View File

@@ -66,7 +66,7 @@ endif
ifneq (,$(findstring unix,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,-version-script=$(LIBRETRO_DIR)/link.T -Wl,-no-undefined
SHARED := -shared -Wl,-no-undefined
TILED_RENDERING=1
# Classic Platforms ####################
@@ -78,7 +78,7 @@ ifneq (,$(findstring unix,$(platform)))
else ifeq ($(platform), classic_armv7_a7)
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined -fPIC
SHARED := -shared -Wl,--no-undefined -fPIC
CFLAGS += -Ofast \
-flto=4 -fwhole-program -fuse-linker-plugin \
-fdata-sections -ffunction-sections -Wl,--gc-sections \
@@ -216,7 +216,7 @@ else ifeq ($(platform), theos_ios)
else ifeq ($(platform), qnx)
TARGET := $(TARGET_NAME)_libretro_$(platform).so
fpic := -fPIC
SHARED := -lcpp -lm -shared -Wl,-version-script=$(LIBRETRO_DIR)/link.T -Wl,-no-undefined
SHARED := -lcpp -lm -shared -Wl,-no-undefined
CC = qcc -Vgcc_ntoarmv7le
CXX = QCC -Vgcc_ntoarmv7le_cpp
AR = QCC -Vgcc_ntoarmv7le
@@ -311,7 +311,7 @@ else ifeq ($(platform), wiiu)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
ENDIANNESS_DEFINES += -DMSB_FIRST -DWORDS_BIGENDIAN=1
PLATFORM_DEFINES += -DGEKKO -DWIIU -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float -D__ppc__
PLATFORM_DEFINES += -DGEKKO -DWIIU -DHW_WUP -mcpu=750 -meabi -mhard-float -D__ppc__
PLATFORM_DEFINES += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int
STATIC_LINKING=1
TILED_RENDERING=1
@@ -322,17 +322,18 @@ else ifeq ($(platform), libnx)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
DEFINES := -DSWITCH=1 -U__linux__ -U__linux -DRARCH_INTERNAL -DHAVE_THREADS=1
CFLAGS := $(DEFINES) -g -O3 \
-fPIE -I$(LIBNX)/include/ -ffunction-sections -fdata-sections -ftls-model=local-exec -Wl,--allow-multiple-definition -specs=$(LIBNX)/switch.specs
-fPIE -I$(LIBNX)/include/ -ffunction-sections -fdata-sections -ftls-model=local-exec -Wl,--allow-multiple-definition -specs=$(LIBNX)/switch.specs
CFLAGS += $(INCDIRS)
CFLAGS += $(INCLUDE) -D__SWITCH__ -DHAVE_LIBNX
CXXFLAGS := $(ASFLAGS) $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
CFLAGS += -std=gnu11
CXXFLAGS := $(ASFLAGS) $(CFLAGS) -fno-rtti -fno-exceptions
STATIC_LINKING=1
# Nintendo Switch (libtransistor)
# Nintendo Switch (devkitpro)
else ifeq ($(platform), switch)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
include $(LIBTRANSISTOR_HOME)/libtransistor.mk
CC = $(DEVKITPRO)/devkitA64/bin/aarch64-none-elf-gcc$(EXE_EXT)
CXX = $(DEVKITPRO)/devkitA64/bin/aarch64-none-elf-g++$(EXE_EXT)
AR = $(DEVKITPRO)/devkitA64/bin/aarch64-none-elf-ar$(EXE_EXT)
STATIC_LINKING=1
TILED_RENDERING=1
@@ -527,7 +528,7 @@ else
TARGET := $(TARGET_NAME)_libretro.dll
CC ?= gcc
CXX ?= g++
SHARED := -shared -static-libgcc -static-libstdc++ -Wl,-no-undefined -Wl,-version-script=$(LIBRETRO_DIR)/link.T
SHARED := -shared -static-libgcc -static-libstdc++ -Wl,-no-undefined
TILED_RENDERING=1
endif

View File

@@ -23,14 +23,16 @@
class SoundRetro : public SoundDriver {
public:
SoundRetro();
virtual ~SoundRetro();
~SoundRetro() override;
virtual bool init(long sampleRate);
virtual void pause();
virtual void reset();
virtual void resume();
virtual void write(uint16_t* finalWave, int length);
virtual void setThrottle(unsigned short throttle);
private:
// SoundDriver implementation.
bool init(long sampleRate) override;
void pause() override;
void reset() override;
void resume() override;
void write(uint16_t *finalWave, int length) override;
void setThrottle(unsigned short throttle_) override;
};
#endif // __VBA_SOUND_RETRO_H__

View File

@@ -1,4 +1,3 @@
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
@@ -12,6 +11,7 @@
#include "components/filters_agb/filters_agb.h"
#include "components/filters_interframe/interframe.h"
#include "core/base/check.h"
#include "core/base/system.h"
#include "core/base/file_util.h"
#include "core/base/sizes.h"
@@ -177,8 +177,7 @@ static void* gb_rtcdata_prt(void)
case gbCartData::MapperType::kGameGenie:
case gbCartData::MapperType::kGameShark:
case gbCartData::MapperType::kUnknown:
// Unreachable.
assert(false);
VBAM_NOTREACHED();
return nullptr;
}
return nullptr;
@@ -205,8 +204,7 @@ static size_t gb_rtcdata_size(void)
case gbCartData::MapperType::kGameGenie:
case gbCartData::MapperType::kGameShark:
case gbCartData::MapperType::kUnknown:
// Unreachable.
assert(false);
VBAM_NOTREACHED();
break;
}
return 0;
@@ -272,8 +270,7 @@ static void gbInitRTC(void)
case gbCartData::MapperType::kGameGenie:
case gbCartData::MapperType::kGameShark:
case gbCartData::MapperType::kUnknown:
// Unreachable.
assert(false);
VBAM_NOTREACHED();
break;
}
}
@@ -1456,8 +1453,7 @@ void retro_run(void)
case gbCartData::MapperType::kGameGenie:
case gbCartData::MapperType::kGameShark:
case gbCartData::MapperType::kUnknown:
// Unreachable.
assert(false);
VBAM_NOTREACHED();
break;
}
/* Initialize RTC using local time if needed */
@@ -1949,10 +1945,10 @@ uint32_t systemGetClock(void)
return 0;
}
SoundDriver* systemSoundInit(void)
std::unique_ptr<SoundDriver> systemSoundInit(void)
{
soundShutdown();
return new SoundRetro();
return std::make_unique<SoundRetro>();
}
void log(const char* defaultMsg, ...)

View File

@@ -1,4 +0,0 @@
{
global: retro_*;
local: *;
};

View File

@@ -7,6 +7,8 @@ add_executable(vbam WIN32)
target_sources(vbam
PRIVATE
audio_sdl.cpp
audio_sdl.h
ConfigManager.cpp
ConfigManager.h
dictionary.c
@@ -38,15 +40,19 @@ if(ENABLE_LIRC)
set(LIRC_CLIENT_LIBRARY lirc_client)
endif()
target_include_directories(vbam
PRIVATE ${SDL2_INCLUDE_DIRS}
)
target_link_libraries(vbam
vbam-core
vbam-components-audio-sdl
vbam-components-draw-text
vbam-components-filters
vbam-components-filters-agb
vbam-components-filters-interframe
vbam-components-user-config
${OPENGL_LIBRARIES}
${VBAM_SDL2_LIBS}
)
if(WIN32)

View File

@@ -68,6 +68,8 @@
#pragma comment(lib, "OpenGL32")
#include <Windows.h>
#define strdup _strdup
#endif // defined(_WIN32)
#if defined(__APPLE__)
@@ -91,7 +93,6 @@
#include <sys/poll.h>
#endif
#include "components/audio_sdl/audio_sdl.h"
#include "components/draw_text/draw_text.h"
#include "components/filters_agb/filters_agb.h"
#include "components/user_config/user_config.h"
@@ -110,6 +111,7 @@
#include "core/gba/gbaRtc.h"
#include "core/gba/gbaSound.h"
#include "sdl/ConfigManager.h"
#include "sdl/audio_sdl.h"
#include "sdl/filters.h"
#include "sdl/inputSDL.h"
@@ -2315,11 +2317,10 @@ uint8_t systemGetSensorDarkness()
return 0xE8;
}
SoundDriver* systemSoundInit()
{
std::unique_ptr<SoundDriver> systemSoundInit() {
soundShutdown();
return new SoundSDL();
return std::make_unique<SoundSDL>();
}
void systemOnSoundShutdown()

View File

@@ -15,7 +15,7 @@
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "components/audio_sdl/audio_sdl.h"
#include "sdl/audio_sdl.h"
#include <cmath>
#include <iostream>

View File

@@ -15,34 +15,34 @@
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef VBAM_COMPONENTS_AUDIO_SDL_AUDIO_SDL_H_
#define VBAM_COMPONENTS_AUDIO_SDL_AUDIO_SDL_H_
#ifndef VBAM_SDL_AUDIO_SDL_H_
#define VBAM_SDL_AUDIO_SDL_H_
#include <SDL.h>
#include "core/base/ringbuffer.h"
#include "core/base/sound_driver.h"
class SoundSDL : public SoundDriver {
class SoundSDL final : public SoundDriver {
public:
SoundSDL();
virtual ~SoundSDL();
virtual bool init(long sampleRate);
virtual void pause();
virtual void reset();
virtual void resume();
virtual void write(uint16_t *finalWave, int length);
virtual void setThrottle(unsigned short throttle_);
protected:
static void soundCallback(void* data, uint8_t* stream, int length);
virtual void read(uint16_t* stream, int length);
virtual bool should_wait();
virtual std::size_t buffer_size();
virtual void deinit();
~SoundSDL() override;
private:
static void soundCallback(void* data, uint8_t* stream, int length);
void read(uint16_t* stream, int length);
bool should_wait();
std::size_t buffer_size();
void deinit();
// SoundDriver implementation.
bool init(long sampleRate) override;
void pause() override;
void reset() override;
void resume() override;
void write(uint16_t *finalWave, int length) override;
void setThrottle(unsigned short throttle_) override;
RingBuffer<uint16_t> samples_buf;
SDL_AudioDeviceID sound_device = 0;
@@ -60,4 +60,4 @@ private:
static const double buftime;
};
#endif // VBAM_COMPONENTS_AUDIO_SDL_AUDIO_SDL_H_
#endif // VBAM_SDL_AUDIO_SDL_H_

View File

@@ -151,7 +151,7 @@ typedef unsigned int flex_uint32_t;
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state* YY_BUFFER_STATE;
typedef struct yy_buffer_state_sdl* YY_BUFFER_STATE;
#endif
extern int yyleng;
@@ -184,7 +184,7 @@ typedef size_t yy_size_t;
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state {
struct yy_buffer_state_sdl {
FILE* yy_input_file;
char* yy_ch_buf; /* input buffer */
@@ -1218,7 +1218,7 @@ YY_BUFFER_STATE yy_create_buffer(FILE* file, int size)
{
YY_BUFFER_STATE b;
b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state));
b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state_sdl));
if (!b)
YY_FATAL_ERROR("out of dynamic memory in yy_create_buffer()");
@@ -1381,11 +1381,11 @@ static void yyensure_buffer_stack(void)
* immediate realloc on the next call.
*/
num_to_alloc = 1;
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc(num_to_alloc * sizeof(struct yy_buffer_state*));
(yy_buffer_stack) = (struct yy_buffer_state_sdl**)yyalloc(num_to_alloc * sizeof(struct yy_buffer_state_sdl*));
if (!(yy_buffer_stack))
YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()");
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state_sdl*));
(yy_buffer_stack_max) = num_to_alloc;
(yy_buffer_stack_top) = 0;
@@ -1398,13 +1398,13 @@ static void yyensure_buffer_stack(void)
int grow_size = 8 /* arbitrary grow size */;
num_to_alloc = (yy_buffer_stack_max) + grow_size;
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*));
(yy_buffer_stack) = (struct yy_buffer_state_sdl**)yyrealloc((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state_sdl*));
if (!(yy_buffer_stack))
YY_FATAL_ERROR("out of dynamic memory in yyensure_buffer_stack()");
/* zero only the new slots.*/
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state_sdl*));
(yy_buffer_stack_max) = num_to_alloc;
}
}
@@ -1423,7 +1423,7 @@ YY_BUFFER_STATE yy_scan_buffer(char* base, yy_size_t size)
/* They forgot to leave room for the EOB's. */
return 0;
b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state));
b = (YY_BUFFER_STATE)yyalloc(sizeof(struct yy_buffer_state_sdl));
if (!b)
YY_FATAL_ERROR("out of dynamic memory in yy_scan_buffer()");

View File

@@ -6,27 +6,17 @@ endif()
include(VbamFunctions)
set(VBAM_WX_COMMON
audio/audio.cpp
audio/audio.h
audio/internal/openal.cpp
audio/internal/openal.h
background-input.cpp
background-input.h
cmdevents.cpp
config/game-control.cpp
config/game-control.h
config/internal/option-internal.cpp
config/internal/option-internal.h
config/internal/shortcuts-internal.cpp
config/internal/shortcuts-internal.h
config/option-id.h
config/option-observer.cpp
config/option-observer.h
config/option-proxy.h
config/option.cpp
config/option.h
config/shortcuts.cpp
config/shortcuts.h
config/user-input.cpp
config/user-input.h
dialogs/accel-config.cpp
dialogs/accel-config.h
dialogs/base-dialog.cpp
dialogs/base-dialog.h
dialogs/directories-config.cpp
dialogs/directories-config.h
dialogs/display-config.cpp
@@ -39,59 +29,34 @@ set(VBAM_WX_COMMON
dialogs/gb-rom-info.h
dialogs/joypad-config.cpp
dialogs/joypad-config.h
dialogs/validated-child.h
dialogs/sound-config.cpp
dialogs/sound-config.h
drawing.h
extra-translations.cpp
gfxviewers.cpp
guiinit.cpp
ioregs.h
openal.cpp
openal.h
opts.cpp
opts.h
panel.cpp
rpi.h
strutils.cpp
strutils.h
sys.cpp
viewers.cpp
viewsupt.cpp
viewsupt.h
wayland.cpp
wayland.h
# from external source with minor modifications
widgets/checkedlistctrl.cpp
widgets/checkedlistctrl.h
widgets/dpi-support.h
widgets/group-check-box.cpp
widgets/group-check-box.h
widgets/keep-on-top-styler.cpp
widgets/keep-on-top-styler.h
widgets/option-validator.cpp
widgets/option-validator.h
widgets/render-plugin.cpp
widgets/render-plugin.h
widgets/user-input-ctrl.cpp
widgets/user-input-ctrl.h
widgets/sdljoy.cpp
widgets/sdljoy.h
widgets/webupdatedef.h
widgets/wxmisc.h
widgets/wxmisc.cpp
wxhead.h
wxlogdebug.h
wxutil.cpp
wxutil.h
wxvbam.cpp
wxvbam.h
x11keymap.h
xrc/visualboyadvance-m.xpm
# Generated files.
${VBAM_GENERATED_DIR}/wx//builtin-xrc.h
${VBAM_GENERATED_DIR}/wx//builtin-over.h
${VBAM_GENERATED_DIR}/wx//cmdhandlers.h
${VBAM_GENERATED_DIR}/wx//cmd-evtable.h
${VBAM_GENERATED_DIR}/wx//cmdtab.cpp
${VBAM_GENERATED_DIR}/wx/builtin-xrc.h
${VBAM_GENERATED_DIR}/wx/builtin-over.h
${VBAM_GENERATED_DIR}/wx/cmdhandlers.h
${VBAM_GENERATED_DIR}/wx/cmd-evtable.h
)
if(NOT ZIP_PROGRAM)
@@ -172,6 +137,158 @@ if(TRANSLATIONS_ONLY)
return()
endif()
# wxWidgets configuration.
set(wxWidgets_USE_UNICODE ON)
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
set(wxWidgets_USE_DEBUG ON) # noop if wx is compiled with --disable-debug, like in Mac Homebrew atm
endif()
if(VBAM_STATIC)
set(wxWidgets_USE_STATIC ON)
endif()
unset(wx_find_extra)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
set(wx_find_extra NO_DEFAULT_PATH)
set(wxWidgets_DIR "${VCPKG_ROOT}/installed/${VCPKG_TARGET_TRIPLET}/share/wxwidgets")
endif()
set(ENABLE_OPENGL TRUE)
find_package(wxWidgets COMPONENTS xrc xml html adv net core base gl ${wx_find_extra})
if(NOT wxWidgets_FOUND)
find_package(wxWidgets COMPONENTS xrc xml html adv net core base ${wx_find_extra} REQUIRED)
set(ENABLE_OPENGL FALSE)
endif()
# Find OpenAL (required).
find_package(OpenAL REQUIRED)
# Workaround of static liblzma not being found on MSYS2.
if(VBAM_STATIC AND MSYS)
unset(cleaned_up_wx_libs)
foreach(lib ${wxWidgets_LIBRARIES})
if(lib STREQUAL "-llzma")
set(lib "liblzma.a")
endif()
list(APPEND cleaned_up_wx_libs "${lib}")
endforeach()
set(wxWidgets_LIBRARIES "${cleaned_up_wx_libs}")
endif()
list(APPEND CMAKE_REQUIRED_LIBRARIES ${wxWidgets_LIBRARIES})
list(APPEND CMAKE_REQUIRED_INCLUDES ${wxWidgets_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_FLAGS ${wxWidgets_CXX_FLAGS})
foreach(DEF ${wxWidgets_DEFINITIONS})
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D${DEF}")
endforeach()
# Configure common settings for wx-based targets, like linking, include
# directories, compile options, and definitions.
function(configure_wx_target target)
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "EXECUTABLE")
set(target_is_executable TRUE)
else()
set(target_is_executable FALSE)
endif()
function(_add_link_libraries)
if(${target_is_executable})
target_link_libraries(${target} ${ARGN})
else()
target_link_libraries(${target} PUBLIC ${ARGN})
endif()
endfunction()
function(_add_include_directories)
if(${target_is_executable})
target_include_directories(${target} PRIVATE ${ARGN})
else()
target_include_directories(${target} PUBLIC ${ARGN})
endif()
endfunction()
function(_add_compile_options)
if(${target_is_executable})
target_compile_options(${target} PRIVATE ${ARGN})
else()
target_compile_options(${target} PUBLIC ${ARGN})
endif()
endfunction()
function(_add_compile_definitions)
if(${target_is_executable})
target_compile_definitions(${target} PRIVATE ${ARGN})
else()
target_compile_definitions(${target} PUBLIC ${ARGN})
endif()
endfunction()
# Core emulator.
_add_link_libraries(vbam-core)
# Nonstd.
_add_link_libraries(nonstd-lib)
_add_include_directories(${NONSTD_INCLUDE_DIR})
# wxWidgets.
_add_link_libraries(${wxWidgets_LIBRARIES})
_add_include_directories(${wxWidgets_INCLUDE_DIRS})
_add_compile_options(${wxWidgets_CXX_FLAGS})
_add_compile_definitions(${wxWidgets_DEFINITIONS})
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
_add_compile_definitions(${wxWidgets_DEFINITIONS_DEBUG})
endif()
# OpenAL.
if(OPENAL_STATIC)
_add_compile_definitions(AL_LIBTYPE_STATIC)
endif()
_add_include_directories(${OPENAL_INCLUDE_DIR})
_add_link_libraries(${OPENAL_LIBRARY})
# XAudio2.
if(ENABLE_XAUDIO2)
_add_compile_definitions(VBAM_ENABLE_XAUDIO2)
endif()
# FAudio.
if(ENABLE_FAUDIO)
_add_compile_definitions(VBAM_ENABLE_FAUDIO)
if(MSVC)
_add_link_libraries(FAudio::FAudio)
else()
_add_link_libraries(FAudio)
if(WIN32)
_add_link_libraries(dxguid uuid winmm ole32 advapi32 user32 mfplat mfreadwrite mfuuid propsys)
endif()
endif()
endif()
# Direct3D.
if(NOT ENABLE_DIRECT3D)
_add_compile_definitions(NO_D3D)
endif()
# SDL2.
_add_link_libraries(${VBAM_SDL2_LIBS})
# OpenGL.
if(ENABLE_OPENGL)
_add_link_libraries(${OPENGL_LIBRARIES})
else()
_add_compile_definitions(NO_OGL)
endif()
endfunction()
# Sub-projects.
add_subdirectory(test)
add_subdirectory(config)
add_subdirectory(widgets)
set(VBAM_ICON visualboyadvance-m.icns)
set(VBAM_ICON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/icons/${VBAM_ICON})
@@ -182,21 +299,36 @@ add_executable(
)
target_sources(visualboyadvance-m PRIVATE ${VBAM_WX_COMMON} ${VBAM_ICON_PATH})
target_include_directories(visualboyadvance-m PRIVATE ${NONSTD_INCLUDE_DIR})
target_include_directories(visualboyadvance-m PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(
visualboyadvance-m
nonstd-lib
vbam-core
vbam-components-audio-sdl
vbam-components-draw-text
vbam-components-filters
vbam-components-filters-agb
vbam-components-filters-interframe
vbam-components-user-config
${OPENGL_LIBRARIES}
vbam-wx-config
vbam-wx-widgets
)
# adjust link command when making a static binary for gcc
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND VBAM_STATIC)
if(MSYS)
add_custom_command(
TARGET visualboyadvance-m PRE_LINK
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/msys-link-static.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
else()
add_custom_command(
TARGET visualboyadvance-m PRE_LINK
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/link-static.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
endif()
endif()
add_dependencies(visualboyadvance-m translations-zip)
# on unix we have to check for X11 before we overwrite all the compile/link
@@ -230,7 +362,7 @@ endif()
if(WIN32)
target_sources(visualboyadvance-m
PRIVATE
dsound.cpp
audio/internal/dsound.cpp
wxvbam.rc
)
target_link_libraries(visualboyadvance-m
@@ -284,70 +416,17 @@ if(CMAKE_COMPILER_IS_GNUCXX AND VBAM_STATIC)
endif()
endif()
# OpenAL.
find_package(OpenAL REQUIRED)
if(OPENAL_STATIC OR (WIN32 AND ((NOT (MINGW AND MSYS)) OR CMAKE_TOOLCHAIN_FILE MATCHES mxe)))
target_compile_definitions(visualboyadvance-m PRIVATE AL_LIBTYPE_STATIC)
endif()
target_include_directories(visualboyadvance-m PRIVATE ${OPENAL_INCLUDE_DIR})
target_link_libraries(visualboyadvance-m ${OPENAL_LIBRARY})
# XAudio2.
if(ENABLE_XAUDIO2)
target_sources(visualboyadvance-m PRIVATE xaudio2.cpp)
else()
target_compile_definitions(visualboyadvance-m PRIVATE NO_XAUDIO2)
endif()
# Direct3D.
if(NOT ENABLE_DIRECT3D)
target_compile_definitions(visualboyadvance-m PRIVATE NO_D3D)
target_sources(visualboyadvance-m PRIVATE audio/internal/xaudio2.cpp)
endif()
# FAudio.
if(ENABLE_FAUDIO)
find_package(FAudio REQUIRED)
target_link_libraries(visualboyadvance-m FAudio::FAudio)
else()
target_compile_definitions(visualboyadvance-m PRIVATE NO_FAUDIO)
target_sources(visualboyadvance-m PRIVATE audio/internal/faudio.cpp)
endif()
# wxWidgets.
set(wxWidgets_USE_UNICODE ON)
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
set(wxWidgets_USE_DEBUG ON) # noop if wx is compiled with --disable-debug, like in Mac Homebrew atm
endif()
if(VBAM_STATIC)
set(wxWidgets_USE_STATIC ON)
endif()
unset(wx_find_extra)
if(CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg")
set(wx_find_extra NO_DEFAULT_PATH)
set(wxWidgets_DIR "${VCPKG_ROOT}/installed/${VCPKG_TARGET_TRIPLET}/share/wxwidgets")
endif()
find_package(wxWidgets COMPONENTS xrc xml html adv net core base gl ${wx_find_extra})
if(NOT wxWidgets_FOUND)
find_package(wxWidgets COMPONENTS xrc xml html adv net core base ${wx_find_extra} REQUIRED)
target_compile_definitions(visualboyadvance-m PRIVATE NO_OGL)
endif()
target_link_libraries(visualboyadvance-m ${wxWidgets_LIBRARIES})
target_include_directories(visualboyadvance-m PRIVATE ${wxWidgets_INCLUDE_DIRS})
target_compile_options(visualboyadvance-m PRIVATE ${wxWidgets_CXX_FLAGS})
target_compile_definitions(visualboyadvance-m PRIVATE ${wxWidgets_DEFINITIONS})
if(CMAKE_BUILD_TYPE MATCHES "^(Debug|RelWithDebInfo)$")
target_compile_definitions(visualboyadvance-m PRIVATE ${wxWidgets_DEFINITIONS_DEBUG})
endif()
list(APPEND CMAKE_REQUIRED_LIBRARIES ${wxWidgets_LIBRARIES})
list(APPEND CMAKE_REQUIRED_INCLUDES ${wxWidgets_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_FLAGS ${wxWidgets_CXX_FLAGS})
foreach(DEF ${wxWidgets_DEFINITIONS})
list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D${DEF}")
endforeach()
configure_wx_target(visualboyadvance-m)
# we make some direct gtk/gdk calls on linux and such
# so need to link the gtk that wx was built with
@@ -557,30 +636,11 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/src/vba-over.ini ${BIN2C}
)
# I don't like duplicating/triplicating code, so I only declare
# event handlers once, and copy them in other places they are needed
# all using portable cmake code
add_custom_command(
OUTPUT
${VBAM_GENERATED_DIR}/wx/cmdtab.cpp
${VBAM_GENERATED_DIR}/wx/cmdhandlers.h
${VBAM_GENERATED_DIR}/wx/cmd-evtable.h
COMMAND
${CMAKE_COMMAND} -D OUTDIR=${VBAM_GENERATED_DIR}/wx/ -P copy-events.cmake
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
cmdevents.cpp
copy-events.cmake
)
# # Win32 definitions common to all toolchains.
# if (WIN32)
# add_compile_definitions(wxUSE_GUI=1)
# endif()
set(VBAM_LOCALIZABLE_FILES ${VBAM_WX_COMMON})
set(VBAM_LOCALIZABLE_FILES ${VBAM_WX_COMMON} ${VBAM_LOCALIZABLE_WX_CONFIG_FILES})
list(APPEND VBAM_LOCALIZABLE_FILES
audio/internal/dsound.cpp
audio/internal/faudio.cpp
audio/internal/xaudio2.cpp
autoupdater/autoupdater.h
autoupdater/macos/autoupdater.cpp
autoupdater/macos/sparkle-wrapper.h
@@ -588,11 +648,8 @@ list(APPEND VBAM_LOCALIZABLE_FILES
autoupdater/wxmsw/winsparkle-rc.h
autoupdater/wxmsw/winsparkle-wrapper.cpp
autoupdater/wxmsw/winsparkle-wrapper.h
dsound.cpp
faudio.cpp
widgets/dpi-support.cpp
widgets/dpi-support-mac.mm
xaudio2.cpp
${CMAKE_SOURCE_DIR}/src/core/gba/gbaLink.cpp
)
@@ -749,7 +806,7 @@ if(UPSTREAM_RELEASE AND WIN32)
TARGET visualboyadvance-m
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy visualboyadvance-m.exe visualboyadvance-m-unsigned.exe
COMMAND ${SIGNTOOL_PROGRAM} sign /f ${cert} /p "vbam3!13" /tr http://timestamp.digicert.com /du https://github.com/visualboyadvance-m/visualboyadvance-m /a visualboyadvance-m.exe
COMMAND ${SIGNTOOL_PROGRAM} sign /f ${cert} /fd certHash /td certHash /p "vbam3!13" /tr http://timestamp.digicert.com /du https://github.com/visualboyadvance-m/visualboyadvance-m /a visualboyadvance-m.exe
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
@@ -774,7 +831,7 @@ if(UPSTREAM_RELEASE AND WIN32)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
if(GPG_KEYS)
if(GPG_SIGNATURES AND GPG_KEYS)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/translations.zip.asc
COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/translations.zip.asc
@@ -951,10 +1008,6 @@ install(
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(BUILD_TESTING AND (NOT CMAKE_CROSSCOMPILING))
add_subdirectory(tests)
endif()
# Installation scripts.
install(
PROGRAMS ${PROJECT_BINARY_DIR}/visualboyadvance-m${CMAKE_EXECUTABLE_SUFFIX}

74
src/wx/audio/audio.cpp Normal file
View File

@@ -0,0 +1,74 @@
#include "wx/audio/audio.h"
#include "core/base/check.h"
#include "wx/audio/internal/openal.h"
#if defined(__WXMSW__)
#include "wx/audio/internal/dsound.h"
#endif
#if defined(VBAM_ENABLE_FAUDIO)
#include "wx/audio/internal/faudio.h"
#endif
#if defined(VBAM_ENABLE_XAUDIO2)
#include "wx/audio/internal/xaudio2.h"
#endif
namespace audio {
std::vector<AudioDevice> EnumerateAudioDevices(const config::AudioApi& audio_api) {
switch (audio_api) {
case config::AudioApi::kOpenAL:
return audio::internal::GetOpenALDevices();
#if defined(__WXMSW__)
case config::AudioApi::kDirectSound:
return audio::internal::GetDirectSoundDevices();
#endif
#if defined(VBAM_ENABLE_XAUDIO2)
case config::AudioApi::kXAudio2:
return audio::internal::GetXAudio2Devices();
#endif
#if defined(VBAM_ENABLE_FAUDIO)
case config::AudioApi::kFAudio:
return audio::internal::GetFAudioDevices();
#endif
case config::AudioApi::kLast:
default:
VBAM_NOTREACHED();
return {};
}
}
std::unique_ptr<SoundDriver> CreateSoundDriver(const config::AudioApi& api) {
switch (api) {
case config::AudioApi::kOpenAL:
return audio::internal::CreateOpenALDriver();
#if defined(__WXMSW__)
case config::AudioApi::kDirectSound:
return audio::internal::CreateDirectSoundDriver();
#endif
#if defined(VBAM_ENABLE_XAUDIO2)
case config::AudioApi::kXAudio2:
return audio::internal::CreateXAudio2Driver();
#endif
#if defined(VBAM_ENABLE_FAUDIO)
case config::AudioApi::kFAudio:
return audio::internal::CreateFAudioDriver();
#endif
case config::AudioApi::kLast:
default:
VBAM_NOTREACHED();
return nullptr;
}
}
} // namespace audio

30
src/wx/audio/audio.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef WX_AUDIO_AUDIO_H_
#define WX_AUDIO_AUDIO_H_
#include <memory>
#include <vector>
#include <wx/string.h>
#include "core/base/sound_driver.h"
#include "wx/config/option.h"
namespace audio {
// Represents an audio device.
struct AudioDevice {
// The device user-friendly name.
wxString name;
// The underlying device ID.
wxString id;
};
// Returns the set of audio devices for the given API.
std::vector<AudioDevice> EnumerateAudioDevices(const config::AudioApi& api);
// Creates a sound driver for the given API.
std::unique_ptr<SoundDriver> CreateSoundDriver(const config::AudioApi& api);
} // namespace audio
#endif // WX_AUDIO_AUDIO_H_

View File

@@ -1,46 +1,62 @@
// Application
#include "wx/wxvbam.h"
#if !defined(__WXMSW__)
#error "This file should only be compiled on Windows"
#endif
#include "wx/audio/internal/dsound.h"
// DirectSound8
#define DIRECTSOUND_VERSION 0x0800
#include <Windows.h>
#include <mmeapi.h>
#include <dsound.h>
#include <uuids.h>
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/translation.h>
// Internals
#include "core/base/sound_driver.h"
#include "core/base/system.h"
#include "core/gba/gbaGlobals.h"
#include "core/gba/gbaSound.h"
// DirectSound8
#define DIRECTSOUND_VERSION 0x0800
#include <mmeapi.h>
#include <uuids.h>
#include <dsound.h>
#include "wx/config/option-proxy.h"
#include "wx/wxvbam.h"
extern bool soundBufferLow;
namespace audio {
namespace internal {
namespace {
class DirectSound : public SoundDriver {
private:
LPDIRECTSOUND8 pDirectSound; // DirectSound interface
LPDIRECTSOUNDBUFFER dsbPrimary; // Primary DirectSound buffer
LPDIRECTSOUNDBUFFER dsbSecondary; // Secondary DirectSound buffer
LPDIRECTSOUND8 pDirectSound; // DirectSound interface
LPDIRECTSOUNDBUFFER dsbPrimary; // Primary DirectSound buffer
LPDIRECTSOUNDBUFFER dsbSecondary; // Secondary DirectSound buffer
LPDIRECTSOUNDNOTIFY dsbNotify;
HANDLE dsbEvent;
WAVEFORMATEX wfx; // Primary buffer wave format
WAVEFORMATEX wfx; // Primary buffer wave format
int soundBufferLen;
int soundBufferTotalLen;
unsigned int soundNextPosition;
public:
DirectSound();
virtual ~DirectSound();
~DirectSound() override;
bool init(long sampleRate); // initialize the primary and secondary sound buffer
void setThrottle(unsigned short throttle_); // set game speed
void pause(); // pause the secondary sound buffer
void reset(); // stop and reset the secondary sound buffer
void resume(); // resume the secondary sound buffer
void write(uint16_t* finalWave, int length); // write the emulated sound to the secondary sound buffer
// SoundDriver implementation.
bool init(long sampleRate) override;
void pause() override;
void reset() override;
void resume() override;
void write(uint16_t* finalWave, int length) override;
void setThrottle(unsigned short throttle_) override;
};
DirectSound::DirectSound()
{
DirectSound::DirectSound() {
pDirectSound = NULL;
dsbPrimary = NULL;
dsbSecondary = NULL;
@@ -50,8 +66,7 @@ DirectSound::DirectSound()
soundNextPosition = 0;
}
DirectSound::~DirectSound()
{
DirectSound::~DirectSound() {
if (dsbNotify) {
dsbNotify->Release();
dsbNotify = NULL;
@@ -78,13 +93,13 @@ DirectSound::~DirectSound()
}
}
bool DirectSound::init(long sampleRate)
{
bool DirectSound::init(long sampleRate) {
HRESULT hr;
DWORD freq;
DSBUFFERDESC dsbdesc;
int i;
hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8, (LPVOID*)&pDirectSound);
hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound8,
(LPVOID*)&pDirectSound);
if (hr != S_OK) {
wxLogError(_("Cannot create Direct Sound %08x"), hr);
@@ -93,10 +108,11 @@ bool DirectSound::init(long sampleRate)
GUID dev;
if (gopts.audio_dev.empty())
const wxString& audio_device = OPTION(kSoundAudioDevice);
if (audio_device.empty())
dev = DSDEVID_DefaultPlayback;
else
CLSIDFromString(gopts.audio_dev.wc_str(), &dev);
CLSIDFromString(audio_device.wc_str(), &dev);
pDirectSound->Initialize(&dev);
@@ -105,7 +121,8 @@ bool DirectSound::init(long sampleRate)
return false;
}
if (FAILED(hr = pDirectSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(), DSSCL_PRIORITY))) {
if (FAILED(hr = pDirectSound->SetCooperativeLevel((HWND)wxGetApp().frame->GetHandle(),
DSSCL_PRIORITY))) {
wxLogError(_("Cannot SetCooperativeLevel %08x"), hr);
return false;
}
@@ -115,7 +132,8 @@ bool DirectSound::init(long sampleRate)
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
if (!gopts.dsound_hw_accel) {
const bool hw_accel = OPTION(kSoundDSoundHWAccel);
if (!hw_accel) {
dsbdesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
}
@@ -146,9 +164,10 @@ bool DirectSound::init(long sampleRate)
// Create secondary sound buffer
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY;
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY |
DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY;
if (!gopts.dsound_hw_accel) {
if (!hw_accel) {
dsbdesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
}
@@ -165,7 +184,8 @@ bool DirectSound::init(long sampleRate)
return false;
}
if (SUCCEEDED(hr = dsbSecondary->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*)&dsbNotify))) {
if (SUCCEEDED(hr =
dsbSecondary->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*)&dsbNotify))) {
dsbEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
DSBPOSITIONNOTIFY notify[10];
@@ -195,7 +215,7 @@ void DirectSound::setThrottle(unsigned short throttle_) {
HRESULT hr;
if (throttle_ == 0)
throttle_ = 450; // Close to upper bound on frequency.
throttle_ = 450; // Close to upper bound on frequency.
long freq = soundGetSampleRate();
@@ -204,8 +224,7 @@ void DirectSound::setThrottle(unsigned short throttle_) {
}
}
void DirectSound::pause()
{
void DirectSound::pause() {
LPDIRECTSOUNDBUFFER bufs[] = {dsbPrimary, dsbSecondary};
for (auto buf : bufs) {
if (buf == NULL)
@@ -219,8 +238,7 @@ void DirectSound::pause()
}
}
void DirectSound::reset()
{
void DirectSound::reset() {
if (dsbSecondary == NULL)
return;
@@ -229,8 +247,7 @@ void DirectSound::reset()
soundNextPosition = 0;
}
void DirectSound::resume()
{
void DirectSound::resume() {
LPDIRECTSOUNDBUFFER bufs[] = {dsbPrimary, dsbSecondary};
for (auto buf : bufs) {
if (buf == NULL)
@@ -240,8 +257,7 @@ void DirectSound::resume()
}
}
void DirectSound::write(uint16_t* finalWave, int)
{
void DirectSound::write(uint16_t* finalWave, int) {
if (!pDirectSound)
return;
@@ -260,7 +276,9 @@ void DirectSound::write(uint16_t* finalWave, int)
if (!soundPaused) {
while (true) {
dsbSecondary->GetCurrentPosition(&play, NULL);
int BufferLeft = ((soundNextPosition <= play) ? play - soundNextPosition : soundBufferTotalLen - soundNextPosition + play);
int BufferLeft = ((soundNextPosition <= play)
? play - soundNextPosition
: soundBufferTotalLen - soundNextPosition + play);
if (BufferLeft > soundBufferLen) {
if (BufferLeft > soundBufferTotalLen - (soundBufferLen * 3))
@@ -285,24 +303,12 @@ void DirectSound::write(uint16_t* finalWave, int)
// Obtain memory address of write block.
// This will be in two parts if the block wraps around.
if (DSERR_BUFFERLOST == (hr = dsbSecondary->Lock(
soundNextPosition,
soundBufferLen,
&lpvPtr1,
&dwBytes1,
&lpvPtr2,
&dwBytes2,
0))) {
if (DSERR_BUFFERLOST == (hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen, &lpvPtr1,
&dwBytes1, &lpvPtr2, &dwBytes2, 0))) {
// If DSERR_BUFFERLOST is returned, restore and retry lock.
dsbSecondary->Restore();
hr = dsbSecondary->Lock(
soundNextPosition,
soundBufferLen,
&lpvPtr1,
&dwBytes1,
&lpvPtr2,
&dwBytes2,
0);
hr = dsbSecondary->Lock(soundNextPosition, soundBufferLen, &lpvPtr1, &dwBytes1, &lpvPtr2,
&dwBytes2, 0);
}
soundNextPosition += soundBufferLen;
@@ -324,27 +330,33 @@ void DirectSound::write(uint16_t* finalWave, int)
}
}
SoundDriver* newDirectSound()
{
return new DirectSound();
}
static BOOL CALLBACK DSEnumCB(LPGUID guid, LPCTSTR desc, LPCTSTR /*module*/, LPVOID user) {
std::vector<AudioDevice>* devices = static_cast<std::vector<AudioDevice>*>(user);
struct devnames {
wxArrayString *names, *ids;
};
if (guid == nullptr) {
devices->push_back({desc, {}});
return TRUE;
}
static BOOL CALLBACK DSEnumCB(LPGUID guid, LPCTSTR desc, LPCTSTR, LPVOID user)
{
devnames* dn = (devnames*)user;
dn->names->push_back(desc);
WCHAR buf[32 + 4 + 2 + 1]; // hex digits + "-" + "{}" + \0
StringFromGUID2(*guid, buf, sizeof(buf));
dn->ids->push_back(buf);
static constexpr size_t kGuidLength = 32 + 4 + 2 + 1; // hex digits + "-" + "{}" + \0
std::array<WCHAR, kGuidLength> device_id;
StringFromGUID2(*guid, device_id.data(), device_id.size());
devices->push_back({desc, device_id.data()});
return TRUE;
}
bool GetDSDevices(wxArrayString& names, wxArrayString& ids)
{
devnames dn = { &names, &ids };
return DirectSoundEnumerate(DSEnumCB, (LPVOID)&dn) == DS_OK;
} // namespace
std::vector<AudioDevice> GetDirectSoundDevices() {
std::vector<AudioDevice> devices;
DirectSoundEnumerateW(DSEnumCB, &devices);
return devices;
}
std::unique_ptr<SoundDriver> CreateDirectSoundDriver() {
return std::make_unique<DirectSound>();
}
} // namespace internal
} // namespace audio

View File

@@ -0,0 +1,22 @@
#ifndef WX_AUDIO_INTERNAL_DSOUND_H_
#define WX_AUDIO_INTERNAL_DSOUND_H_
#if !defined(__WXMSW__)
#error "This file should only be included on Windows"
#endif
#include "wx/audio/audio.h"
namespace audio {
namespace internal {
// Returns the set of DirectSound devices.
std::vector<AudioDevice> GetDirectSoundDevices();
// Creates a DirectSound sound driver.
std::unique_ptr<SoundDriver> CreateDirectSoundDriver();
} // namespace internal
} // namespace audio
#endif // WX_AUDIO_INTERNAL_DSOUND_H_

View File

@@ -0,0 +1,516 @@
#include <wx/string.h>
#if !defined(VBAM_ENABLE_FAUDIO)
#error "This file should only be compiled if FAudio is enabled"
#endif
#include "wx/audio/internal/faudio.h"
#include <condition_variable>
#include <mutex>
#include <vector>
// FAudio
#include <FAudio.h>
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/translation.h>
#include "core/base/check.h"
#include "core/base/system.h"
#include "core/gba/gbaGlobals.h"
#include "wx/config/option-proxy.h"
namespace audio {
namespace internal {
namespace {
int FAGetDev(FAudio* fa) {
const wxString& audio_device = OPTION(kSoundAudioDevice);
if (audio_device.empty()) {
// Just use the default device.
return 0;
}
uint32_t hr;
uint32_t dev_count = 0;
hr = FAudio_GetDeviceCount(fa, &dev_count);
if (hr != 0) {
wxLogError(_("FAudio: Enumerating devices failed!"));
return 0;
}
FAudioDeviceDetails dd;
for (uint32_t i = 0; i < dev_count; i++) {
hr = FAudio_GetDeviceDetails(fa, i, &dd);
if (hr != 0) {
continue;
}
const wxString device_id(reinterpret_cast<wchar_t*>(dd.DeviceID));
if (audio_device == device_id) {
return i;
}
}
return 0;
}
class FAudio_BufferNotify : public FAudioVoiceCallback {
public:
// Waits for the buffer end event to be signaled for 10 seconds.
// Returns true if the buffer end event was signaled, false if the wait timed out.
bool WaitForSignal() {
std::unique_lock<std::mutex> lock(mutex_);
waiting_for_buffer_end_ = true;
const bool was_signaled =
buffer_end_cv_.wait_for(lock, std::chrono::seconds(10), [this] { return signaled_; });
waiting_for_buffer_end_ = false;
signaled_ = false;
return was_signaled;
}
FAudio_BufferNotify() {
OnBufferEnd = &FAudio_BufferNotify::StaticOnBufferEnd;
OnVoiceProcessingPassStart = &FAudio_BufferNotify::StaticOnVoiceProcessingPassStart;
OnVoiceProcessingPassEnd = &FAudio_BufferNotify::StaticOnVoiceProcessingPassEnd;
OnStreamEnd = &FAudio_BufferNotify::StaticOnStreamEnd;
OnBufferStart = &FAudio_BufferNotify::StaticOnBufferStart;
OnLoopEnd = &FAudio_BufferNotify::StaticOnLoopEnd;
OnVoiceError = &FAudio_BufferNotify::StaticOnVoiceError;
}
~FAudio_BufferNotify() = default;
private:
// Signals that the buffer end event has occurred.
void SignalBufferEnd() {
std::lock_guard<std::mutex> lock(mutex_);
if (!waiting_for_buffer_end_) {
return;
}
signaled_ = true;
buffer_end_cv_.notify_one();
}
// Protects `waiting_for_buffer_end_` and `signaled_`.
std::mutex mutex_;
// Used to wait for the buffer end event.
std::condition_variable buffer_end_cv_;
// Set to true when we are waiting for the buffer end event.
// Must be protected by `mutex_`.
bool waiting_for_buffer_end_ = false;
// Set to true when the buffer end event has been signaled.
// Must be protected by `mutex_`.
bool signaled_ = false;
static void StaticOnBufferEnd(FAudioVoiceCallback* callback, void*) {
static_cast<FAudio_BufferNotify*>(callback)->SignalBufferEnd();
}
static void StaticOnVoiceProcessingPassStart(FAudioVoiceCallback*, uint32_t) {}
static void StaticOnVoiceProcessingPassEnd(FAudioVoiceCallback*) {}
static void StaticOnStreamEnd(FAudioVoiceCallback*) {}
static void StaticOnBufferStart(FAudioVoiceCallback*, void*) {}
static void StaticOnLoopEnd(FAudioVoiceCallback*, void*) {}
static void StaticOnVoiceError(FAudioVoiceCallback*, void*, uint32_t) {}
};
class FAudio_Output : public SoundDriver {
public:
FAudio_Output();
~FAudio_Output();
void device_change();
private:
void close();
// SoundDriver implementation.
bool init(long sampleRate) override;
void pause() override;
void reset() override;
void resume() override;
void write(uint16_t* finalWave, int length) override;
void setThrottle(unsigned short throttle_) override;
bool failed;
bool initialized;
bool playing;
uint32_t freq_;
const uint32_t buffer_count_;
std::vector<uint8_t> buffers_;
int currentBuffer;
int sound_buffer_len_;
volatile bool device_changed;
FAudio* faud;
FAudioMasteringVoice* mVoice; // listener
FAudioSourceVoice* sVoice; // sound source
FAudioBuffer buf;
FAudioVoiceState vState;
FAudio_BufferNotify notify; // buffer end notification
};
// Class Implementation
FAudio_Output::FAudio_Output() : buffer_count_(OPTION(kSoundBuffers)) {
failed = false;
initialized = false;
playing = false;
freq_ = 0;
currentBuffer = 0;
device_changed = false;
faud = nullptr;
mVoice = nullptr;
sVoice = nullptr;
memset(&buf, 0, sizeof(buf));
memset(&vState, 0, sizeof(vState));
}
FAudio_Output::~FAudio_Output() {
close();
}
void FAudio_Output::close() {
initialized = false;
if (sVoice) {
if (playing) {
VBAM_CHECK(FAudioSourceVoice_Stop(sVoice, 0, FAUDIO_COMMIT_NOW) == 0);
}
FAudioVoice_DestroyVoice(sVoice);
sVoice = nullptr;
}
if (mVoice) {
FAudioVoice_DestroyVoice(mVoice);
mVoice = nullptr;
}
if (faud) {
FAudio_Release(faud);
faud = nullptr;
}
}
void FAudio_Output::device_change() {
device_changed = true;
}
bool FAudio_Output::init(long sampleRate) {
if (failed || initialized)
return false;
uint32_t hr;
// Initialize FAudio
uint32_t flags = 0;
// #ifdef _DEBUG
// flags = FAUDIO_DEBUG_ENGINE;
// #endif
hr = FAudioCreate(&faud, flags, FAUDIO_DEFAULT_PROCESSOR);
if (hr != 0) {
wxLogError(_("The FAudio interface failed to initialize!"));
failed = true;
return false;
}
freq_ = sampleRate;
// calculate the number of samples per frame first
// then multiply it with the size of a sample frame (16 bit * stereo)
sound_buffer_len_ = (freq_ / 60) * 4;
// create own buffers to store sound data because it must not be
// manipulated while the voice plays from it.
// +1 because we need one temporary buffer when all others are in use.
buffers_.resize((buffer_count_ + 1) * sound_buffer_len_);
static const uint16_t kNumChannels = 2;
static const uint16_t kBitsPerSample = 16;
static const uint16_t kBlockAlign = kNumChannels * (kBitsPerSample / 8);
FAudioWaveFormatEx wfx{
/*.wFormatTag=*/FAUDIO_FORMAT_PCM,
/*.nChannels=*/kNumChannels,
/*.nSamplesPerSec=*/freq_,
/*.nAvgBytesPerSec=*/freq_ * kBlockAlign,
/*.nBlockAlign=*/kNumChannels * (kBitsPerSample / 8),
/*.wBitsPerSample=*/kBitsPerSample,
/*.cbSize=*/0,
};
// create sound receiver
hr = FAudio_CreateMasteringVoice(faud, &mVoice, FAUDIO_DEFAULT_CHANNELS,
FAUDIO_DEFAULT_SAMPLERATE, 0, FAGetDev(faud), nullptr);
if (hr != 0) {
wxLogError(_("FAudio: Creating mastering voice failed!"));
failed = true;
return false;
}
// create sound emitter
hr = FAudio_CreateSourceVoice(faud, &sVoice, &wfx, 0, 4.0f, &notify, nullptr, nullptr);
if (hr != 0) {
wxLogError(_("FAudio: Creating source voice failed!"));
failed = true;
return false;
}
if (OPTION(kSoundUpmix)) {
// set up stereo upmixing
FAudioDeviceDetails dd{};
VBAM_CHECK(FAudio_GetDeviceDetails(faud, 0, &dd) == 0);
std::vector<float> matrix(sizeof(float) * 2 * dd.OutputFormat.Format.nChannels);
bool matrixAvailable = true;
switch (dd.OutputFormat.Format.nChannels) {
case 4: // 4.0
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Back L*/ matrix[4] = 1.0000f;
matrix[5] = 0.0000f;
/*Back R*/ matrix[6] = 0.0000f;
matrix[7] = 1.0000f;
break;
case 5: // 5.0
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*Side L*/ matrix[6] = 1.0000f;
matrix[7] = 0.0000f;
/*Side R*/ matrix[8] = 0.0000f;
matrix[9] = 1.0000f;
break;
case 6: // 5.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
break;
case 7: // 6.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Back C*/ matrix[12] = 0.7071f;
matrix[13] = 0.7071f;
break;
case 8: // 7.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Back L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Back R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Side L*/ matrix[12] = 1.0000f;
matrix[13] = 0.0000f;
/*Side R*/ matrix[14] = 0.0000f;
matrix[15] = 1.0000f;
break;
default:
matrixAvailable = false;
break;
}
if (matrixAvailable) {
hr = FAudioVoice_SetOutputMatrix(sVoice, nullptr, 2, dd.OutputFormat.Format.nChannels,
matrix.data(), FAUDIO_DEFAULT_CHANNELS);
VBAM_CHECK(hr == 0);
}
}
hr = FAudioSourceVoice_Start(sVoice, 0, FAUDIO_COMMIT_NOW);
VBAM_CHECK(hr == 0);
playing = true;
currentBuffer = 0;
device_changed = false;
initialized = true;
return true;
}
void FAudio_Output::write(uint16_t* finalWave, int) {
uint32_t flags = 0;
if (!initialized || failed)
return;
while (true) {
if (device_changed) {
close();
if (!init(freq_))
return;
}
FAudioSourceVoice_GetState(sVoice, &vState, flags);
VBAM_CHECK(vState.BuffersQueued <= buffer_count_);
if (vState.BuffersQueued < buffer_count_) {
if (vState.BuffersQueued == 0) {
// buffers ran dry
if (systemVerbose & VERBOSE_SOUNDOUTPUT) {
static unsigned int i = 0;
log("FAudio: Buffers were not refilled fast enough (i=%i)\n", i++);
}
}
// there is at least one free buffer
break;
} else {
// the maximum number of buffers is currently queued
if (!coreOptions.speedup && coreOptions.throttle && !gba_joybus_active) {
// wait for one buffer to finish playing
if (notify.WaitForSignal()) {
device_changed = true;
}
} else {
// drop current audio frame
return;
}
}
}
// copy & protect the audio data in own memory area while playing it
memcpy(&buffers_[currentBuffer * sound_buffer_len_], finalWave, sound_buffer_len_);
buf.AudioBytes = sound_buffer_len_;
buf.pAudioData = &buffers_[currentBuffer * sound_buffer_len_];
currentBuffer++;
currentBuffer %= (buffer_count_ + 1); // + 1 because we need one temporary buffer
[[maybe_unused]] uint32_t hr = FAudioSourceVoice_SubmitSourceBuffer(sVoice, &buf, nullptr);
VBAM_CHECK(hr == 0);
}
void FAudio_Output::pause() {
if (!initialized || failed)
return;
if (playing) {
[[maybe_unused]] uint32_t hr = FAudioSourceVoice_Stop(sVoice, 0, FAUDIO_COMMIT_NOW);
VBAM_CHECK(hr == 0);
playing = false;
}
}
void FAudio_Output::resume() {
if (!initialized || failed)
return;
if (!playing) {
[[maybe_unused]] int32_t hr = FAudioSourceVoice_Start(sVoice, 0, FAUDIO_COMMIT_NOW);
VBAM_CHECK(hr == 0);
playing = true;
}
}
void FAudio_Output::reset() {
if (!initialized || failed)
return;
if (playing) {
[[maybe_unused]] uint32_t hr = FAudioSourceVoice_Stop(sVoice, 0, FAUDIO_COMMIT_NOW);
VBAM_CHECK(hr == 0);
}
FAudioSourceVoice_FlushSourceBuffers(sVoice);
FAudioSourceVoice_Start(sVoice, 0, FAUDIO_COMMIT_NOW);
playing = true;
}
void FAudio_Output::setThrottle(unsigned short throttle_) {
if (!initialized || failed)
return;
if (throttle_ == 0)
throttle_ = 100;
[[maybe_unused]] uint32_t hr =
FAudioSourceVoice_SetFrequencyRatio(sVoice, (float)throttle_ / 100.0f, FAUDIO_COMMIT_NOW);
VBAM_CHECK(hr == 0);
}
} // namespace
std::vector<AudioDevice> GetFAudioDevices() {
FAudio* fa = nullptr;
uint32_t hr;
uint32_t flags = 0;
#ifdef _DEBUG
flags = FAUDIO_DEBUG_ENGINE;
#endif
hr = FAudioCreate(&fa, flags, FAUDIO_DEFAULT_PROCESSOR);
if (hr != 0) {
wxLogError(_("The FAudio interface failed to initialize!"));
return {};
}
uint32_t dev_count = 0;
hr = FAudio_GetDeviceCount(fa, &dev_count);
if (hr != 0) {
wxLogError(_("FAudio: Enumerating devices failed!"));
return {};
}
std::vector<AudioDevice> devices;
devices.reserve(dev_count + 1);
devices.push_back({_("Default device"), wxEmptyString});
for (uint32_t i = 0; i < dev_count; i++) {
FAudioDeviceDetails dd;
hr = FAudio_GetDeviceDetails(fa, i, &dd);
if (hr != 0) {
continue;
}
const wxString display_name(reinterpret_cast<wchar_t*>(dd.DisplayName));
const wxString device_id(reinterpret_cast<wchar_t*>(dd.DeviceID));
devices.push_back({display_name, device_id});
}
FAudio_Release(fa);
return devices;
}
std::unique_ptr<SoundDriver> CreateFAudioDriver() {
return std::make_unique<FAudio_Output>();
}
} // namespace internal
} // namespace audio

View File

@@ -0,0 +1,22 @@
#ifndef WX_AUDIO_INTERNAL_FAUDIO_H_
#define WX_AUDIO_INTERNAL_FAUDIO_H_
#if !defined(VBAM_ENABLE_FAUDIO)
#error "This file should only be included if FAudio is enabled"
#endif
#include "wx/audio/audio.h"
namespace audio {
namespace internal {
// Returns the set of FAudio devices.
std::vector<AudioDevice> GetFAudioDevices();
// Creates an FAudio sound driver.
std::unique_ptr<SoundDriver> CreateFAudioDriver();
} // namespace internal
} // namespace audio
#endif // WX_AUDIO_INTERNAL_FAUDIO_H_

View File

@@ -1,25 +1,52 @@
#include "wx/audio/internal/openal.h"
// === LOGALL writes very detailed informations to vba-trace.log ===
//#define LOGALL
// #define LOGALL
#ifndef NO_OAL
// on win32 and mac, pointer typedefs only happen with AL_NO_PROTOTYPES
// on mac, ALC_NO_PROTOTYPES as well
// for gopts
// also, wx-related
#include "wx/wxvbam.h"
// #define AL_NO_PROTOTYPES 1
// Interface
#include "core/base/sound_driver.h"
// on mac, alc pointer typedefs ony happen for ALC if ALC_NO_PROTOTYPES
// unfortunately, there is a bug in the system headers (use of ALCvoid when
// void should be used; shame on Apple for introducing this error, and shame
// on Creative for making a typedef to void in the first place)
// #define ALC_NO_PROTOTYPES 1
// OpenAL
#include "openal.h"
#include <al.h>
#include <alc.h>
// Internals
#include "core/gba/gbaGlobals.h" // for 'speedup' and 'synchronize'
// since the ALC typedefs are broken on Mac:
#ifdef __WXMAC__
typedef ALCcontext*(ALC_APIENTRY* LPALCCREATECONTEXT)(ALCdevice* device, const ALCint* attrlist);
typedef ALCboolean(ALC_APIENTRY* LPALCMAKECONTEXTCURRENT)(ALCcontext* context);
typedef void(ALC_APIENTRY* LPALCDESTROYCONTEXT)(ALCcontext* context);
typedef ALCdevice*(ALC_APIENTRY* LPALCOPENDEVICE)(const ALCchar* devicename);
typedef ALCboolean(ALC_APIENTRY* LPALCCLOSEDEVICE)(ALCdevice* device);
typedef ALCboolean(ALC_APIENTRY* LPALCISEXTENSIONPRESENT)(ALCdevice* device,
const ALCchar* extname);
typedef const ALCchar*(ALC_APIENTRY* LPALCGETSTRING)(ALCdevice* device, ALCenum param);
#endif
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/translation.h>
#include <wx/utils.h>
#include "core/base/check.h"
#include "core/gba/gbaGlobals.h"
#include "core/gba/gbaSound.h"
#include "wx/config/option-proxy.h"
namespace audio {
namespace internal {
namespace {
// Debug
#include <assert.h>
#define ASSERT_SUCCESS assert(AL_NO_ERROR == alGetError())
#define ASSERT_SUCCESS VBAM_CHECK(AL_NO_ERROR == alGetError())
#ifndef LOGALL
// replace logging functions with comments
@@ -27,8 +54,10 @@
#undef winlog
#endif
// https://stackoverflow.com/a/1306690/262458
#define winlog(x,...) do {} while(0)
#define debugState() //
#define winlog(x, ...) \
do { \
} while (0)
#define debugState() //
#endif
struct OPENALFNTABLE;
@@ -36,15 +65,15 @@ struct OPENALFNTABLE;
class OpenAL : public SoundDriver {
public:
OpenAL();
virtual ~OpenAL();
~OpenAL() override;
static bool GetDevices(wxArrayString& names, wxArrayString& ids);
bool init(long sampleRate); // initialize the sound buffer queue
void setThrottle(unsigned short throttle_); // set game speed
void pause(); // pause the secondary sound buffer
void reset(); // stop and reset the secondary sound buffer
void resume(); // play/resume the secondary sound buffer
void write(uint16_t* finalWave, int length); // write the emulated sound to a sound buffer
bool init(long sampleRate) override; // initialize the sound buffer queue
void setThrottle(unsigned short throttle_) override; // set game speed
void pause() override; // pause the secondary sound buffer
void reset() override; // stop and reset the secondary sound buffer
void resume() override; // play/resume the secondary sound buffer
void write(uint16_t* finalWave,
int length) override; // write the emulated sound to a sound buffer
private:
bool initialized;
@@ -62,20 +91,18 @@ private:
#endif
};
OpenAL::OpenAL()
{
OpenAL::OpenAL() {
initialized = false;
buffersLoaded = false;
device = NULL;
context = NULL;
buffer = (ALuint*)malloc(gopts.audio_buffers * sizeof(ALuint));
memset(buffer, 0, gopts.audio_buffers * sizeof(ALuint));
device = nullptr;
context = nullptr;
buffer = (ALuint*)malloc(OPTION(kSoundBuffers) * sizeof(ALuint));
memset(buffer, 0, OPTION(kSoundBuffers) * sizeof(ALuint));
tempBuffer = 0;
source = 0;
}
OpenAL::~OpenAL()
{
OpenAL::~OpenAL() {
if (!initialized)
return;
@@ -85,25 +112,24 @@ OpenAL::~OpenAL()
ASSERT_SUCCESS;
alDeleteSources(1, &source);
ASSERT_SUCCESS;
alDeleteBuffers(gopts.audio_buffers, buffer);
alDeleteBuffers(OPTION(kSoundBuffers), buffer);
ASSERT_SUCCESS;
free(buffer);
alcMakeContextCurrent(NULL);
alcMakeContextCurrent(nullptr);
// Wine incorrectly returns ALC_INVALID_VALUE
// and then fails the rest of these functions as well
// so there will be a leak under Wine, but that's a bug in Wine, not
// this code
//ASSERT_SUCCESS;
// ASSERT_SUCCESS;
alcDestroyContext(context);
//ASSERT_SUCCESS;
// ASSERT_SUCCESS;
alcCloseDevice(device);
//ASSERT_SUCCESS;
alGetError(); // reset error state
// ASSERT_SUCCESS;
alGetError(); // reset error state
}
#ifdef LOGALL
void OpenAL::debugState()
{
void OpenAL::debugState() {
ALint value = 0;
alGetSourcei(source, AL_SOURCE_STATE, &value);
ASSERT_SUCCESS;
@@ -112,28 +138,27 @@ void OpenAL::debugState()
winlog(" State: ");
switch (value) {
case AL_INITIAL:
winlog("AL_INITIAL\n");
break;
case AL_INITIAL:
winlog("AL_INITIAL\n");
break;
case AL_PLAYING:
winlog("AL_PLAYING\n");
break;
case AL_PLAYING:
winlog("AL_PLAYING\n");
break;
case AL_PAUSED:
winlog("AL_PAUSED\n");
break;
case AL_PAUSED:
winlog("AL_PAUSED\n");
break;
case AL_STOPPED:
winlog("AL_STOPPED\n");
break;
case AL_STOPPED:
winlog("AL_STOPPED\n");
break;
default:
winlog("!unknown!\n");
break;
default:
winlog("!unknown!\n");
break;
}
alGetSourcei(source, AL_BUFFERS_QUEUED, &value);
ASSERT_SUCCESS;
winlog(" Buffers in queue: %i\n", value);
@@ -143,23 +168,32 @@ void OpenAL::debugState()
}
#endif
bool OpenAL::init(long sampleRate)
{
bool OpenAL::init(long sampleRate) {
winlog("OpenAL::init\n");
assert(initialized == false);
VBAM_CHECK(initialized == false);
if (!gopts.audio_dev.empty()) {
device = alcOpenDevice(gopts.audio_dev.utf8_str());
const wxString& audio_device = OPTION(kSoundAudioDevice);
if (!audio_device.empty()) {
device = alcOpenDevice(audio_device.utf8_str());
if (device == nullptr) {
// Might be the default device. Try again.
OPTION(kSoundAudioDevice) = wxEmptyString;
device = alcOpenDevice(nullptr);
}
} else {
device = alcOpenDevice(NULL);
device = alcOpenDevice(nullptr);
}
assert(device != NULL);
context = alcCreateContext(device, NULL);
assert(context != NULL);
if (!device) {
wxLogError(_("OpenAL: Failed to open audio device"));
return false;
}
context = alcCreateContext(device, nullptr);
VBAM_CHECK(context != nullptr);
ALCboolean retVal = alcMakeContextCurrent(context);
assert(ALC_TRUE == retVal);
alGenBuffers(gopts.audio_buffers, buffer);
VBAM_CHECK(ALC_TRUE == retVal);
alGenBuffers(OPTION(kSoundBuffers), buffer);
ASSERT_SUCCESS;
alGenSources(1, &source);
ASSERT_SUCCESS;
@@ -182,8 +216,7 @@ void OpenAL::setThrottle(unsigned short throttle_) {
ASSERT_SUCCESS;
}
void OpenAL::resume()
{
void OpenAL::resume() {
if (!initialized)
return;
@@ -205,8 +238,7 @@ void OpenAL::resume()
debugState();
}
void OpenAL::pause()
{
void OpenAL::pause() {
if (!initialized)
return;
@@ -228,8 +260,7 @@ void OpenAL::pause()
debugState();
}
void OpenAL::reset()
{
void OpenAL::reset() {
if (!initialized)
return;
@@ -251,9 +282,8 @@ void OpenAL::reset()
debugState();
}
void OpenAL::write(uint16_t* finalWave, int length)
{
(void)length; // unused param
void OpenAL::write(uint16_t* finalWave, int length) {
(void)length; // unused param
if (!initialized)
return;
@@ -266,14 +296,14 @@ void OpenAL::write(uint16_t* finalWave, int length)
// ==initial buffer filling==
winlog(" initial buffer filling\n");
for (int i = 0; i < gopts.audio_buffers; i++) {
for (int i = 0; i < OPTION(kSoundBuffers); i++) {
// Filling the buffers explicitly with silence would be cleaner,
// but the very first sample is usually silence anyway.
alBufferData(buffer[i], AL_FORMAT_STEREO16, finalWave, soundBufferLen, freq);
ASSERT_SUCCESS;
}
alSourceQueueBuffers(source, gopts.audio_buffers, buffer);
alSourceQueueBuffers(source, OPTION(kSoundBuffers), buffer);
ASSERT_SUCCESS;
buffersLoaded = true;
} else {
@@ -282,7 +312,7 @@ void OpenAL::write(uint16_t* finalWave, int length)
alGetSourcei(source, AL_BUFFERS_PROCESSED, &nBuffersProcessed);
ASSERT_SUCCESS;
if (nBuffersProcessed == gopts.audio_buffers) {
if (nBuffersProcessed == OPTION(kSoundBuffers)) {
// we only want to know about it when we are emulating at full speed or faster:
if ((coreOptions.throttle >= 100) || (coreOptions.throttle == 0)) {
if (systemVerbose & VERBOSE_SOUNDOUTPUT) {
@@ -307,7 +337,7 @@ void OpenAL::write(uint16_t* finalWave, int length)
return;
}
assert(nBuffersProcessed > 0);
VBAM_CHECK(nBuffersProcessed > 0);
// unqueue buffer
tempBuffer = 0;
@@ -331,37 +361,39 @@ void OpenAL::write(uint16_t* finalWave, int length)
}
}
SoundDriver* newOpenAL()
{
winlog("newOpenAL\n");
return new OpenAL();
}
} // namespace
bool GetOALDevices(wxArrayString& names, wxArrayString& ids)
{
return OpenAL::GetDevices(names, ids);
}
std::vector<AudioDevice> GetOpenALDevices() {
std::vector<AudioDevice> devices;
bool OpenAL::GetDevices(wxArrayString& names, wxArrayString& ids)
{
#ifdef ALC_DEVICE_SPECIFIER
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_FALSE)
if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_FALSE) {
// this extension isn't critical to OpenAL operating
return true;
return devices;
}
const char* devs = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
const char* devs = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
while (*devs) {
names.push_back(wxString(devs, wxConvLibc));
ids.push_back(names[names.size() - 1]);
const wxString device_name(devs, wxConvLibc);
devices.push_back({device_name, device_name});
devs += strlen(devs) + 1;
}
#else
devices.push_back({_("Default device"), wxEmptyString});
#endif
// should work anyway, but must always use default driver
return true;
return devices;
}
#endif
std::unique_ptr<SoundDriver> CreateOpenALDriver() {
winlog("newOpenAL\n");
return std::make_unique<OpenAL>();
}
} // namespace internal
} // namespace audio

View File

@@ -0,0 +1,18 @@
#ifndef WX_AUDIO_INTERNAL_OPENAL_H_
#define WX_AUDIO_INTERNAL_OPENAL_H_
#include "wx/audio/audio.h"
namespace audio {
namespace internal {
// Returns the set of OpenAL devices.
std::vector<AudioDevice> GetOpenALDevices();
// Creates an OpenAL sound driver.
std::unique_ptr<SoundDriver> CreateOpenALDriver();
} // namespace internal
} // namespace audio
#endif // WX_AUDIO_INTERNAL_OPENAL_H_

View File

@@ -1,88 +1,70 @@
#ifndef NO_XAUDIO2
#if !defined(VBAM_ENABLE_XAUDIO2)
#error "This file should only be compiled if XAudio2 is enabled"
#endif
// Application
#include "wx/wxvbam.h"
#include <stdio.h>
#include "wx/audio/internal/xaudio2.h"
// Interface
#include "core/base/sound_driver.h"
#include <cstdio>
#include <string>
#include <vector>
// MMDevice API
#include <mmdeviceapi.h>
// XAudio2
#if _MSC_VER
#include <xaudio2.legacy.h>
#else
#include <XAudio2.h>
#endif
#endif
// MMDevice API
#include <mmdeviceapi.h>
#include <string>
#include <vector>
#include <wx/arrstr.h>
#include <wx/log.h>
#include <wx/translation.h>
// Internals
#include "core/base/system.h" // for systemMessage()
#include "core/base/sound_driver.h"
#include "core/base/system.h" // for systemMessage()
#include "core/gba/gbaGlobals.h"
#include "wx/config/option-proxy.h"
int GetXA2Devices(IXAudio2* xa, wxArrayString* names, wxArrayString* ids,
const wxString* match)
{
HRESULT hr;
UINT32 dev_count = 0;
hr = xa->GetDeviceCount(&dev_count);
namespace audio {
namespace internal {
if (hr != S_OK) {
wxLogError(_("XAudio2: Enumerating devices failed!"));
return true;
} else {
XAUDIO2_DEVICE_DETAILS dd;
namespace {
for (UINT32 i = 0; i < dev_count; i++) {
hr = xa->GetDeviceDetails(i, &dd);
if (hr != S_OK) {
continue;
} else {
if (ids) {
ids->push_back(dd.DeviceID);
names->push_back(dd.DisplayName);
} else if (*match == dd.DeviceID)
return i;
}
}
int XA2GetDev(IXAudio2* xa) {
const wxString& audio_device = OPTION(kSoundAudioDevice);
if (audio_device.empty()) {
// Just use the default device.
return 0;
}
return -1;
}
bool GetXA2Devices(wxArrayString& names, wxArrayString& ids)
{
HRESULT hr;
IXAudio2* xa = NULL;
hr = XAudio2Create(&xa, 0);
uint32_t hr;
uint32_t dev_count = 0;
hr = xa->GetDeviceCount(&dev_count);
if (hr != S_OK) {
wxLogError(_("The XAudio2 interface failed to initialize!"));
wxLogError(_("XAudio2: Enumerating devices failed!"));
return false;
}
GetXA2Devices(xa, &names, &ids, NULL);
xa->Release();
return true;
}
static int XA2GetDev(IXAudio2* xa)
{
if (gopts.audio_dev.empty())
return 0;
else {
int ret = GetXA2Devices(xa, NULL, NULL, &gopts.audio_dev);
return ret < 0 ? 0 : ret;
for (UINT32 i = 0; i < dev_count; i++) {
XAUDIO2_DEVICE_DETAILS dd;
hr = xa->GetDeviceDetails(i, &dd);
if (hr != S_OK) {
continue;
}
const wxString device_id(reinterpret_cast<wchar_t*>(dd.DeviceID));
if (audio_device == device_id) {
return i;
}
}
return 0;
}
class XAudio2_Output;
static void xaudio2_device_changed(XAudio2_Output*);
void xaudio2_device_changed(XAudio2_Output*);
class XAudio2_Device_Notifier : public IMMNotificationClient {
volatile LONG registered;
@@ -94,28 +76,14 @@ class XAudio2_Device_Notifier : public IMMNotificationClient {
std::vector<XAudio2_Output*> instances;
public:
XAudio2_Device_Notifier()
: registered(0)
{
InitializeCriticalSection(&lock);
}
~XAudio2_Device_Notifier()
{
DeleteCriticalSection(&lock);
}
XAudio2_Device_Notifier() : registered(0) { InitializeCriticalSection(&lock); }
~XAudio2_Device_Notifier() { DeleteCriticalSection(&lock); }
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE AddRef() { return 1; }
ULONG STDMETHODCALLTYPE Release()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release() { return 1; }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface)
{
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) {
if (IID_IUnknown == riid) {
*ppvInterface = (IUnknown*)this;
} else if (__uuidof(IMMNotificationClient) == riid) {
@@ -128,8 +96,7 @@ public:
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole, LPCWSTR pwstrDeviceId)
{
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole, LPCWSTR pwstrDeviceId) {
if (flow == eRender && last_device.compare(pwstrDeviceId) != 0) {
last_device = pwstrDeviceId;
EnterCriticalSection(&lock);
@@ -149,11 +116,11 @@ public:
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) { return S_OK; }
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) { return S_OK; }
void do_register(XAudio2_Output* p_instance)
{
void do_register(XAudio2_Output* p_instance) {
if (InterlockedIncrement(&registered) == 1) {
pEnumerator = NULL;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
if (SUCCEEDED(hr)) {
pEnumerator->RegisterEndpointNotificationCallback(this);
@@ -165,8 +132,7 @@ public:
LeaveCriticalSection(&lock);
}
void do_unregister(XAudio2_Output* p_instance)
{
void do_unregister(XAudio2_Output* p_instance) {
if (InterlockedDecrement(&registered) == 0) {
if (pEnumerator) {
pEnumerator->UnregisterEndpointNotificationCallback(this);
@@ -193,22 +159,19 @@ class XAudio2_BufferNotify : public IXAudio2VoiceCallback {
public:
HANDLE hBufferEndEvent;
XAudio2_BufferNotify()
{
XAudio2_BufferNotify() {
hBufferEndEvent = NULL;
hBufferEndEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
assert(hBufferEndEvent != NULL);
}
~XAudio2_BufferNotify()
{
~XAudio2_BufferNotify() {
CloseHandle(hBufferEndEvent);
hBufferEndEvent = NULL;
}
STDMETHOD_(void, OnBufferEnd)
(void*)
{
(void*) {
assert(hBufferEndEvent != NULL);
SetEvent(hBufferEndEvent);
}
@@ -229,29 +192,24 @@ public:
};
// Class Declaration
class XAudio2_Output
: public SoundDriver {
class XAudio2_Output : public SoundDriver {
public:
XAudio2_Output();
~XAudio2_Output();
~XAudio2_Output() override;
// Initialization
bool init(long sampleRate);
// Sound Data Feed
void write(uint16_t* finalWave, int length);
// Play Control
void pause();
void resume();
void reset();
void close();
void device_change();
// Configuration Changes
void setThrottle(unsigned short throttle);
private:
void close();
// SoundDriver implementation.
bool init(long sampleRate) override;
void pause() override;
void reset() override;
void resume() override;
void write(uint16_t* finalWave, int length) override;
void setThrottle(unsigned short throttle_) override;
bool failed;
bool initialized;
bool playing;
@@ -264,21 +222,20 @@ private:
volatile bool device_changed;
IXAudio2* xaud;
IXAudio2MasteringVoice* mVoice; // listener
IXAudio2SourceVoice* sVoice; // sound source
IXAudio2MasteringVoice* mVoice; // listener
IXAudio2SourceVoice* sVoice; // sound source
XAUDIO2_BUFFER buf;
XAUDIO2_VOICE_STATE vState;
XAudio2_BufferNotify notify; // buffer end notification
XAudio2_BufferNotify notify; // buffer end notification
};
// Class Implementation
XAudio2_Output::XAudio2_Output()
{
XAudio2_Output::XAudio2_Output() {
failed = false;
initialized = false;
playing = false;
freq = 0;
bufferCount = gopts.audio_buffers;
bufferCount = OPTION(kSoundBuffers);
buffers = NULL;
currentBuffer = 0;
device_changed = false;
@@ -290,14 +247,12 @@ XAudio2_Output::XAudio2_Output()
g_notifier.do_register(this);
}
XAudio2_Output::~XAudio2_Output()
{
XAudio2_Output::~XAudio2_Output() {
g_notifier.do_unregister(this);
close();
}
void XAudio2_Output::close()
{
void XAudio2_Output::close() {
initialized = false;
if (sVoice) {
@@ -326,13 +281,11 @@ void XAudio2_Output::close()
}
}
void XAudio2_Output::device_change()
{
void XAudio2_Output::device_change() {
device_changed = true;
}
bool XAudio2_Output::init(long sampleRate)
{
bool XAudio2_Output::init(long sampleRate) {
if (failed || initialized)
return false;
@@ -363,13 +316,8 @@ bool XAudio2_Output::init(long sampleRate)
wfx.nBlockAlign = wfx.nChannels * (wfx.wBitsPerSample / 8);
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
// create sound receiver
hr = xaud->CreateMasteringVoice(
&mVoice,
XAUDIO2_DEFAULT_CHANNELS,
XAUDIO2_DEFAULT_SAMPLERATE,
0,
XA2GetDev(xaud),
NULL);
hr = xaud->CreateMasteringVoice(&mVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE,
0, XA2GetDev(xaud), NULL);
if (hr != S_OK) {
wxLogError(_("XAudio2: Creating mastering voice failed!"));
@@ -386,7 +334,7 @@ bool XAudio2_Output::init(long sampleRate)
return false;
}
if (gopts.upmix) {
if (OPTION(kSoundUpmix)) {
// set up stereo upmixing
XAUDIO2_DEVICE_DETAILS dd;
ZeroMemory(&dd, sizeof(dd));
@@ -401,89 +349,89 @@ bool XAudio2_Output::init(long sampleRate)
bool matrixAvailable = true;
switch (dd.OutputFormat.Format.nChannels) {
case 4: // 4.0
//Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Back L*/ matrix[4] = 1.0000f;
matrix[5] = 0.0000f;
/*Back R*/ matrix[6] = 0.0000f;
matrix[7] = 1.0000f;
break;
case 4: // 4.0
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Back L*/ matrix[4] = 1.0000f;
matrix[5] = 0.0000f;
/*Back R*/ matrix[6] = 0.0000f;
matrix[7] = 1.0000f;
break;
case 5: // 5.0
//Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*Side L*/ matrix[6] = 1.0000f;
matrix[7] = 0.0000f;
/*Side R*/ matrix[8] = 0.0000f;
matrix[9] = 1.0000f;
break;
case 5: // 5.0
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*Side L*/ matrix[6] = 1.0000f;
matrix[7] = 0.0000f;
/*Side R*/ matrix[8] = 0.0000f;
matrix[9] = 1.0000f;
break;
case 6: // 5.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
break;
case 6: // 5.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
break;
case 7: // 6.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Back C*/ matrix[12] = 0.7071f;
matrix[13] = 0.7071f;
break;
case 7: // 6.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Side L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Side R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Back C*/ matrix[12] = 0.7071f;
matrix[13] = 0.7071f;
break;
case 8: // 7.1
//Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Back L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Back R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Side L*/ matrix[12] = 1.0000f;
matrix[13] = 0.0000f;
/*Side R*/ matrix[14] = 0.0000f;
matrix[15] = 1.0000f;
break;
case 8: // 7.1
// Speaker \ Left Source Right Source
/*Front L*/ matrix[0] = 1.0000f;
matrix[1] = 0.0000f;
/*Front R*/ matrix[2] = 0.0000f;
matrix[3] = 1.0000f;
/*Front C*/ matrix[4] = 0.7071f;
matrix[5] = 0.7071f;
/*LFE */ matrix[6] = 0.0000f;
matrix[7] = 0.0000f;
/*Back L*/ matrix[8] = 1.0000f;
matrix[9] = 0.0000f;
/*Back R*/ matrix[10] = 0.0000f;
matrix[11] = 1.0000f;
/*Side L*/ matrix[12] = 1.0000f;
matrix[13] = 0.0000f;
/*Side R*/ matrix[14] = 0.0000f;
matrix[15] = 1.0000f;
break;
default:
matrixAvailable = false;
break;
default:
matrixAvailable = false;
break;
}
if (matrixAvailable) {
@@ -504,8 +452,7 @@ bool XAudio2_Output::init(long sampleRate)
return true;
}
void XAudio2_Output::write(uint16_t* finalWave, int)
{
void XAudio2_Output::write(uint16_t* finalWave, int) {
if (!initialized || failed)
return;
@@ -550,13 +497,12 @@ void XAudio2_Output::write(uint16_t* finalWave, int)
buf.AudioBytes = soundBufferLen;
buf.pAudioData = &buffers[currentBuffer * soundBufferLen];
currentBuffer++;
currentBuffer %= (bufferCount + 1); // + 1 because we need one temporary buffer
HRESULT hr = sVoice->SubmitSourceBuffer(&buf); // send buffer to queue
currentBuffer %= (bufferCount + 1); // + 1 because we need one temporary buffer
HRESULT hr = sVoice->SubmitSourceBuffer(&buf); // send buffer to queue
assert(hr == S_OK);
}
void XAudio2_Output::pause()
{
void XAudio2_Output::pause() {
if (!initialized || failed)
return;
@@ -567,8 +513,7 @@ void XAudio2_Output::pause()
}
}
void XAudio2_Output::resume()
{
void XAudio2_Output::resume() {
if (!initialized || failed)
return;
@@ -579,8 +524,7 @@ void XAudio2_Output::resume()
}
}
void XAudio2_Output::reset()
{
void XAudio2_Output::reset() {
if (!initialized || failed)
return;
@@ -594,8 +538,7 @@ void XAudio2_Output::reset()
playing = true;
}
void XAudio2_Output::setThrottle(unsigned short throttle_)
{
void XAudio2_Output::setThrottle(unsigned short throttle_) {
if (!initialized || failed)
return;
@@ -606,14 +549,50 @@ void XAudio2_Output::setThrottle(unsigned short throttle_)
assert(hr == S_OK);
}
void xaudio2_device_changed(XAudio2_Output* instance)
{
void xaudio2_device_changed(XAudio2_Output* instance) {
instance->device_change();
}
SoundDriver* newXAudio2_Output()
{
return new XAudio2_Output();
} // namespace
std::vector<AudioDevice> GetXAudio2Devices() {
HRESULT hr;
IXAudio2* xa = nullptr;
hr = XAudio2Create(&xa, 0);
if (hr != S_OK) {
wxLogError(_("The XAudio2 interface failed to initialize!"));
return {};
}
UINT32 dev_count = 0;
hr = xa->GetDeviceCount(&dev_count);
if (hr != S_OK) {
wxLogError(_("XAudio2: Enumerating devices failed!"));
return {};
}
std::vector<AudioDevice> devices;
devices.reserve(dev_count + 1);
devices.push_back({_("Default device"), wxEmptyString});
for (UINT32 i = 0; i < dev_count; i++) {
XAUDIO2_DEVICE_DETAILS dd;
hr = xa->GetDeviceDetails(i, &dd);
if (hr != S_OK) {
continue;
}
devices.push_back({dd.DisplayName, dd.DeviceID});
}
xa->Release();
return devices;
}
#endif // #ifndef NO_XAUDIO2
std::unique_ptr<SoundDriver> CreateXAudio2Driver() {
return std::make_unique<XAudio2_Output>();
}
} // namespace internal
} // namespace audio

View File

@@ -0,0 +1,18 @@
#ifndef WX_AUDIO_INTERNAL_XAUDIO2_H_
#define WX_AUDIO_INTERNAL_XAUDIO2_H_
#include "wx/audio/audio.h"
namespace audio {
namespace internal {
// Returns the set of XAudio2 devices.
std::vector<AudioDevice> GetXAudio2Devices();
// Creates an XAudio2 sound driver.
std::unique_ptr<SoundDriver> CreateXAudio2Driver();
} // namespace internal
} // namespace audio
#endif // WX_AUDIO_INTERNAL_XAUDIO2_H_

View File

@@ -1,8 +1,8 @@
#ifndef AUTOUPDATER_H
#define AUTOUPDATER_H
#ifndef VBAM_WX_AUTOUPDATER_AUTOUPDATER_H_
#define VBAM_WX_AUTOUPDATER_AUTOUPDATER_H_
void initAutoupdater();
void checkUpdatesUi();
void shutdownAutoupdater();
#endif // AUTOUPDATER_H
#endif // VBAM_WX_AUTOUPDATER_AUTOUPDATER_H_

View File

@@ -1,5 +1,6 @@
#include "../autoupdater.h"
#include "sparkle-wrapper.h"
#include "wx/autoupdater/autoupdater.h"
#include "wx/autoupdater/macos/sparkle-wrapper.h"
SparkleWrapper autoupdater;

View File

@@ -1,5 +1,5 @@
#ifndef SPARKLE_WRAPPER_H
#define SPARKLE_WRAPPER_H
#ifndef VBAM_WX_AUTOUPDATER_MACOS_SPARKLE_WRAPPER_H_
#define VBAM_WX_AUTOUPDATER_MACOS_SPARKLE_WRAPPER_H_
class SparkleWrapper
{
@@ -14,4 +14,4 @@ class SparkleWrapper
Private* d;
};
#endif // SPARKLE_WRAPPER_H
#endif // VBAM_WX_AUTOUPDATER_MACOS_SPARKLE_WRAPPER_H_

View File

@@ -1,14 +1,13 @@
#include "../autoupdater.h"
#include "wx/autoupdater/autoupdater.h"
#include "core/base/version.h"
#include "../../strutils.h"
#include "winsparkle-wrapper.h"
#include "wx/autoupdater/wxmsw/winsparkle-wrapper.h"
void initAutoupdater()
{
// even if we are a nightly, only check latest stable version
wxString version = strutils::split(kVbamVersion, '-')[0];
const wxString version(kVbamMainVersion);
#ifndef NO_HTTPS
win_sparkle_set_appcast_url("https://data.visualboyadvance-m.org/appcast.xml");
#else

View File

@@ -1,12 +1,13 @@
#include "wx/autoupdater/wxmsw/winsparkle-wrapper.h"
#include <cstdio>
#include <string>
#include <stdexcept>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/msw/private.h>
#include <wx/utils.h>
#include "wx/wxvbam.h"
#include "winsparkle-wrapper.h"
#include "wx/msw/private.h"
#include "wx/autoupdater/wxmsw/winsparkle-rc.h"
WinSparkleDllWrapper *WinSparkleDllWrapper::GetInstance()
{

View File

@@ -4,8 +4,6 @@
#include <wx/string.h>
#include <wx/dynlib.h>
#include "winsparkle-rc.h"
class WinSparkleDllWrapper {
public:
static WinSparkleDllWrapper *GetInstance();

View File

@@ -547,17 +547,17 @@ wxThread::ExitCode BackgroundInput::CheckKeyboard()
// virtual key "i" is pressed
if ((bits & 0x8000) && (previousState[i] & 0x8000) == 0) {
if (handler && !wxWindow::FindFocus()) {
wxKeyEvent ev(wxEVT_KEY_DOWN);
ev.m_keyCode = xKeySym;
handler->AddPendingEvent(ev);
wxKeyEvent* event = new wxKeyEvent(wxEVT_KEY_DOWN);
event->m_keyCode = xKeySym;
handler->QueueEvent(event);
}
}
// virtual key "i" is released
else if (((bits & 0x8000) == 0) && (previousState[i] & 0x8000)) {
if (handler && !wxWindow::FindFocus()) {
wxKeyEvent ev(wxEVT_KEY_UP);
ev.m_keyCode = xKeySym;
handler->AddPendingEvent(ev);
wxKeyEvent* event = new wxKeyEvent(wxEVT_KEY_UP);
event->m_keyCode = xKeySym;
handler->QueueEvent(event);
}
}
previousState[i] = bits;

View File

@@ -11,6 +11,7 @@
#include <wx/msgdlg.h>
#include "components/filters_interframe/interframe.h"
#include "core/base/check.h"
#include "core/base/version.h"
#include "core/gb/gb.h"
#include "core/gb/gbCheats.h"
@@ -22,6 +23,7 @@
#include "core/gba/gbaGlobals.h"
#include "core/gba/gbaPrint.h"
#include "core/gba/gbaSound.h"
#include "wx/config/cmdtab.h"
#include "wx/config/option-proxy.h"
#include "wx/config/option.h"
#include "wx/dialogs/game-maker.h"
@@ -29,14 +31,9 @@
#define GetXRCDialog(n) \
wxStaticCast(wxGetApp().frame->FindWindowByName(n), wxDialog)
bool cmditem_lt(const struct cmditem& cmd1, const struct cmditem& cmd2)
{
return wxStrcmp(cmd1.cmd, cmd2.cmd) < 0;
}
void MainFrame::GetMenuOptionBool(const wxString& menuName, bool* field)
{
assert(field);
VBAM_CHECK(field);
*field = !*field;
int id = wxXmlResource::GetXRCID(menuName);
@@ -52,7 +49,7 @@ void MainFrame::GetMenuOptionBool(const wxString& menuName, bool* field)
void MainFrame::GetMenuOptionConfig(const wxString& menu_name,
const config::OptionID& option_id) {
config::Option* option = config::Option::ByID(option_id);
assert(option);
VBAM_CHECK(option);
int id = wxXmlResource::GetXRCID(menu_name);
for (size_t i = 0; i < checkable_mi.size(); i++) {
@@ -68,7 +65,7 @@ void MainFrame::GetMenuOptionConfig(const wxString& menu_name,
option->SetInt(is_checked);
break;
default:
assert(false);
VBAM_CHECK(false);
return;
}
break;
@@ -77,7 +74,7 @@ void MainFrame::GetMenuOptionConfig(const wxString& menu_name,
void MainFrame::GetMenuOptionInt(const wxString& menuName, int* field, int mask)
{
assert(field);
VBAM_CHECK(field);
int value = mask;
bool is_checked = ((*field) & (mask)) != (value);
int id = wxXmlResource::GetXRCID(menuName);
@@ -365,7 +362,7 @@ EVT_HANDLER_MASK(SetLoadingDotCodeFile, "Load e-Reader Dot Code...", CMDEN_GBA)
static wxString loaddotcodefile_path;
wxFileDialog dlg(this, _("Select Dot Code file"), loaddotcodefile_path, wxEmptyString,
_(
"e-Reader Dot Code (*.bin;*.raw)|"
"E-Reader Dot Code (*.bin;*.raw)|"
"*.bin;*.raw"),
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
int ret = ShowModal(&dlg);
@@ -387,7 +384,7 @@ EVT_HANDLER_MASK(SetSavingDotCodeFile, "Save e-Reader Dot Code...", CMDEN_GBA)
static wxString savedotcodefile_path;
wxFileDialog dlg(this, _("Select Dot Code file"), savedotcodefile_path, wxEmptyString,
_(
"e-Reader Dot Code (*.bin;*.raw)|"
"E-Reader Dot Code (*.bin;*.raw)|"
"*.bin;*.raw"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
int ret = ShowModal(&dlg);
@@ -1184,7 +1181,7 @@ EVT_HANDLER(AllowKeyboardBackgroundInput, "Allow keyboard background input (togg
disableKeyboardBackgroundInput();
if (OPTION(kUIAllowKeyboardBackgroundInput)) {
if (panel && panel->panel) {
enableKeyboardBackgroundInput(panel->panel->GetWindow());
enableKeyboardBackgroundInput(panel->panel->GetWindow()->GetEventHandler());
}
}
}
@@ -1686,30 +1683,13 @@ EVT_HANDLER(ToggleSound, "Enable/disable all sound channels")
EVT_HANDLER(IncreaseVolume, "Increase volume")
{
gopts.sound_vol += 5;
OPTION(kSoundVolume) += 5;
if (gopts.sound_vol > 200)
gopts.sound_vol = 200;
update_opts();
soundSetVolume((float)gopts.sound_vol / 100.0);
wxString msg;
msg.Printf(_("Volume: %d %%"), gopts.sound_vol);
systemScreenMessage(msg);
}
EVT_HANDLER(DecreaseVolume, "Decrease volume")
{
gopts.sound_vol -= 5;
if (gopts.sound_vol < 0)
gopts.sound_vol = 0;
update_opts();
soundSetVolume((float)gopts.sound_vol / 100.0);
wxString msg;
msg.Printf(_("Volume: %d %%"), gopts.sound_vol);
systemScreenMessage(msg);
OPTION(kSoundVolume) -= 5;
}
EVT_HANDLER_MASK(NextFrame, "Next Frame", CMDEN_GB | CMDEN_GBA)
@@ -1731,7 +1711,7 @@ EVT_HANDLER_MASK(Disassemble, "Disassemble...", CMDEN_GB | CMDEN_GBA)
EVT_HANDLER(Logging, "Logging...")
{
wxDialog* dlg = wxGetApp().frame->logdlg;
wxDialog* dlg = wxGetApp().frame->logdlg.get();
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
dlg->Show();
dlg->Raise();
@@ -2174,45 +2154,13 @@ EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY)
EVT_HANDLER_MASK(SoundConfigure, "Sound options...", CMDEN_NREC_ANY)
{
int oqual = gopts.sound_qual, oapi = gopts.audio_api;
bool oupmix = gopts.upmix, ohw = gopts.dsound_hw_accel;
wxString odev = gopts.audio_dev;
wxDialog* dlg = GetXRCDialog("SoundConfig");
if (ShowModal(dlg) != wxID_OK)
if (ShowModal(GetXRCDialog("SoundConfig")) != wxID_OK)
return;
switch (panel->game_type()) {
case IMAGE_UNKNOWN:
break;
case IMAGE_GB:
gb_effects_config.echo = (float)gopts.gb_echo / 100.0;
gb_effects_config.stereo = (float)gopts.gb_stereo / 100.0;
gbSoundSetSampleRate(!gopts.sound_qual ? 48000 : 44100 / (1 << (gopts.sound_qual - 1)));
break;
case IMAGE_GBA:
soundSetSampleRate(!gopts.sound_qual ? 48000 : 44100 / (1 << (gopts.sound_qual - 1)));
soundFiltering = (float)gopts.gba_sound_filter / 100.0f;
break;
}
// changing sample rate causes driver reload, so no explicit reload needed
if (oqual == gopts.sound_qual &&
// otherwise reload if API changes
(oapi != gopts.audio_api || odev != gopts.audio_dev ||
// or init-only options
(oapi == AUD_XAUDIO2 && oupmix != gopts.upmix) || (oapi == AUD_FAUDIO && oupmix != gopts.upmix) || (oapi == AUD_DIRECTSOUND && ohw != gopts.dsound_hw_accel))) {
soundShutdown();
if (!soundInit()) {
wxLogError(_("Could not initialize the sound driver!"));
}
}
soundSetVolume((float)gopts.sound_vol / 100.0);
update_opts();
// No point in observing these since they can only be set in this dialog.
gb_effects_config.echo = (float)OPTION(kSoundGBEcho) / 100.0;
gb_effects_config.stereo = (float)OPTION(kSoundGBStereo) / 100.0;
soundFiltering = (float)OPTION(kSoundGBAFiltering) / 100.0f;
}
EVT_HANDLER(EmulatorDirectories, "Directories...")
@@ -2222,44 +2170,17 @@ EVT_HANDLER(EmulatorDirectories, "Directories...")
EVT_HANDLER(JoypadConfigure, "Joypad options...")
{
joy.PollAllJoysticks();
auto frame = wxGetApp().frame;
bool joy_timer = frame->IsJoyPollTimerRunning();
if (!joy_timer) {
frame->StartJoyPollTimer();
}
if (ShowModal(GetXRCDialog("JoypadConfig")) == wxID_OK) {
update_joypad_opts();
update_shortcut_opts();
}
if (!joy_timer) {
frame->StopJoyPollTimer();
}
SetJoystick();
}
EVT_HANDLER(Customize, "Customize UI...")
{
wxDialog* dlg = GetXRCDialog("AccelConfig");
joy.PollAllJoysticks();
auto frame = wxGetApp().frame;
bool joy_timer = frame->IsJoyPollTimerRunning();
if (!joy_timer) frame->StartJoyPollTimer();
if (ShowModal(dlg) == wxID_OK) {
if (ShowModal(GetXRCDialog("AccelConfig")) == wxID_OK) {
update_shortcut_opts();
ResetMenuAccelerators();
}
if (!joy_timer) frame->StopJoyPollTimer();
SetJoystick();
}
#ifndef NO_ONLINEUPDATES

View File

@@ -0,0 +1,89 @@
# This defines the vbam-wx-config target and the
# `VBAM_LOCALIZABLE_WX_CONFIG_FILES` variable, containing the list of
# localizable files in the vbam-wx-config target.
# I don't like duplicating/triplicating code, so I only declare
# event handlers once, and copy them in other places they are needed
# all using portable cmake code
add_custom_command(
OUTPUT
${VBAM_GENERATED_DIR}/wx/config/internal/cmdtab.cpp
${VBAM_GENERATED_DIR}/wx/cmdhandlers.h
${VBAM_GENERATED_DIR}/wx/cmd-evtable.h
COMMAND
${CMAKE_COMMAND} -D OUTDIR=${VBAM_GENERATED_DIR}/wx/ -P copy-events.cmake
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
../cmdevents.cpp
copy-events.cmake
)
add_library(vbam-wx-config OBJECT)
# Export the localizable files to the parent scope.
set(VBAM_LOCALIZABLE_WX_CONFIG_FILES
${CMAKE_CURRENT_LIST_DIR}/bindings.cpp
${CMAKE_CURRENT_LIST_DIR}/command.cpp
${CMAKE_CURRENT_LIST_DIR}/cmdtab.cpp
${CMAKE_CURRENT_LIST_DIR}/emulated-gamepad.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/bindings-internal.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/bindings-internal.h
${CMAKE_CURRENT_LIST_DIR}/internal/option-internal.cpp
${CMAKE_CURRENT_LIST_DIR}/internal/option-internal.h
${CMAKE_CURRENT_LIST_DIR}/option-observer.cpp
${CMAKE_CURRENT_LIST_DIR}/option.cpp
${CMAKE_CURRENT_LIST_DIR}/strutils.cpp
${CMAKE_CURRENT_LIST_DIR}/user-input.cpp
# Generated file.
${VBAM_GENERATED_DIR}/wx/config/internal/cmdtab.cpp
)
set(VBAM_LOCALIZABLE_WX_CONFIG_FILES
${VBAM_LOCALIZABLE_WX_CONFIG_FILES}
PARENT_SCOPE
)
target_sources(vbam-wx-config
PRIVATE
${VBAM_LOCALIZABLE_WX_CONFIG_FILES}
PUBLIC
bindings.h
command.h
cmdtab.h
emulated-gamepad.h
option-id.h
option-observer.h
option-proxy.h
option.h
strutils.h
user-input.h
)
configure_wx_target(vbam-wx-config)
if(BUILD_TESTING)
add_executable(vbam-wx-config-tests
bindings-test.cpp
command-test.cpp
emulated-gamepad-test.cpp
option-test.cpp
strutils-test.cpp
user-input-test.cpp
)
target_link_libraries(vbam-wx-config-tests
# Test deps.
vbam-core-fake
vbam-wx-fake-opts
# Target deps.
vbam-wx-config
GTest::gtest_main
)
configure_wx_target(vbam-wx-config-tests)
if (NOT CMAKE_CROSSCOMPILING)
gtest_discover_tests(vbam-wx-config-tests)
endif()
endif()

View File

@@ -0,0 +1,152 @@
#include "wx/config/bindings.h"
#include <gtest/gtest.h>
#include <wx/xrc/xmlres.h>
#include "wx/config/command.h"
#include "wx/config/user-input.h"
TEST(BindingsTest, Default) {
const config::Bindings bindings;
// Check that the default bindings are set up correctly.
auto inputs =
bindings.InputsForCommand(config::GameCommand(config::GameJoy(0), config::GameKey::Up));
EXPECT_TRUE(inputs.find(config::KeyboardInput('W')) != inputs.end());
EXPECT_TRUE(inputs.find(config::JoyInput(config::JoyId(0), config::JoyControl::HatNorth, 0)) !=
inputs.end());
inputs = bindings.InputsForCommand(config::ShortcutCommand(wxID_CLOSE));
EXPECT_TRUE(inputs.find(config::KeyboardInput('W', wxMOD_CMD)) != inputs.end());
inputs = bindings.InputsForCommand(config::ShortcutCommand(XRCID("LoadGame01")));
EXPECT_TRUE(inputs.find(config::KeyboardInput(WXK_F1)) != inputs.end());
// Check that the INI configuration for the keyboard is empty.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_TRUE(config.empty());
}
// Tests that assigning a default input to another command generates the right
// configuration.
TEST(BindingsTest, AssignDefault) {
config::Bindings bindings;
// Assign F1 to the "Close" command.
bindings.AssignInputToCommand(config::KeyboardInput(WXK_F1),
config::ShortcutCommand(wxID_CLOSE));
// The INI configuration should have NOOP set to F1, and Close set to F1.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_EQ(config.size(), 2);
EXPECT_EQ(config[0].first, "Keyboard/NOOP");
EXPECT_EQ(config[0].second, "F1");
EXPECT_EQ(config[1].first, "Keyboard/CLOSE");
EXPECT_EQ(config[1].second, "F1");
}
// Tests that unassigning a default input generates the right configuration.
TEST(BindingsTest, UnassignDefault) {
config::Bindings bindings;
// Unassign F1.
bindings.UnassignInput(config::KeyboardInput(WXK_F1));
// The INI configuration should have NOOP set to F1.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_EQ(config.size(), 1);
EXPECT_EQ(config[0].first, "Keyboard/NOOP");
EXPECT_EQ(config[0].second, "F1");
}
// Tests that re-assigning a default input to its default command generates the
// right configuration.
TEST(BindingsTest, ReassignDefault) {
config::Bindings bindings;
// Assign F1 to the "Close" command.
bindings.AssignInputToCommand(config::KeyboardInput(WXK_F1),
config::ShortcutCommand(wxID_CLOSE));
// Re-assign F1 to the "LoadGame01" command.
bindings.AssignInputToCommand(config::KeyboardInput(WXK_F1),
config::ShortcutCommand(XRCID("LoadGame01")));
// The INI configuration should be empty.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_TRUE(config.empty());
}
// Tests that assigning an input to "NOOP" properly disables the default input.
TEST(BindingsTest, AssignToNoop) {
config::Bindings bindings;
// Assign F1 to the "NOOP" command.
bindings.AssignInputToCommand(config::KeyboardInput(WXK_F1),
config::ShortcutCommand(XRCID("NOOP")));
const auto command = bindings.CommandForInput(config::KeyboardInput(WXK_F1));
EXPECT_FALSE(command.has_value());
// The INI configuration should have NOOP set to F1 and nothing more.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_EQ(config.size(), 1);
EXPECT_EQ(config[0].first, "Keyboard/NOOP");
EXPECT_EQ(config[0].second, "F1");
}
// Tests that assigning an input not used as a default shortcut to "NOOP" does
// nothing.
TEST(BindingsTest, AssignUnusedToNoop) {
config::Bindings bindings;
// Assign "T" to the "NOOP" command.
bindings.AssignInputToCommand(config::KeyboardInput('T'), config::ShortcutCommand(XRCID("NOOP")));
// The INI configuration should be empty.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_TRUE(config.empty());
// "T" should have no assignment.
const auto command = bindings.CommandForInput(config::KeyboardInput('T'));
EXPECT_FALSE(command.has_value());
}
// Tests that assigning a default input to a Game command works as expected.
TEST(BindingsTest, AssignDefaultToGame) {
config::Bindings bindings;
// Assign F1 to the "Up" command and clear all of the default input for the
// "Up" command.
bindings.AssignInputsToCommand({config::KeyboardInput(WXK_F1)},
config::GameCommand(config::GameJoy(0), config::GameKey::Up));
// The INI configuration should have NOOP set to F1.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_EQ(config.size(), 1);
EXPECT_EQ(config[0].first, "Keyboard/NOOP");
EXPECT_EQ(config[0].second, "F1");
EXPECT_EQ(
bindings.InputsForCommand(config::GameCommand(config::GameJoy(0), config::GameKey::Up)),
std::unordered_set<config::UserInput>{config::KeyboardInput(WXK_F1)});
EXPECT_EQ(bindings.CommandForInput(config::KeyboardInput(WXK_F1)),
config::Command(config::GameCommand(config::GameJoy(0), config::GameKey::Up)));
}
// Tests the "ClearCommandAssignments" method.
TEST(BindingsTest, ClearCommand) {
config::Bindings bindings;
// Clear "CLOSE" assignments.
bindings.ClearCommandAssignments(config::ShortcutCommand(wxID_CLOSE));
// The INI configuration should only have the NOOP assignment.
const auto config = bindings.GetKeyboardConfiguration();
EXPECT_EQ(config.size(), 1);
EXPECT_EQ(config[0].first, "Keyboard/NOOP");
EXPECT_EQ(config[0].second, "CTRL+W");
EXPECT_TRUE(bindings.InputsForCommand(config::ShortcutCommand(wxID_CLOSE)).empty());
}

252
src/wx/config/bindings.cpp Normal file
View File

@@ -0,0 +1,252 @@
#include "wx/config/bindings.h"
#include <wx/string.h>
#include <wx/translation.h>
#include <wx/xrc/xmlres.h>
#include "wx/config/user-input.h"
#define VBAM_BINDINGS_INTERNAL_INCLUDE
#include "wx/config/internal/bindings-internal.h"
#undef VBAM_BINDINGS_INTERNAL_INCLUDE
namespace config {
namespace {
int NoopCommand() {
static const int noop = XRCID("NOOP");
return noop;
}
} // namespace
// static
const std::unordered_set<UserInput>& Bindings::DefaultInputsForCommand(const Command& command) {
return internal::DefaultInputsForCommand(command);
}
Bindings::Bindings() {
// Set up default shortcuts.
for (const auto& iter : internal::DefaultInputs()) {
for (const auto& input : iter.second) {
AssignInputToCommand(input, iter.first);
}
}
}
Bindings::Bindings(
const std::unordered_map<Command, std::unordered_set<UserInput>>& control_to_inputs,
const std::unordered_map<UserInput, Command>& input_to_control,
const std::unordered_map<UserInput, ShortcutCommand>& disabled_defaults)
: control_to_inputs_(control_to_inputs.begin(), control_to_inputs.end()),
input_to_control_(input_to_control.begin(), input_to_control.end()),
disabled_defaults_(disabled_defaults.begin(), disabled_defaults.end()) {}
std::vector<std::pair<wxString, wxString>> Bindings::GetKeyboardConfiguration() const {
std::vector<std::pair<wxString, wxString>> config;
config.reserve(control_to_inputs_.size() + 1);
if (!disabled_defaults_.empty()) {
std::unordered_set<UserInput> noop_inputs;
for (const auto& iter : disabled_defaults_) {
noop_inputs.insert(iter.first);
}
config.push_back(std::make_pair(ShortcutCommand(NoopCommand()).ToConfigString(),
UserInput::SpanToConfigString(noop_inputs)));
}
for (const auto& iter : control_to_inputs_) {
if (iter.first.is_game()) {
// We only consider shortcut assignments here.
continue;
}
// Gather the inputs for this command.
std::unordered_set<UserInput> inputs;
for (const auto& input : iter.second) {
if (internal::IsDefaultInputForCommand(iter.first, input)) {
// Default assignments are ignored.
continue;
}
// Not a default input.
inputs.insert(input);
}
if (!inputs.empty()) {
config.push_back(std::make_pair(iter.first.shortcut().ToConfigString(),
UserInput::SpanToConfigString(inputs)));
}
}
return config;
}
std::vector<std::pair<GameCommand, wxString>> Bindings::GetJoypadConfiguration() const {
std::vector<std::pair<GameCommand, wxString>> config;
config.reserve(kNbGameKeys * kNbJoypads);
for (const auto& game_command : internal::kOrderedGameCommands) {
const auto iter = control_to_inputs_.find(Command(game_command));
if (iter == control_to_inputs_.end()) {
config.push_back(std::make_pair(game_command, wxEmptyString));
continue;
}
const std::unordered_set<UserInput>& inputs = iter->second;
config.push_back(std::make_pair(game_command, UserInput::SpanToConfigString(inputs)));
}
return config;
}
std::unordered_set<UserInput> Bindings::InputsForCommand(const Command& command) const {
if (command.is_shortcut() && command.shortcut().id() == NoopCommand()) {
std::unordered_set<UserInput> noop_inputs;
for (const auto& iter : disabled_defaults_) {
noop_inputs.insert(iter.first);
}
return noop_inputs;
}
auto iter = control_to_inputs_.find(command);
if (iter == control_to_inputs_.end()) {
return {};
}
return iter->second;
}
nonstd::optional<Command> Bindings::CommandForInput(const UserInput& input) const {
const auto iter = input_to_control_.find(input);
if (iter == input_to_control_.end()) {
return nonstd::nullopt;
}
return iter->second;
}
Bindings Bindings::Clone() const {
return Bindings(this->control_to_inputs_, this->input_to_control_, this->disabled_defaults_);
}
void Bindings::AssignInputToCommand(const UserInput& input, const Command& command) {
if (command.is_shortcut() && command.shortcut().id() == NoopCommand()) {
// "Assigning to Noop" means unassinging the default binding.
UnassignDefaultBinding(input);
return;
}
// Remove the existing binding if it exists.
auto iter = input_to_control_.find(input);
if (iter != input_to_control_.end()) {
UnassignInput(input);
}
if (command.is_shortcut()) {
const ShortcutCommand& shortcut_command = command.shortcut();
auto disabled_iter = disabled_defaults_.find(input);
if (disabled_iter != disabled_defaults_.end()) {
const ShortcutCommand& original_command = disabled_iter->second;
if (original_command == shortcut_command) {
// Restoring a disabled input. Remove from the disabled set.
disabled_defaults_.erase(disabled_iter);
}
// Then, just continue normally.
}
}
control_to_inputs_[command].emplace(input);
input_to_control_.emplace(std::make_pair(input, command));
}
void Bindings::AssignInputsToCommand(const std::unordered_set<UserInput>& inputs,
const Command& command) {
// Remove the existing binding if it exists.
const auto iter = control_to_inputs_.find(command);
if (iter != control_to_inputs_.end()) {
// We need to make a copy here because the iterator is going to be invalidated.
const std::unordered_set<UserInput> inputs_to_unassign = iter->second;
for (const UserInput& user_input : inputs_to_unassign) {
UnassignInput(user_input);
}
}
for (const UserInput& user_input : inputs) {
AssignInputToCommand(user_input, command);
}
}
void Bindings::UnassignInput(const UserInput& input) {
VBAM_CHECK(input);
auto iter = input_to_control_.find(input);
if (iter == input_to_control_.end()) {
// Input not found, nothing to do.
return;
}
if (iter->second.is_shortcut()) {
if (internal::IsDefaultInputForCommand(iter->second, input)) {
// Unassigning a default binding has some special handling.
UnassignDefaultBinding(input);
return;
}
}
// Otherwise, just remove it from the 2 maps.
auto command_iter = control_to_inputs_.find(iter->second);
VBAM_CHECK(command_iter != control_to_inputs_.end());
command_iter->second.erase(input);
if (command_iter->second.empty()) {
// Remove empty set.
control_to_inputs_.erase(command_iter);
}
input_to_control_.erase(iter);
}
void Bindings::ClearCommandAssignments(const Command& command) {
const auto iter = control_to_inputs_.find(command);
if (iter == control_to_inputs_.end()) {
// Command not found, nothing to do.
return;
}
// Keep a copy of the inputs to unassign.
std::unordered_set<UserInput> inputs_to_unassign(iter->second);
// Unassign all inputs.
for (const UserInput& input : inputs_to_unassign) {
UnassignInput(input);
}
}
void Bindings::UnassignDefaultBinding(const UserInput& input) {
auto input_iter = input_to_control_.find(input);
if (input_iter == input_to_control_.end()) {
// This can happen if the INI file provided by the user has an invalid
// option. In this case, just silently ignore it.
return;
}
if (!input_iter->second.is_shortcut()) {
return;
}
if (!internal::IsDefaultInputForCommand(input_iter->second, input)) {
// As above, we have already removed the default binding, ignore it.
return;
}
auto command_iter = control_to_inputs_.find(input_iter->second);
VBAM_CHECK(command_iter != control_to_inputs_.end());
command_iter->second.erase(input);
if (command_iter->second.empty()) {
control_to_inputs_.erase(command_iter);
}
disabled_defaults_.emplace(std::make_pair(input, input_iter->second.shortcut()));
input_to_control_.erase(input_iter);
}
} // namespace config

104
src/wx/config/bindings.h Normal file
View File

@@ -0,0 +1,104 @@
#ifndef VBAM_WX_CONFIG_BINDINGS_H_
#define VBAM_WX_CONFIG_BINDINGS_H_
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "wx/config/command.h"
#include "wx/config/user-input.h"
// wxWidgets only goes up to `wxID_FILE9` but we want 10 recent files.
#define wxID_FILE10 (wxID_FILE9 + 1)
namespace config {
// Bindings is a class that manages the association between commands and
// user inputs. It is used to manage the shortcuts configuration. The class
// provides methods to assign and unassign inputs to commands, as well as
// retrieve the current configuration for the INI file.
class Bindings {
public:
// Returns the list of default inputs for `command`.
static const std::unordered_set<UserInput>& DefaultInputsForCommand(const Command& command);
Bindings();
~Bindings() = default;
Bindings(Bindings&&) noexcept = default;
Bindings& operator=(Bindings&&) noexcept = default;
// Disable copy and copy assignment operator.
// `Clone()` is provided only for the configuration window, this class
// should otherwise be treated as move-only. If you wish to access the
// Bindings configuration, do it from `wxGetApp().bindings()`.
Bindings(const Bindings&) = delete;
Bindings& operator=(const Bindings&) = delete;
// Returns the shortcuts configuration for the INI file.
// Internally, there are global default system inputs that are immediately
// available on first run. For the configuration saved in the [Keyboard]
// section of the vbam.ini file, we only keep track of the following:
// - Disabled default input. These appear under [Keyboard/NOOP].
// - User-added custom bindings. These appear under [Keyboard/CommandName].
// Essentially, this is a diff between the default shortcuts and the user
// configuration.
std::vector<std::pair<wxString, wxString>> GetKeyboardConfiguration() const;
// Returns the game control configuration for the INI file. These go in the
// [Joypad] section of the INI file.
std::vector<std::pair<GameCommand, wxString>> GetJoypadConfiguration() const;
// Returns the list of input currently configured for `command`.
std::unordered_set<UserInput> InputsForCommand(const Command& command) const;
// Returns the Command currently assigned to `input` or nullopt if none.
nonstd::optional<Command> CommandForInput(const UserInput& input) const;
// Returns a copy of this object. This can be an expensive operation and
// should only be used to modify the currently active shortcuts
// configuration.
Bindings Clone() const;
// Assigns `input` to `command`. Silently unassigns `input` if it is already
// assigned to another command.
void AssignInputToCommand(const UserInput& input, const Command& command);
// Assigns `inputs` to `command`. Silently unassigns any of `inputs` if they
// are already assigned to another command. Any input previously assigned to
// `command` will be cleared.
void AssignInputsToCommand(const std::unordered_set<UserInput>& inputs, const Command& command);
// Removes `input` assignment. No-op if `input` is not assigned. `input`
// must be a valid UserInput. Call will assert otherwise. Call will assert otherwise.
void UnassignInput(const UserInput& input);
// Removes all assignments for `command`. No-op if `command` has no assignment.
void ClearCommandAssignments(const Command& command);
private:
// Faster constructor for explicit copy.
Bindings(
const std::unordered_map<Command, std::unordered_set<UserInput>>& control_to_inputs,
const std::unordered_map<UserInput, Command>& input_to_control,
const std::unordered_map<UserInput, ShortcutCommand>& disabled_defaults);
// Helper method to unassign a binding used by the default configuration.
// This requires special handling since the INI configuration is a diff
// between the default bindings and the user configuration.
void UnassignDefaultBinding(const UserInput& input);
// Map of command to their associated input set.
std::unordered_map<Command, std::unordered_set<UserInput>> control_to_inputs_;
// Reverse map of the above. An input can only map to a single command.
std::unordered_map<UserInput, Command> input_to_control_;
// Disabled default shortcuts. This is used to easily retrieve the
// configuration to save in the INI file.
std::unordered_map<UserInput, ShortcutCommand> disabled_defaults_;
};
using BindingsProvider = std::function<Bindings*()>;
} // namespace config
#endif // VBAM_WX_CONFIG_BINDINGS_H_

Some files were not shown because too many files have changed in this diff Show More