Port plugin to Aroma

This commit is contained in:
Maschell 2023-02-16 10:52:22 +01:00
parent 65aec45c62
commit 567e286b6e
29 changed files with 1516 additions and 765 deletions

67
.clang-format Normal file
View File

@ -0,0 +1,67 @@
# Generated from CLion C/C++ Code Style settings
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 8
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Right
ReflowComments: false
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Never

59
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: CI-Release
on:
push:
branches:
- main
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src --exclude ./src/utils/json.hpp
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- name: create version.h
run: |
git_hash=$(git rev-parse --short "$GITHUB_SHA")
cat <<EOF > ./src/version.h
#pragma once
#define PLUGIN_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.wps"
deploy-binary:
needs: build-binary
runs-on: ubuntu-22.04
steps:
- name: Get environment variables
id: get_repository_name
run: |
echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//") >> $GITHUB_ENV
echo DATETIME=$(echo $(date '+%Y%m%d-%H%M%S')) >> $GITHUB_ENV
- uses: actions/download-artifact@master
with:
name: binary
- name: zip artifact
run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wps
- name: Create Release
uses: "softprops/action-gh-release@v1"
with:
tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
draft: false
prerelease: true
generate_release_notes: true
name: Nightly-${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }}
files: |
./${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip

32
.github/workflows/pr.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: CI-PR
on: [ pull_request ]
jobs:
clang-format:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: clang-format
run: |
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src --exclude ./src/utils/json.hpp
build-binary:
runs-on: ubuntu-22.04
needs: clang-format
steps:
- uses: actions/checkout@v3
- name: create version.h
run: |
git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
cat <<EOF > ./src/version.h
#pragma once
#define PLUGIN_VERSION_EXTRA " (nightly-$git_hash)"
EOF
- name: build binary
run: |
docker build . -t builder
docker run --rm -v ${PWD}:/project builder make
- uses: actions/upload-artifact@master
with:
name: binary
path: "*.wps"

5
.gitignore vendored
View File

@ -1,2 +1,7 @@
build/* build/*
*.mod *.mod
cmake-build-debug/
.idea/
*.wps
*.elf
CMakeLists.txt

View File

@ -1,31 +0,0 @@
sudo: required
branches:
only:
- master
services:
- docker
addons:
apt:
packages:
- p7zip-full
before_script:
- docker build . -t swipswapme-builder
script:
- docker run -it --rm -v ${PWD}:/project swipswapme-builder make
before_deploy:
- cd $TRAVIS_BUILD_DIR/
- mkdir -p "wiiu/plugins"
- commit="$(git rev-parse --short=7 HEAD)"
- find -type f -name "*.mod" | xargs -i cp {} wiiu/plugins
- zip -r swipswapme_nightly_$commit.zip wiiu
- git config --local user.name "Maschell"
- git config --local user.email "Maschell@gmx.de"
- git tag "SwipSwapMe-$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)"
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: Gqu3sySILamrn1sY2Hcr32DHHXHvffzPg6uIR9gsJxMLReZT+OU4x9Pys88epPqpQCAnwbmoJYDSBrUTAumfwLxBeBv4FzySL87Ztbv9JLIvOakwNAi0d0dAtHYl7D/+2JlU57pY2CYK/k/Y/kKz0WswAi2QYZ68uY028l+2dc5a2y4L06ZMqbd3xWIzBGxgyJurmMXrHGdsiLz+2WEbDf/9dSuBrwjqGC5StfmupOwZVIBivZgrQz/g9Y8snK4FDPuR2eLOZKxas1QxcjFKI5hWlex/oHpxD41Zy5DyfawvgZU3YmScCJs/BzaOBkEs3boHbC199ppHCB0fl/GFgHdlmVmjdKOKJhuhRbj5zLKoEem0ujFi6MQF+OBHdEFhgpqC+CWuz+HZR3M/2p/e90W/0ZJOhWpWUWaIFLnQJ3abXAbd0oqnqJCbPZI5m7z+N/cNjGAJg/AQqYi/ophT4+Nh+9zNcDRtOwY8eQsYXKMCGOiaP/84LaO708TJQJFpY2GScorVrCWdFW/BPOU/RICLdKlBP6ljaMsC+TYFlJv1VRAh2+gLC8kNO5tdG6oNMYHgAPTGS45AHhIJNSiUOL0DhuTbrFEHVsae8uzmMdgxnQQVMRf17UVr7t5Dsap2CdD36eZspbPjmin4xFfaUxPoUoVrfwaSPpsWQJH+vYA=
file: swipswapme_nightly_$commit.zip
on:
repo: Maschell/SwipSwapMe

View File

@ -1,6 +1,7 @@
FROM wups/core-with-wut:0.1 FROM wiiuenv/devkitppc:20221228
# Get dependencies COPY --from=wiiuenv/wiiupluginsystem:20230215 /artifacts $DEVKITPRO
COPY --from=wiiuwut/libutils:0.1 /artifacts $WUT_ROOT COPY --from=wiiuenv/libnotifications:20230126 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libmappedmemory:20220904 /artifacts $DEVKITPRO
WORKDIR project WORKDIR project

353
Makefile
View File

@ -1,300 +1,147 @@
# You probably never need to adjust this Makefile. #-------------------------------------------------------------------------------
# All changes can be done in the makefile.mk
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES: .SUFFIXES:
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC")
endif
ifeq ($(strip $(DEVKITPRO)),) ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPRO") $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif endif
export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) TOPDIR ?= $(CURDIR)
export PORTLIBS := $(DEVKITPRO)/portlibs/ppc
export WUPSDIR := $(DEVKITPRO)/wups
export GCC_VER := $(shell $(DEVKITPPC)/bin/powerpc-eabi-gcc -dumpversion)
PREFIX := powerpc-eabi- include $(DEVKITPRO)/wups/share/wups_rules
export AS := $(PREFIX)as WUT_ROOT := $(DEVKITPRO)/wut
export CC := $(PREFIX)gcc WUMS_ROOT := $(DEVKITPRO)/wums
export CXX := $(PREFIX)g++
export LD := $(PREFIX)ld
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# TARGET is the name of the output # TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed # BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code # SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files # DATA is a list of directories containing data files
#--------------------------------------------------------------------------------- # INCLUDES is a list of directories containing header files
TARGET := $(notdir $(CURDIR)) #-------------------------------------------------------------------------------
TARGET := swipswapme
BUILD := build BUILD := build
SOURCES := src src/utils
DATA := data
INCLUDES := src
ifeq ($(notdir $(CURDIR)),$(BUILD)) #-------------------------------------------------------------------------------
include ../makefile.mk
else
include makefile.mk
endif
include $(WUPSDIR)/plugin_makefile.mk
#MAP ?= $(TARGET:.mod=.map)
#---------------------------------------------------------------------------------
# options for code generation # options for code generation
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
CFLAGS := -Wall -O2 -ffunction-sections \
$(MACHDEP)
# -Os: optimise size CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
# -Wall: generate lots of warnings
# -D__wiiu__: define the symbol __wiiu__ (used in some headers)
# -mcpu=750: enable processor specific compilation
# -meabi: enable eabi specific compilation
# -mhard-float: enable hardware floating point instructions
# -nostartfiles: Do not use the standard system startup files when linking
# -ffunction-sections: split up functions so linker can garbage collect
# -fdata-sections: split up data so linker can garbage collect
COMMON_CFLAGS := -Os -Wall -mcpu=750 -meabi -mhard-float -D__WIIU__ -nostartfiles -ffunction-sections -fdata-sections -Wl,-q $(COMMON_CFLAGS)
# -x c: compile as c code CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti
# -std=c11: use the c11 standard
CFLAGS := $(COMMON_CFLAGS) -x c -std=gnu11 $(CFLAGS)
# -x c: compile as c++ code ASFLAGS := -g $(ARCH)
# -std=gnu++11: use the c++11 standard LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUPSSPECS)
CXXFLAGS := $(COMMON_CFLAGS) -x c++ -std=gnu++11 $(CXXFLAGS)
ifeq ($(DO_LOGGING), 1) ifeq ($(DEBUG),1)
CFLAGS += -D__LOGGING__ CXXFLAGS += -DDEBUG -g
CXXFLAGS += -D__LOGGING__ CFLAGS += -DDEBUG -g
endif endif
#--------------------------------------------------------------------------------- ifeq ($(DEBUG),VERBOSE)
# any extra ld flags CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
#-------------------------------------------------------------------------------- CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
# --gc-sections: remove unneeded symbols
# -Map: generate a map file
LDFLAGS += -Wl,-Map,$(notdir $@).map,--gc-sections
#---------------------------------------------------------------------------------
Q := @
MAKEFLAGS += --no-print-directory
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS +=
#
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS +=
NEEDS_WUT := 0
ifeq ($(WUT_ENABLE_CPP), 1)
WUT_ENABLE_NEWLIB := 1
LDFLAGS += -Wl,-whole-archive,-lwutstdc++,-no-whole-archive
NEEDS_WUT := 1
endif endif
ifeq ($(WUT_ENABLE_NEWLIB), 1) LIBS := -lwups -lnotifications -lmappedmemory -lwut
LDFLAGS += -Wl,-whole-archive,-lwutnewlib,-no-whole-archive
NEEDS_WUT := 1
endif
ifeq ($(WUT_DEFAULT_MALLOC), 1) #-------------------------------------------------------------------------------
LDFLAGS += -Wl,-whole-archive,-lwutmalloc,-no-whole-archive # list of directories containing libraries, this must be the top level
NEEDS_WUT := 1 # containing include and lib
endif #-------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUT_ROOT) $(WUMS_ROOT)
ifeq ($(NEEDS_WUT), 1) #-------------------------------------------------------------------------------
ifeq ($(strip $(WUT_ROOT)),)
$(error "Please set WUT_ROOT in your environment. export WUT_ROOT=<path to>wut)
endif
CFLAGS += -D__WUT__
CXXFLAGS += -D__WUT__
endif
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional # no real need to edit anything past this point unless you need to add additional
# rules for different file extensions # rules for different file extensions
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR))) ifneq ($(BUILD),$(notdir $(CURDIR)))
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
export PROJECTDIR := $(CURDIR)
export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
TTFFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.ttf)))
PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
export REAL_LD := $(CC)
else
export REAL_LD := $(CXX)
endif
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
$(sFILES:.s=.o) $(SFILES:.S=.o) \
$(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES))
#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE_FULL += $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(EXTERNAL_INCLUDE)
#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS_FULL += $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
$(EXTERNAL_LIBPATHS)
export OUTPUT := $(CURDIR)/$(TARGET) export OUTPUT := $(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean install export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#-------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#-------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#-------------------------------------------------------------------------------
export LD := $(CC)
#-------------------------------------------------------------------------------
else
#-------------------------------------------------------------------------------
export LD := $(CXX)
#-------------------------------------------------------------------------------
endif
#-------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#-------------------------------------------------------------------------------
all: $(BUILD)
#---------------------------------------------------------------------------------
$(BUILD): $(BUILD):
@[ -d $@ ] || mkdir -p $@ @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
clean: clean:
@echo clean ... @echo clean ...
@rm -fr $(BUILD) $(OUTPUT).mod $(OUTPUT) @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
else else
.PHONY: all
DEPENDS := $(OFILES:.o=.d) DEPENDS := $(OFILES:.o=.d)
THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) #-------------------------------------------------------------------------------
# main targets
#-------------------------------------------------------------------------------
all : $(OUTPUT).wps
############################################################################### $(OUTPUT).wps : $(OUTPUT).elf
# Rule to make everything. $(OUTPUT).elf : $(OFILES)
PHONY += all
all : $(OUTPUT) $(OFILES_SRC) : $(HFILES_BIN)
###############################################################################
# Special build rules
#-------------------------------------------------------------------------------
# Rule to make the module file. # you need a rule like this for each extension you use as binary data
$(OUTPUT) : $(OFILES) #-------------------------------------------------------------------------------
@echo "linking ... " $@ %.bin.o %_bin.h : %.bin
@$(REAL_LD) $(OFILES) $(LDFLAGS) $(LIBS) $(LIBPATHS_FULL) -o $@ #-------------------------------------------------------------------------------
###############################################################################
# Standard build rules
#---------------------------------------------------------------------------------
%.a:
#---------------------------------------------------------------------------------
@echo $(notdir $@)
@rm -f $@
@$(AR) -rc $@ $^
#---------------------------------------------------------------------------------
%.o: %.cpp
@echo $(notdir $<) @echo $(notdir $<)
@$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER) @$(bin2o)
#---------------------------------------------------------------------------------
%.o: %.c
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.o: %.S
@echo $(notdir $<)
@$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(INCLUDE_FULL) -c $< -o $@ $(ERROR_FILTER)
#---------------------------------------------------------------------------------
%.png.o : %.png
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.jpg.o : %.jpg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ttf.o : %.ttf
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.wav.o : %.wav
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.mp3.o : %.mp3
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
#---------------------------------------------------------------------------------
%.ogg.o : %.ogg
@echo $(notdir $<)
@bin2s -a 32 $< | $(AS) -o $(@)
###############################################################################
# Assembly listing rules
# Rule to make assembly listing.
PHONY += list
list : $(LIST)
# Rule to make the listing file.
%.list : $(TARGET)
$(LOG)
-$Qmkdir -p $(dir $@)
$Q$(OBJDUMP) -d $< > $@
###############################################################################
# Clean rule
# Rule to clean files.
PHONY += clean
clean :
$Qrm -rf $(wildcard $(BUILD) $(BIN))
###############################################################################
# Phony targets
.PHONY : $(PHONY)
-include $(DEPENDS) -include $(DEPENDS)
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
endif endif
#--------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -1,32 +1,69 @@
# SwipSwapMe Plugin for the Wii U Plugin System [![Build Status](https://api.travis-ci.org/Maschell/SwipSwapMe.svg?branch=master)](https://travis-ci.org/Maschell/SwipSwapMe) # SwipSwapMe Plugin
This little app can be used to swap the TV and DRC screen. This little plugin can be used to swap the TV and GamePad screen and offers different audio modes.
# Wii U Plugin System **When this plugin is enabled, the audio output of your Wii U is forced to stereo**
This is a plugin for the [Wii U Plugin System (WUPS)](https://github.com/Maschell/WiiUPluginSystem/). To be able to use this plugin you have to place the resulting `.mod` file into the following folder:
``` ## Installation
sd:/wiiu/plugins
```
When the file is placed on the SDCard you can load it with [plugin loader](https://github.com/Maschell/WiiUPluginSystem/).
# Usage (`[ENVIRONMENT]` is a placeholder for the actual environment name.)
When starting the app, you have the option to set your own button combo. Just press the button combo you want for 2 seconds. 1. Copy the file `swipswapme.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`.
Otherwise it will use the default settings (TV button). 2. Requires the [WiiUPluginLoaderBackend](https://github.com/wiiu-env/WiiUPluginLoaderBackend) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
3. Requires the [MemoryMappingModule](https://github.com/wiiu-env/MemoryMappingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
4. Requires the [NotificationModule](https://github.com/wiiu-env/NotificationModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
Press the TV button (or your button combo) on the Gamepad to swap the screens. Thats all. ## Usage
Press a button combo (default is the GamePad's TV button) on the GamePad, Pro Controller or Classic Controller to take swap the screens.
Via the plugin config menu (press L, DPAD Down and Minus on the GamePad, Pro Controller or Classic Controller) you can configure the plugin. The available options are the following:
- **Settings**:
- Plugin enabled: (Default is true)
- Enables or disables the SwipSwapMe plugin. **Forces the audio output to stereo when enabled.**
- Show notifications: (Default is true)
- Displays notifications when swapping the screens or changing the audio mode.
- Swap screens: (Default is false)
- Swaps the TV and GamePad screen when set to true.
- Audio mode: (Default is "Sound matches screen")
- Sets the audio mode. See "Audio modes" for more details.
- **Button combos**
- Enable swap screen button combo: (Default is true)
- Determines if the screen can be swapped with a button combo.
- Swap screen: (Default is the "TV" button)
- Button combo to swap the TV and GamePad screen.
- Enable change audio mode button combo: (Default is false)
- Determines if the audio mode can be changed via a button combo.
- Change audio: (Default is "left stick button"/L3)
- Button combo to change the audio mode.
#### Audio Modes
SwipSwapme does not only allow you to swap the screen, it also offers multiple audio modes:
- **Normal**
- The audio output is not touched at all.
- **Swap TV and GamePad sound**
- Swaps the audio output of the TV and GamePad regardless of the screen swapping.
- **Sound matches screen**
- Swaps the audio output of the TV and GamePad if the screen are swapped as well.
- **Combine TV and GamePad sound**
- Outputs the TV and GamePad sound on both.
- **Left: TV; Right: GamePad**
- Outputs the TV sound on the left speaker, and the GamePad sound on the right speaker.
## Building ## Building
For building you need: For building you need:
- [wups](https://github.com/Maschell/WiiUPluginSystem)
- [wut](https://github.com/decaf-emu/wut)
- [libutilswut](https://github.com/Maschell/libutils/tree/wut) (WUT version) for common functions.
Install them (in this order) according to their README's. Don't forget the dependencies of the libs itself. - [wups](https://github.com/wiiu-env/WiiUPluginSystem)
- [wut](https://github.com/devkitPro/wut)
- [libnotifications](https://github.com/wiiu-env/libnotifications)
- [libmappedmemory](https://github.com/wiiu-env/libmappedmemory)
## Building using the Dockerfile
### Building using the Dockerfile
It's possible to use a docker image for building. This way you don't need anything installed on your host system. It's possible to use a docker image for building. This way you don't need anything installed on your host system.
``` ```
@ -39,3 +76,7 @@ docker run -it --rm -v ${PWD}:/project swipswapme-builder make
# make clean # make clean
docker run -it --rm -v ${PWD}:/project swipswapme-builder make clean docker run -it --rm -v ${PWD}:/project swipswapme-builder make clean
``` ```
## Format the code via docker
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i`

View File

@ -1,66 +0,0 @@
# Compiling the projects with libutils logging code?
DO_LOGGING := 1
# Links against the wut implementation of newlib, this is useful for using any function
# from the C standard library
WUT_ENABLE_NEWLIB := 0
# Links against the wut implementation of stdcpp, this is useful for using any function
# from the C++ standard library. This will enable WUT_ENABLE_NEWLIB if you have not already done so.
WUT_ENABLE_CPP := 0
# By default newlib will allocate 90% of the default heap for use with sbrk & malloc,
# if this is unacceptable to you then you should use this as it replaces the newlib
# malloc functions which ones which redirect to the CafeOS default heap functions
# such as MEMAllocFromDefaultHeap.
WUT_DEFAULT_MALLOC := 1
# Target filename
TARGET := swipswapme.mod
# Source directories
SOURCES := src/ \
src/common \
src/utils \
# Data directories
DATA :=
# Include directories
INCLUDES := src
#---------------------------------------------------------------------------------
# options for code generation and linking
#---------------------------------------------------------------------------------
# Extra C AND C++ compiler flags
COMMON_CFLAGS :=
# Extra C compiler flags
CFLAGS :=
# Extra C++ compiler flags
CXXFLAGS :=
# Extra linking flags for all linking steps
LDFLAGS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(WUPSDIR) $(WUT_ROOT)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lwups -lutilswut -lcoreinit -lvpad -lnsysnet
#---------------------------------------------------------------------------------
# Will be added to the final lib paths
# example:
# -L$C:/library1/lib
#---------------------------------------------------------------------------------
EXTERNAL_LIBPATHS :=
#---------------------------------------------------------------------------------
# Will be added to the final include paths
# -IC:/library1/include
#---------------------------------------------------------------------------------
EXTERNAL_INCLUDE := -I$(WUT_ROOT)/include/libutilswut

View File

@ -1,24 +0,0 @@
/****************************************************************************
* Copyright (C) 2017,2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "common/c_retain_vars.h"
uint8_t gSwap __attribute__((section(".data"))) = 0;
uint8_t gCallbackCooldown __attribute__((section(".data"))) = 0;
uint8_t gAppStatus __attribute__((section(".data"))) = 0;
uint32_t gButtonCombo __attribute__((section(".data"))) = 0;
VoiceInfo gVoiceInfos[VOICE_INFO_MAX] __attribute__((section(".data")));

View File

@ -1,27 +0,0 @@
/****************************************************************************
* Copyright (C) 2017,2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef C_RETAINS_VARS_H_
#define C_RETAINS_VARS_H_
#include "utils/voice_info.h"
extern uint8_t gSwap;
extern uint8_t gCallbackCooldown;
extern uint8_t gAppStatus;
extern uint32_t gButtonCombo;
extern VoiceInfo gVoiceInfos[VOICE_INFO_MAX];
#endif // C_RETAINS_VARS_H_

View File

@ -14,106 +14,315 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include <wups.h> #include "retain_vars.hpp"
#include "utils/input.h"
#include "utils/logger.h"
#include <coreinit/dynload.h>
#include <gx2/surface.h>
#include <gx2/swap.h> #include <gx2/swap.h>
#include <memory/mappedmemory.h>
#include <notifications/notifications.h>
#include <padscore/wpad.h>
#include <vpad/input.h> #include <vpad/input.h>
#include <utils/logger.h> #include <wups.h>
#include "utils/voice_swapper.h" void UpdateAudioMode();
#include "common/c_retain_vars.h"
DECL_FUNCTION(int32_t, AXSetVoiceDeviceMixOld, void *v, int32_t device, uint32_t id, void *mix){ DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) {
if(gSwap){ device = !device;} if (gEnabled && gDoScreenSwap) {
if(VOICE_SWAP_LOG == 1){log_printf("AXSetVoiceDeviceMixOld voice: %08X device: %d, mix: %08X\n",v,device,mix);} if (scan_target == GX2_SCAN_TARGET_TV) {
VoiceSwapper_setMix(v,device,mix); scan_target = GX2_SCAN_TARGET_DRC;
return real_AXSetVoiceDeviceMixOld(v,device,id,mix); } else if (scan_target == GX2_SCAN_TARGET_DRC) {
scan_target = GX2_SCAN_TARGET_TV;
} }
if (colorBuffer->surface.aa != GX2_AA_MODE1X) {
// If AA is enabled, we need to resolve the AA buffer.
GX2Surface tempSurface;
tempSurface = colorBuffer->surface;
tempSurface.aa = GX2_AA_MODE1X;
GX2CalcSurfaceSizeAndAlignment(&tempSurface);
DECL_FUNCTION(int32_t, AXSetVoiceDeviceMix, void *v, int32_t device, uint32_t id, void *mix){ tempSurface.image = MEMAllocFromMappedMemoryForGX2Ex(tempSurface.imageSize, tempSurface.alignment);
if(gSwap){ device = !device;} if (tempSurface.image != nullptr) {
if(VOICE_SWAP_LOG == 1){log_printf("AXSetVoiceDeviceMix voice: %08X device: %d, mix: %08X\n",v,device,mix);} GX2ResolveAAColorBuffer(colorBuffer, &tempSurface, 0, 0);
VoiceSwapper_setMix(v,device,mix);
return real_AXSetVoiceDeviceMix(v,device,id,mix); auto surfaceCpy = colorBuffer->surface;
colorBuffer->surface = tempSurface;
real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
colorBuffer->surface = surfaceCpy;
if (tempSurface.image != nullptr) {
MEMFreeToMappedMemory(tempSurface.image);
tempSurface.image = nullptr;
} }
return;
DECL_FUNCTION(void *, AXAcquireVoiceExOld, uint32_t prio, void * callback, uint32_t arg){
void * result = real_AXAcquireVoiceExOld(prio,callback,arg);
if(VOICE_SWAP_LOG == 1){log_printf("AXAcquireVoiceExOld result: %08X \n",result);}
VoiceSwapper_acquireVoice(result);
return result;
}
DECL_FUNCTION(void *, AXAcquireVoiceEx, uint32_t prio, void * callback, uint32_t arg){
void * result = real_AXAcquireVoiceEx(prio,callback,arg);
if(VOICE_SWAP_LOG == 1){log_printf("AXAcquireVoiceEx result: %08X \n",result);}
VoiceSwapper_acquireVoice(result);
return result;
}
DECL_FUNCTION(void, AXFreeVoiceOld, void *v){
if(VOICE_SWAP_LOG == 1){log_printf("AXFreeVoiceOld v: %08X \n",v);}
VoiceSwapper_freeVoice(v);
real_AXFreeVoiceOld(v);
}
DECL_FUNCTION(void, AXFreeVoice, void *v){
if(VOICE_SWAP_LOG == 1){log_printf("AXFreeVoice v: %08X \n",v);}
VoiceSwapper_freeVoice(v);
real_AXFreeVoice(v);
}
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, GX2ColorBuffer *colorBuffer, int32_t scan_target){
if(gSwap){
if(scan_target == 1){
scan_target = 4;
} else { } else {
scan_target = 1; DEBUG_FUNCTION_LINE_ERR("Failed to allocate %d bytes for resolving AA", tempSurface.imageSize);
} }
} }
}
real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target); real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target);
} }
/* void SwapScreens() {
DECL(int32_t, AXSetDefaultMixerSelectOld, uint32_t s){ gDoScreenSwap = !gDoScreenSwap;
int32_t result = real_AXSetDefaultMixerSelectOld(s);
return result;
}*/
if (gShowNotifications && gNotificationModuleInitDone) {
void swapVoices(){ if (gDoScreenSwap) {
VoiceSwapper_swapAll(); NotificationModule_AddInfoNotification("Swapping TV and GamePad screen");
for(int32_t i = 0;i<VOICE_INFO_MAX;i++){ } else {
if(gVoiceInfos[i].voice == NULL) continue; NotificationModule_AddInfoNotification("Stop swapping TV and GamePad screen");
}
real_AXSetVoiceDeviceMix(gVoiceInfos[i].voice,0,0,gVoiceInfos[i].mixTV);
real_AXSetVoiceDeviceMix(gVoiceInfos[i].voice,1,0,gVoiceInfos[i].mixDRC);
real_AXSetVoiceDeviceMixOld(gVoiceInfos[i].voice,0,0,gVoiceInfos[i].mixTV);
real_AXSetVoiceDeviceMixOld(gVoiceInfos[i].voice,1,0,gVoiceInfos[i].mixDRC);
} }
} }
DECL_FUNCTION(int32_t, VPADRead, int32_t chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) { void SwapVoices();
int32_t result = real_VPADRead(chan, buffer, buffer_size, error); extern "C" uint32_t VPADGetButtonProcMode(VPADChan chan);
if(result > 0 && *error == VPAD_READ_SUCCESS && ((buffer[0].hold & gButtonCombo) == gButtonCombo) && gCallbackCooldown == 0 ){ static uint32_t sSwapScreenWasHoldForXFrameGamePad;
gCallbackCooldown = 0x3C; static uint32_t sSwapVoicesWasHoldForXFrameGamePad;
if(gAppStatus == WUPS_APP_STATUS_FOREGROUND){ DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) {
gSwap = !gSwap; VPADReadError real_error;
swapVoices(); int32_t result = real_VPADRead(chan, buffer, buffer_size, &real_error);
if (gEnabled && (gSwapScreenButtonComboEnabled || gChangeAudioModeButtonComboEnabled)) {
if (result > 0 && real_error == VPAD_READ_SUCCESS) {
// Fix games like TP HD
bool checkFullBuffer = VPADGetButtonProcMode(chan) == 1;
if (gChangeAudioModeButtonComboEnabled && checkButtonComboVPAD(buffer,
checkFullBuffer ? buffer_size : 1,
gSwapAudioButtonCombo,
sSwapVoicesWasHoldForXFrameGamePad)) {
SwapVoices();
}
if (gSwapScreenButtonComboEnabled && checkButtonComboVPAD(buffer,
checkFullBuffer ? buffer_size : 1,
gSwapScreenButtonCombo,
sSwapScreenWasHoldForXFrameGamePad)) {
SwapScreens();
}
} }
} }
if(gCallbackCooldown > 0) gCallbackCooldown--;
if (error) {
*error = real_error;
}
return result; return result;
} }
const char *modeToStr(SwipSwapAudioMode mode) {
switch (mode) {
case AUDIO_MODE_NONE:
return "Audio mode: Normal";
case AUDIO_MODE_SWAP:
return "Audio mode: Swap TV and GamePad";
case AUDIO_MODE_MATCH_SCREEN:
return "Audio mode: Sound matches screen";
case AUDIO_MODE_COMBINE:
return "Audio mode: Combine TV and GamePad";
case AUDIO_MODE_LEFT_TV_RIGHT_DRC:
return "Audio mode: Left speaker TV, right speaker GamePad";
case AUDIO_MODE_MAX_VALUE:
break;
}
return "Invalid audio mode";
}
void SwapVoices() {
auto val = (uint32_t) gCurAudioMode;
val++;
if (val >= AUDIO_MODE_MAX_VALUE) {
val = 0;
}
gCurAudioMode = static_cast<SwipSwapAudioMode>(val);
if (gShowNotifications && gNotificationModuleInitDone) {
NotificationModule_AddInfoNotification(modeToStr(gCurAudioMode));
}
}
static uint32_t sSwapScreenWasHoldForXFrame[4];
static uint32_t sSwapAudioWasHoldForXFrame[4];
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
real_WPADRead(chan, data);
if (gEnabled && (gSwapScreenButtonComboEnabled || gChangeAudioModeButtonComboEnabled) && chan >= 0 && chan < 4) {
if (data && data[0].err == 0) {
if (data[0].extensionType != 0xFF) {
uint32_t curButtonHold = 0;
if (data[0].extensionType == WPAD_EXT_CORE || data[0].extensionType == WPAD_EXT_NUNCHUK) {
// button data is in the first 2 bytes for wiimotes
curButtonHold = remapWiiMoteButtons(((uint16_t *) data)[0]);
} else if (data[0].extensionType == WPAD_EXT_CLASSIC) {
curButtonHold = remapClassicButtons(((uint32_t *) data)[10] & 0xFFFF);
} else if (data[0].extensionType == WPAD_EXT_PRO_CONTROLLER) {
curButtonHold = remapProButtons(data[0].buttons);
}
if (gSwapScreenButtonComboEnabled && checkButtonComboWPAD(curButtonHold, gSwapScreenButtonCombo, sSwapScreenWasHoldForXFrame[chan])) {
SwapScreens();
}
if (gChangeAudioModeButtonComboEnabled && checkButtonComboWPAD(curButtonHold, gSwapAudioButtonCombo, sSwapAudioWasHoldForXFrame[chan])) {
SwapVoices();
}
}
}
}
}
int16_t DRCCopy[0x120] = {};
int16_t TVCopy[0x120] = {};
typedef void (*AIInitDMAfn)(int16_t *addr, uint32_t size);
void DoAudioMagic(int16_t *addr, uint32_t size, bool isDRC, AIInitDMAfn targetFunc, AIInitDMAfn otherFunc) {
auto sizeCpy = size > 576 ? 576 : size;
if (!gEnabled) {
targetFunc(addr, size);
return;
}
switch (gCurAudioMode) {
case AUDIO_MODE_NONE:
break;
case AUDIO_MODE_SWAP:
otherFunc(addr, sizeCpy);
return;
case AUDIO_MODE_MATCH_SCREEN: {
if (gDoScreenSwap) {
otherFunc(addr, sizeCpy);
return;
}
break;
}
case AUDIO_MODE_COMBINE:
case AUDIO_MODE_LEFT_TV_RIGHT_DRC: {
if (isDRC) {
memcpy(DRCCopy, addr, sizeCpy);
} else {
memcpy(TVCopy, addr, sizeCpy);
}
if (gCurAudioMode == AUDIO_MODE_COMBINE) {
for (uint32_t i = 0; i < 0x120; i += 2) {
// Combine left channel of TV and DRC
auto val = (((int32_t) TVCopy[i] + (int32_t) DRCCopy[i]) >> 1);
if (val > 0x7FFF) {
val = 0x7FFF;
} else if (val < -0x8000) {
val = 0x8000;
}
addr[i] = (int16_t) val;
// Combine right channel of TV and DRC
val = (((int32_t) TVCopy[i] + (int32_t) DRCCopy[i]) >> 1);
if (val > 0x7FFF) {
val = 0x7FFF;
} else if (val < -0x8000) {
val = 0x8000;
}
addr[i + 1] = (int16_t) val;
}
} else if (gCurAudioMode == AUDIO_MODE_LEFT_TV_RIGHT_DRC) {
for (uint32_t i = 0; i < 0x120; i += 2) {
// Mix down TV to MONO and put it in the left channel
auto val = (((int32_t) TVCopy[i] + (int32_t) TVCopy[i + 1]) >> 1);
if (val > 0x7FFF) {
val = 0x7FFF;
} else if (val < -0x8000) {
val = 0x8000;
}
addr[i] = (int16_t) val;
// Mix down DRC to MONO and put it in the right channel
val = (((int32_t) DRCCopy[i] + (int32_t) DRCCopy[i + 1]) >> 1);
if (val > 0x7FFF) {
val = 0x7FFF;
} else if (val < -0x8000) {
val = 0x8000;
}
addr[i + 1] = (int16_t) val;
}
}
break;
}
default:
gCurAudioMode = AUDIO_MODE_NONE;
break;
}
targetFunc(addr, sizeCpy);
}
extern "C" void (*real_AIInitDMA)(int16_t *addr, uint32_t size) __attribute__((section(".data")));
extern "C" void (*real_AIInitDMA2)(int16_t *addr, uint32_t size) __attribute__((section(".data")));
DECL_FUNCTION(void, AI2InitDMA, int16_t *addr, uint32_t size) {
DoAudioMagic(addr, size, true, real_AI2InitDMA, real_AIInitDMA);
}
DECL_FUNCTION(void, AIInitDMA, int16_t *addr, uint32_t size) {
DoAudioMagic(addr, size, false, real_AIInitDMA, real_AI2InitDMA);
}
DECL_FUNCTION(void, AI2InitDMA2, int16_t *addr, uint32_t size) {
DoAudioMagic(addr, size, true, real_AI2InitDMA2, real_AIInitDMA2);
}
DECL_FUNCTION(void, AIInitDMA2, int16_t *addr, uint32_t size) {
DoAudioMagic(addr, size, false, real_AIInitDMA2, real_AI2InitDMA2);
}
bool sAvoidRecursiveCall = false;
DECL_FUNCTION(void, AXUpdateDeviceModes) {
if (!gEnabled) {
real_AXUpdateDeviceModes();
return;
}
sAvoidRecursiveCall = true;
real_AXUpdateDeviceModes();
sAvoidRecursiveCall = false;
}
bool sAvoidRecursiveCall2 = false;
DECL_FUNCTION(void, AXUpdateDeviceModes2) {
if (!gEnabled) {
real_AXUpdateDeviceModes2();
return;
}
sAvoidRecursiveCall2 = true;
real_AXUpdateDeviceModes2();
sAvoidRecursiveCall2 = false;
}
DECL_FUNCTION(uint32_t, AVMGetTVAudioMode, uint32_t *mode) {
auto res = real_AVMGetTVAudioMode(mode);
if (!gEnabled) {
return res;
}
if (*mode != 1) {
// force stereo
*mode = 1;
UpdateAudioMode();
}
return res;
}
void UpdateAudioMode() {
OSDynLoad_Module mod = nullptr;
if (OSDynLoad_IsModuleLoaded("sndcore2", &mod) == OS_DYNLOAD_OK && mod != nullptr) {
if (real_AXUpdateDeviceModes2 != nullptr && !sAvoidRecursiveCall2) {
my_AXUpdateDeviceModes2();
}
} else if (OSDynLoad_IsModuleLoaded("snd_core", &mod) == OS_DYNLOAD_OK && mod != nullptr) {
if (real_AXUpdateDeviceModes != nullptr && !sAvoidRecursiveCall) {
my_AXUpdateDeviceModes();
}
}
}
WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer); WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer);
WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead); WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead);
WUPS_MUST_REPLACE(AXAcquireVoiceExOld, WUPS_LOADER_LIBRARY_SND_CORE, AXAcquireVoiceEx); WUPS_MUST_REPLACE(WPADRead, WUPS_LOADER_LIBRARY_PADSCORE, WPADRead);
WUPS_MUST_REPLACE(AXFreeVoiceOld, WUPS_LOADER_LIBRARY_SND_CORE, AXFreeVoice);
WUPS_MUST_REPLACE(AXSetVoiceDeviceMixOld, WUPS_LOADER_LIBRARY_SND_CORE, AXSetVoiceDeviceMix); WUPS_MUST_REPLACE_FOR_PROCESS(AIInitDMA, WUPS_LOADER_LIBRARY_SND_CORE, AIInitDMA, WUPS_FP_TARGET_PROCESS_ALL);
//WUPS_MUST_REPLACE(AXSetDefaultMixerSelectOld, , WUPS_LOADER_LIBRARY_SND_CORE, AXSetDefaultMixerSelect), WUPS_MUST_REPLACE_FOR_PROCESS(AI2InitDMA, WUPS_LOADER_LIBRARY_SND_CORE, AI2InitDMA, WUPS_FP_TARGET_PROCESS_ALL);
WUPS_MUST_REPLACE(AXAcquireVoiceEx, WUPS_LOADER_LIBRARY_SNDCORE2, AXAcquireVoiceEx); WUPS_MUST_REPLACE_FOR_PROCESS(AIInitDMA2, WUPS_LOADER_LIBRARY_SNDCORE2, AIInitDMA, WUPS_FP_TARGET_PROCESS_ALL);
WUPS_MUST_REPLACE(AXFreeVoice, WUPS_LOADER_LIBRARY_SNDCORE2, AXFreeVoice); WUPS_MUST_REPLACE_FOR_PROCESS(AI2InitDMA2, WUPS_LOADER_LIBRARY_SNDCORE2, AI2InitDMA, WUPS_FP_TARGET_PROCESS_ALL);
WUPS_MUST_REPLACE(AXSetVoiceDeviceMix, WUPS_LOADER_LIBRARY_SNDCORE2, AXSetVoiceDeviceMix);
WUPS_MUST_REPLACE_FOR_PROCESS(AVMGetTVAudioMode, WUPS_LOADER_LIBRARY_AVM, AVMGetTVAudioMode, WUPS_FP_TARGET_PROCESS_ALL);
WUPS_MUST_REPLACE_FOR_PROCESS(AXUpdateDeviceModes, WUPS_LOADER_LIBRARY_SND_CORE, AXUpdateDeviceModes, WUPS_FP_TARGET_PROCESS_ALL);
WUPS_MUST_REPLACE_FOR_PROCESS(AXUpdateDeviceModes2, WUPS_LOADER_LIBRARY_SNDCORE2, AXUpdateDeviceModes, WUPS_FP_TARGET_PROCESS_ALL);

View File

@ -14,141 +14,85 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/ ****************************************************************************/
#include "main.h"
#include <string.h> #include "retain_vars.hpp"
#include <stdlib.h> #include "utils/WUPSConfigItemButtonCombo.h"
#include <stdio.h> #include "utils/config.h"
#include <malloc.h> #include "utils/logger.h"
#include <notifications/notifications.h>
#include <string>
#include <wups.h> #include <wups.h>
#include <vector> // Mandatory plugin information.
#include <string>
#include <vpad/input.h>
#include <coreinit/screen.h>
#include <coreinit/thread.h>
#include <common/c_retain_vars.h>
#include <nsysnet/socket.h>
#include <utils/logger.h>
WUPS_PLUGIN_NAME("SwipSwapMe"); WUPS_PLUGIN_NAME("SwipSwapMe");
WUPS_PLUGIN_DESCRIPTION("Swaps the gamepad and tv screen when pressing a certain button (TV is default)"); WUPS_PLUGIN_DESCRIPTION("Swaps the GamePad and TV screen when pressing a certain button combination");
WUPS_PLUGIN_VERSION("v1.0"); WUPS_PLUGIN_VERSION(PLUGIN_VERSION_FULL);
WUPS_PLUGIN_AUTHOR("Maschell"); WUPS_PLUGIN_AUTHOR("Maschell");
WUPS_PLUGIN_LICENSE("GPL"); WUPS_PLUGIN_LICENSE("GPL");
WUPS_FS_ACCESS() // FS Access
WUPS_USE_WUT_DEVOPTAB();
uint32_t SplashScreen(int32_t time,int32_t combotime); WUPS_USE_STORAGE("SwipSwapMeAroma");
/* Entry point */
ON_APPLICATION_START(args) {
memset(gVoiceInfos,0,sizeof(gVoiceInfos));
socket_lib_init();
log_init();
}
ON_APP_STATUS_CHANGED(status) {
gAppStatus = status;
}
// Gets called once the loader exists.
INITIALIZE_PLUGIN() { INITIALIZE_PLUGIN() {
uint32_t res = SplashScreen(10,2); initLogging();
gButtonCombo = res;
}
#define FPS 60 if (NotificationModule_InitLibrary() == NOTIFICATION_MODULE_RESULT_SUCCESS) {
uint32_t SplashScreen(int32_t time,int32_t combotime) { gNotificationModuleInitDone = true;
uint32_t result = VPAD_BUTTON_TV;
// Init screen
OSScreenInit();
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
uint32_t * screenbuffer0 = (uint32_t*)memalign(0x100, screen_buf0_size);
uint32_t * screenbuffer1 = (uint32_t*)memalign(0x100, screen_buf1_size);
if(screenbuffer0 == NULL || screenbuffer1 == NULL) {
if(screenbuffer0 != NULL) {
free(screenbuffer0);
}
if(screenbuffer1 != NULL) {
free(screenbuffer1);
}
return result;
}
OSScreenSetBufferEx(SCREEN_TV, (void *)screenbuffer0);
OSScreenSetBufferEx(SCREEN_DRC, (void *)screenbuffer1);
OSScreenEnableEx(SCREEN_TV, 1);
OSScreenEnableEx(SCREEN_DRC, 1);
// Clear screens
OSScreenClearBufferEx(SCREEN_TV, 0);
OSScreenClearBufferEx(SCREEN_DRC, 0);
// Flip buffers
OSScreenFlipBuffersEx(SCREEN_TV);
OSScreenFlipBuffersEx(SCREEN_DRC);
OSScreenClearBufferEx(SCREEN_TV, 0);
OSScreenClearBufferEx(SCREEN_DRC, 0);
std::vector<std::string> strings;
strings.push_back("SwipSwapMe 0.2 - by Maschell.");
strings.push_back("");
strings.push_back("");
strings.push_back("Press the combo you want to use for swapping now for 2 seconds.");
strings.push_back("Pressing the TV button will return directly.");
strings.push_back("");
strings.push_back("Otherwise the default combo (TV button) will be used in 10 seconds.");
uint8_t pos = 0;
for (std::vector<std::string>::iterator it = strings.begin() ; it != strings.end(); ++it) {
OSScreenPutFontEx(SCREEN_TV, 0, pos, (*it).c_str());
OSScreenPutFontEx(SCREEN_DRC, 0, pos, (*it).c_str());
pos++;
}
OSScreenFlipBuffersEx(SCREEN_TV);
OSScreenFlipBuffersEx(SCREEN_DRC);
int32_t tickswait = time * FPS * 16;
int32_t sleepingtime = 16;
int32_t times = tickswait/16;
int32_t i=0;
VPADStatus vpad_data;
VPADReadError error;
uint32_t last = 0xFFFFFFFF;
int32_t timer = 0;
while(i<times) {
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &error);
if(vpad_data.trigger == VPAD_BUTTON_TV)
break;
if(last == vpad_data.hold && last != 0) {
timer++;
} else { } else {
last = vpad_data.hold; gNotificationModuleInitDone = false;
timer = 0; DEBUG_FUNCTION_LINE_ERR("Failed to init notification lib");
}
if(timer >= combotime*FPS) {
result = vpad_data.hold;
break;
}
i++;
OSSleepTicks(OSMicrosecondsToTicks(sleepingtime*1000));
} }
if(screenbuffer0 != NULL) { // Open storage to read values
free(screenbuffer0); WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
} else {
LOAD_BOOL_FROM_STORAGE(ENABLED_CONFIG_STRING, gEnabled);
LOAD_BOOL_FROM_STORAGE(SWAP_SCREENS_CONFIG_STRING, gDoScreenSwap);
LOAD_BOOL_FROM_STORAGE(ENABLED_SWAP_SCREENS_COMBO_CONFIG_STRING, gSwapScreenButtonComboEnabled);
LOAD_BOOL_FROM_STORAGE(ENABLED_CHANGE_AUDIO_COMBO_CONFIG_STRING, gChangeAudioModeButtonComboEnabled);
LOAD_BOOL_FROM_STORAGE(ENABLE_NOTIFICATIONS_CONFIG_STRING, gShowNotifications);
LOAD_INT_FROM_STORAGE(SWAP_SCREEN_BUTTON_COMBO_CONFIG_STRING, gSwapScreenButtonCombo);
LOAD_INT_FROM_STORAGE(CHANGE_AUDIO_BUTTON_COMBO_CONFIG_STRING, gSwapAudioButtonCombo);
LOAD_INT_FROM_STORAGE(SCREEN_MODE_CONFIG_STRING, gCurAudioMode);
// Close storage
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
} }
if(screenbuffer1 != NULL) { }
free(screenbuffer1); deinitLogging();
} }
return result; // Called whenever an application was started.
ON_APPLICATION_START() {
initLogging();
}
ON_APPLICATION_REQUESTS_EXIT() {
// Open storage to write current config
WUPSStorageError storageRes = WUPS_OpenStorage();
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
} else {
WUPS_StoreInt(nullptr, SCREEN_MODE_CONFIG_STRING, (int32_t) gCurAudioMode);
WUPS_StoreBool(nullptr, SWAP_SCREENS_CONFIG_STRING, (int32_t) gDoScreenSwap);
// Close storage
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
}
deinitLogging();
}
ON_APPLICATION_ENDS() {
if (gNotificationModuleInitDone) {
NotificationModule_DeInitLibrary();
gNotificationModuleInitDone = false;
}
} }

5
src/main.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "version.h"
#define PLUGIN_VERSION "v0.1"
#define PLUGIN_VERSION_FULL PLUGIN_VERSION PLUGIN_VERSION_EXTRA

12
src/retain_vars.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "retain_vars.hpp"
#include <vpad/input.h>
uint32_t gSwapScreenButtonCombo = VPAD_BUTTON_TV;
uint32_t gSwapAudioButtonCombo = VPAD_BUTTON_STICK_L;
bool gSwapScreenButtonComboEnabled = true;
bool gChangeAudioModeButtonComboEnabled = false;
bool gEnabled = true;
bool gDoScreenSwap = false;
bool gShowNotifications = true;
bool gNotificationModuleInitDone = true;
SwipSwapAudioMode gCurAudioMode = AUDIO_MODE_MATCH_SCREEN;

22
src/retain_vars.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
typedef enum SwipSwapAudioMode {
AUDIO_MODE_NONE = 0,
AUDIO_MODE_SWAP = 1,
AUDIO_MODE_MATCH_SCREEN = 2,
AUDIO_MODE_COMBINE = 3,
AUDIO_MODE_LEFT_TV_RIGHT_DRC = 4,
AUDIO_MODE_MAX_VALUE = 5
} SwipSwapAudioMode;
extern uint32_t gSwapScreenButtonCombo;
extern uint32_t gSwapAudioButtonCombo;
extern bool gSwapScreenButtonComboEnabled;
extern bool gChangeAudioModeButtonComboEnabled;
extern bool gEnabled;
extern bool gDoScreenSwap;
extern bool gShowNotifications;
extern bool gNotificationModuleInitDone;
extern SwipSwapAudioMode gCurAudioMode;

View File

@ -0,0 +1,265 @@
#include "WUPSConfigItemButtonCombo.h"
#include "utils/input.h"
#include <coreinit/debug.h>
#include <coreinit/thread.h>
#include <coreinit/time.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vpad/input.h>
#include <wups.h>
const char *getButtonChar(VPADButtons value) {
std::string combo;
if (value & VPAD_BUTTON_A) {
return "\ue000";
}
if (value & VPAD_BUTTON_B) {
return "\ue001";
}
if (value & VPAD_BUTTON_X) {
return "\ue002";
}
if (value & VPAD_BUTTON_Y) {
return "\ue003";
}
if (value & VPAD_BUTTON_L) {
return "\ue083";
}
if (value & VPAD_BUTTON_R) {
return "\ue084";
}
if (value & VPAD_BUTTON_ZL) {
return "\ue085";
}
if (value & VPAD_BUTTON_ZR) {
return "\ue086";
}
if (value & VPAD_BUTTON_UP) {
return "\ue079";
}
if (value & VPAD_BUTTON_DOWN) {
return "\ue07A";
}
if (value & VPAD_BUTTON_LEFT) {
return "\ue07B";
}
if (value & VPAD_BUTTON_RIGHT) {
return "\ue07C";
}
if (value & VPAD_BUTTON_STICK_L) {
return "\ue081";
}
if (value & VPAD_BUTTON_STICK_R) {
return "\ue082";
}
if (value & VPAD_BUTTON_PLUS) {
return "\ue045";
}
if (value & VPAD_BUTTON_MINUS) {
return "\ue046";
}
if (value & VPAD_BUTTON_TV) {
return "\ue089";
}
if (value & VPAD_BUTTON_RESERVED_BIT) {
return "\ue01E";
}
return "";
}
std::string getComboAsString(uint32_t value) {
char comboString[60];
memset(comboString, 0, sizeof(comboString));
for (uint32_t i = 0; i < 32; i++) {
uint32_t bitMask = 1 << i;
if (value & bitMask) {
auto val = getButtonChar(static_cast<VPADButtons>(bitMask));
if (val[0] != '\0') {
strcat(comboString, val);
strcat(comboString, "+");
}
}
}
std::string res(comboString);
if (res.ends_with("+")) {
res.pop_back();
}
return res;
}
int32_t WUPSConfigItemButtonCombo_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
snprintf(out_buf, out_size, "%s", getComboAsString(item->value).c_str());
return 0;
}
bool WUPSConfigItemButtonCombo_callCallback(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->callback != nullptr) {
((ButtonComboValueChangedCallback) (item->callback))(item, item->value);
return true;
}
return false;
}
void checkForHold(ConfigItemButtonCombo *item) {
uint32_t lastHold = 0;
uint32_t holdFor = 0;
uint32_t holdForTarget = item->holdDurationInMs >> 4;
uint32_t holdAbortTarget = item->abortButtonHoldDurationInMs >> 4;
auto mask = VPAD_BUTTON_A | VPAD_BUTTON_B | VPAD_BUTTON_X | VPAD_BUTTON_Y | VPAD_BUTTON_L | VPAD_BUTTON_R |
VPAD_BUTTON_ZL | VPAD_BUTTON_ZR | VPAD_BUTTON_UP | VPAD_BUTTON_DOWN | VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT |
VPAD_BUTTON_STICK_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_PLUS | VPAD_BUTTON_MINUS | VPAD_BUTTON_TV | VPAD_BUTTON_RESERVED_BIT;
KPADStatus kpad_data{};
KPADError kpad_error;
while (true) {
uint32_t buttonsHold = 0;
VPADReadError vpad_error = VPAD_READ_UNINITIALIZED;
VPADStatus vpad_data;
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
if (vpad_error == VPAD_READ_SUCCESS) {
buttonsHold = vpad_data.hold;
}
for (int i = 0; i < 4; i++) {
memset(&kpad_data, 0, sizeof(kpad_data));
if (KPADReadEx((KPADChan) i, &kpad_data, 1, &kpad_error) > 0) {
if (kpad_error == KPAD_ERROR_OK && kpad_data.extensionType != 0xFF) {
if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) {
buttonsHold |= remapWiiMoteButtons(kpad_data.hold);
} else if (kpad_data.extensionType == WPAD_EXT_PRO_CONTROLLER) {
buttonsHold |= remapProButtons(kpad_data.pro.hold);
} else {
buttonsHold |= remapClassicButtons(kpad_data.classic.hold);
}
}
}
}
buttonsHold &= mask;
if (buttonsHold == lastHold) {
if (buttonsHold != 0) {
holdFor++;
}
} else {
holdFor = 0;
}
lastHold = buttonsHold;
if (holdFor >= holdAbortTarget && lastHold == item->abortButton) {
break;
}
if (holdFor >= holdForTarget) {
item->value = lastHold;
break;
}
OSSleepTicks(OSMillisecondsToTicks(16));
}
}
void WUPSConfigItemButtonCombo_onButtonPressed(void *context, WUPSConfigButtons buttons) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_NONE) {
if ((buttons & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) {
item->state = BUTTON_COMBO_STATE_PREPARE_FOR_HOLD;
}
}
}
bool WUPSConfigItemButtonCombo_isMovementAllowed(void *context) {
return true;
}
int32_t WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD || item->state == BUTTON_COMBO_STATE_WAIT_FOR_HOLD) {
if (item->state == BUTTON_COMBO_STATE_PREPARE_FOR_HOLD) {
item->state = BUTTON_COMBO_STATE_WAIT_FOR_HOLD;
snprintf(out_buf, out_size, "<Hold new combo for %dms; hold %s to abort>", item->holdDurationInMs, getButtonChar(item->abortButton));
return 0;
} else {
checkForHold(item);
item->state = BUTTON_COMBO_STATE_NONE;
}
}
snprintf(out_buf, out_size, "(Press \ue000 to change) %s", getComboAsString(item->value).c_str());
return 0;
}
void WUPSConfigItemButtonCombo_restoreDefault(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
item->value = item->defaultValue;
}
void WUPSConfigItemButtonCombo_onSelected(void *context, bool isSelected) {
}
void WUPSConfigItemButtonCombo_onDelete(void *context) {
auto *item = (ConfigItemButtonCombo *) context;
if (item->configId) {
free(item->configId);
}
free(item);
}
extern "C" bool
WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback) {
if (cat == 0) {
return false;
}
auto *item = (ConfigItemButtonCombo *) malloc(sizeof(ConfigItemButtonCombo));
if (item == nullptr) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to allocate memory for item data.\n");
return false;
}
if (configID != nullptr) {
item->configId = strdup(configID);
} else {
item->configId = nullptr;
}
item->abortButton = abortButton;
item->abortButtonHoldDurationInMs = abortButtonHoldDurationInMs;
item->holdDurationInMs = holdDurationInMs;
item->defaultValue = defaultComboInVPADButtons;
item->value = defaultComboInVPADButtons;
item->callback = (void *) callback;
item->state = BUTTON_COMBO_STATE_NONE;
WUPSConfigCallbacks_t callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemButtonCombo_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemButtonCombo_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemButtonCombo_onSelected,
.restoreDefault = &WUPSConfigItemButtonCombo_restoreDefault,
.isMovementAllowed = &WUPSConfigItemButtonCombo_isMovementAllowed,
.callCallback = &WUPSConfigItemButtonCombo_callCallback,
.onButtonPressed = &WUPSConfigItemButtonCombo_onButtonPressed,
.onDelete = &WUPSConfigItemButtonCombo_onDelete};
if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to create config item.\n");
free(item);
return false;
}
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
OSReport("WUPSConfigItemButtonComboAddToCategoryEx: Failed to add item to category.\n");
WUPSConfigItem_Destroy(item->handle);
return false;
}
return true;
}
extern "C" bool
WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback) {
return WUPSConfigItemButtonComboAddToCategoryEx(cat, configID, displayName, defaultComboInVPADButtons, 2000, VPAD_BUTTON_B, 250, callback);
}

View File

@ -0,0 +1,43 @@
#include <stdint.h>
#include <vpad/input.h>
#include <wups.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum ButtonComboState {
BUTTON_COMBO_STATE_NONE,
BUTTON_COMBO_STATE_PREPARE_FOR_HOLD,
BUTTON_COMBO_STATE_WAIT_FOR_HOLD,
} ButtonComboState;
typedef struct ConfigItemButtonCombo {
char *configId;
WUPSConfigItemHandle handle;
uint32_t defaultValue;
uint32_t value;
uint32_t holdDurationInMs;
VPADButtons abortButton;
uint32_t abortButtonHoldDurationInMs;
void *callback;
ButtonComboState state;
} ConfigItemButtonCombo;
typedef void (*ButtonComboValueChangedCallback)(ConfigItemButtonCombo *item, uint32_t buttonComboInVPADButtons);
bool WUPSConfigItemButtonComboAddToCategory(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, ButtonComboValueChangedCallback callback);
bool WUPSConfigItemButtonComboAddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configId, const char *displayName, uint32_t defaultComboInVPADButtons, uint32_t holdDurationInMs, VPADButtons abortButton, uint32_t abortButtonHoldDurationInMs, ButtonComboValueChangedCallback callback);
#define WUPSConfigItemButtonCombo_AddToCategoryHandled(__config__, __cat__, __configID__, __displayName__, __defaultComboInVPADButtons__, __callback__) \
do { \
if (!WUPSConfigItemButtonComboAddToCategory(__cat__, __configID__, __displayName__, __defaultComboInVPADButtons__, __callback__)) { \
WUPSConfig_Destroy(__config__); \
return 0; \
} \
} while (0)
#ifdef __cplusplus
}
#endif

104
src/utils/config.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "config.h"
#include "WUPSConfigItemButtonCombo.h"
#include "retain_vars.hpp"
#include <map>
#include <wups/config/WUPSConfigItemMultipleValues.h>
extern void UpdateAudioMode();
void boolItemChangedConfig(ConfigItemBoolean *item, bool newValue) {
if (std::string_view(item->configId) == ENABLED_CONFIG_STRING) {
DEBUG_FUNCTION_LINE("New value in %s: %d", ENABLED_CONFIG_STRING, newValue);
gEnabled = newValue;
WUPS_StoreInt(nullptr, ENABLED_CONFIG_STRING, gEnabled);
UpdateAudioMode();
return;
}
PROCESS_BOOL_ITEM_CHANGED(SWAP_SCREENS_CONFIG_STRING, gDoScreenSwap);
PROCESS_BOOL_ITEM_CHANGED(ENABLED_SWAP_SCREENS_COMBO_CONFIG_STRING, gSwapScreenButtonComboEnabled);
PROCESS_BOOL_ITEM_CHANGED(ENABLED_CHANGE_AUDIO_COMBO_CONFIG_STRING, gChangeAudioModeButtonComboEnabled);
PROCESS_BOOL_ITEM_CHANGED(ENABLE_NOTIFICATIONS_CONFIG_STRING, gShowNotifications);
}
void buttonComboItemChanged(ConfigItemButtonCombo *item, uint32_t newValue) {
if (item && item->configId) {
if (std::string_view(item->configId) == SWAP_SCREEN_BUTTON_COMBO_CONFIG_STRING) {
gSwapScreenButtonCombo = newValue;
WUPS_StoreInt(nullptr, item->configId, (int32_t) gSwapScreenButtonCombo);
} else if (std::string_view(item->configId) == CHANGE_AUDIO_BUTTON_COMBO_CONFIG_STRING) {
gSwapAudioButtonCombo = newValue;
WUPS_StoreInt(nullptr, item->configId, (int32_t) gSwapAudioButtonCombo);
}
}
}
void getConfigInfoForMap(std::map<SwipSwapAudioMode, const char *> &curMap, ConfigItemMultipleValuesPair *pair, uint32_t default_lang, uint32_t *default_index, uint32_t *len) {
uint32_t i = 0;
for (auto &curEntry : curMap) {
if (default_lang == curEntry.first) {
*default_index = i;
}
pair[i].value = curEntry.first;
pair[i].valueName = (char *) curEntry.second;
i++;
}
*len = i;
}
void default_lang_changed(ConfigItemMultipleValues *item, uint32_t newValue) {
DEBUG_FUNCTION_LINE("New value in %s changed: %d", item->configId, newValue);
if (strcmp(item->configId, SCREEN_MODE_CONFIG_STRING) == 0) {
gCurAudioMode = static_cast<SwipSwapAudioMode>(newValue);
WUPS_StoreInt(nullptr, item->configId, (int32_t) gCurAudioMode);
}
}
WUPS_GET_CONFIG() {
// We open the storage, so we can persist the configuration the user did.
if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to open storage");
return 0;
}
WUPSConfigHandle config;
WUPSConfig_CreateHandled(&config, "SwipSwapMe");
WUPSConfigCategoryHandle setting;
WUPSConfig_AddCategoryByNameHandled(config, "Settings", &setting);
WUPSConfigCategoryHandle combos;
WUPSConfig_AddCategoryByNameHandled(config, "Button combos", &combos);
std::map<SwipSwapAudioMode, const char *> audioModeMap{
{AUDIO_MODE_NONE, "Normal"},
{AUDIO_MODE_SWAP, "Swap TV and GamePad sound"},
{AUDIO_MODE_MATCH_SCREEN, "Sound matches screen"},
{AUDIO_MODE_COMBINE, "Combine TV and GamePad sound"},
{AUDIO_MODE_LEFT_TV_RIGHT_DRC, "Left: TV; Right: GamePad"}};
ConfigItemMultipleValuesPair audioModePairs[audioModeMap.size()];
uint32_t number_values = 0;
uint32_t default_index = 0;
getConfigInfoForMap(audioModeMap, audioModePairs, gCurAudioMode, &default_index, &number_values);
WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, ENABLED_CONFIG_STRING, "Plugin enabled", gEnabled, &boolItemChangedConfig);
WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, ENABLE_NOTIFICATIONS_CONFIG_STRING, "Show notifications", gShowNotifications, &boolItemChangedConfig);
WUPSConfigItemBoolean_AddToCategoryHandled(config, setting, SWAP_SCREENS_CONFIG_STRING, "Swap screens", gDoScreenSwap, &boolItemChangedConfig);
WUPSConfigItemMultipleValues_AddToCategoryHandled(config, setting, SCREEN_MODE_CONFIG_STRING, "Audio mode:", default_index, audioModePairs, number_values,
&default_lang_changed);
WUPSConfigItemBoolean_AddToCategoryHandled(config, combos, ENABLED_SWAP_SCREENS_COMBO_CONFIG_STRING, "Enable swap screen button combo", gSwapScreenButtonComboEnabled, &boolItemChangedConfig);
WUPSConfigItemButtonCombo_AddToCategoryHandled(config, combos, SWAP_SCREEN_BUTTON_COMBO_CONFIG_STRING, "Swap screen", gSwapScreenButtonCombo, &buttonComboItemChanged);
WUPSConfigItemBoolean_AddToCategoryHandled(config, combos, ENABLED_CHANGE_AUDIO_COMBO_CONFIG_STRING, "Enable change audio mode button combo", gChangeAudioModeButtonComboEnabled, &boolItemChangedConfig);
WUPSConfigItemButtonCombo_AddToCategoryHandled(config, combos, CHANGE_AUDIO_BUTTON_COMBO_CONFIG_STRING, "Change audio", gSwapAudioButtonCombo, &buttonComboItemChanged);
return config;
}
WUPS_CONFIG_CLOSED() {
// Save all changes
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to close storage");
}
}

53
src/utils/config.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include "logger.h"
#include <string>
#include <wups/config/WUPSConfigItemBoolean.h>
#include <wups/storage.h>
#define ENABLED_CONFIG_STRING "enabled"
#define SWAP_SCREENS_CONFIG_STRING "swapScreens"
#define ENABLED_SWAP_SCREENS_COMBO_CONFIG_STRING "swapScreensComboEnabled"
#define ENABLED_CHANGE_AUDIO_COMBO_CONFIG_STRING "changeAudioComboEnabled"
#define ENABLE_NOTIFICATIONS_CONFIG_STRING "notificationsEnabled"
#define SWAP_SCREEN_BUTTON_COMBO_CONFIG_STRING "screenButtonCombo"
#define CHANGE_AUDIO_BUTTON_COMBO_CONFIG_STRING "audioButtonCombo"
#define SCREEN_MODE_CONFIG_STRING "audioMode"
#define LOAD_BOOL_FROM_STORAGE(config_name, __variable__) \
if ((storageRes = WUPS_GetBool(nullptr, config_name, &__variable__)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
if (WUPS_StoreBool(nullptr, config_name, __variable__) != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to store bool"); \
} \
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
} \
while (0)
#define LOAD_STRING_FROM_STORAGE(config_name, __string, __string_length) \
if ((storageRes = WUPS_GetString(nullptr, config_name, __string, __string_length)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
if (WUPS_StoreString(nullptr, config_name, __string) != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to store string"); \
} \
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
} \
while (0)
#define LOAD_INT_FROM_STORAGE(config_name, __intValue) \
if ((storageRes = WUPS_GetInt(nullptr, config_name, (int32_t *) &__intValue)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
if (WUPS_StoreInt(nullptr, config_name, (int32_t) __intValue) != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to store int"); \
} \
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
DEBUG_FUNCTION_LINE_WARN("Failed to get int %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
} \
while (0)
#define PROCESS_BOOL_ITEM_CHANGED(__config__name, __variable__) \
if (std::string_view(item->configId) == __config__name) { \
DEBUG_FUNCTION_LINE_ERR("New value in %s: %d", __config__name, newValue); \
__variable__ = newValue; \
WUPS_StoreInt(nullptr, __config__name, __variable__); \
return; \
} \
while (0)

187
src/utils/input.cpp Normal file
View File

@ -0,0 +1,187 @@
#include "input.h"
uint32_t remapWiiMoteButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_BUTTON_LEFT) {
conv_buttons |= VPAD_BUTTON_LEFT;
}
if (buttons & WPAD_BUTTON_RIGHT) {
conv_buttons |= VPAD_BUTTON_RIGHT;
}
if (buttons & WPAD_BUTTON_DOWN) {
conv_buttons |= VPAD_BUTTON_DOWN;
}
if (buttons & WPAD_BUTTON_UP) {
conv_buttons |= VPAD_BUTTON_UP;
}
if (buttons & WPAD_BUTTON_PLUS) {
conv_buttons |= VPAD_BUTTON_PLUS;
}
if (buttons & WPAD_BUTTON_B) {
conv_buttons |= VPAD_BUTTON_B;
}
if (buttons & WPAD_BUTTON_A) {
conv_buttons |= VPAD_BUTTON_A;
}
if (buttons & WPAD_BUTTON_MINUS) {
conv_buttons |= VPAD_BUTTON_MINUS;
}
if (buttons & WPAD_BUTTON_HOME) {
conv_buttons |= VPAD_BUTTON_HOME;
}
return conv_buttons;
}
uint32_t remapClassicButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_CLASSIC_BUTTON_LEFT) {
conv_buttons |= VPAD_BUTTON_LEFT;
}
if (buttons & WPAD_CLASSIC_BUTTON_RIGHT) {
conv_buttons |= VPAD_BUTTON_RIGHT;
}
if (buttons & WPAD_CLASSIC_BUTTON_DOWN) {
conv_buttons |= VPAD_BUTTON_DOWN;
}
if (buttons & WPAD_CLASSIC_BUTTON_UP) {
conv_buttons |= VPAD_BUTTON_UP;
}
if (buttons & WPAD_CLASSIC_BUTTON_PLUS) {
conv_buttons |= VPAD_BUTTON_PLUS;
}
if (buttons & WPAD_CLASSIC_BUTTON_X) {
conv_buttons |= VPAD_BUTTON_X;
}
if (buttons & WPAD_CLASSIC_BUTTON_Y) {
conv_buttons |= VPAD_BUTTON_Y;
}
if (buttons & WPAD_CLASSIC_BUTTON_B) {
conv_buttons |= VPAD_BUTTON_B;
}
if (buttons & WPAD_CLASSIC_BUTTON_A) {
conv_buttons |= VPAD_BUTTON_A;
}
if (buttons & WPAD_CLASSIC_BUTTON_MINUS) {
conv_buttons |= VPAD_BUTTON_MINUS;
}
if (buttons & WPAD_CLASSIC_BUTTON_HOME) {
conv_buttons |= VPAD_BUTTON_HOME;
}
if (buttons & WPAD_CLASSIC_BUTTON_ZR) {
conv_buttons |= VPAD_BUTTON_ZR;
}
if (buttons & WPAD_CLASSIC_BUTTON_ZL) {
conv_buttons |= VPAD_BUTTON_ZL;
}
if (buttons & WPAD_CLASSIC_BUTTON_R) {
conv_buttons |= VPAD_BUTTON_R;
}
if (buttons & WPAD_CLASSIC_BUTTON_L) {
conv_buttons |= VPAD_BUTTON_L;
}
return conv_buttons;
}
uint32_t remapProButtons(uint32_t buttons) {
uint32_t conv_buttons = 0;
if (buttons & WPAD_PRO_BUTTON_LEFT) {
conv_buttons |= VPAD_BUTTON_LEFT;
}
if (buttons & WPAD_PRO_BUTTON_RIGHT) {
conv_buttons |= VPAD_BUTTON_RIGHT;
}
if (buttons & WPAD_PRO_BUTTON_DOWN) {
conv_buttons |= VPAD_BUTTON_DOWN;
}
if (buttons & WPAD_PRO_BUTTON_UP) {
conv_buttons |= VPAD_BUTTON_UP;
}
if (buttons & WPAD_PRO_BUTTON_PLUS) {
conv_buttons |= VPAD_BUTTON_PLUS;
}
if (buttons & WPAD_PRO_BUTTON_X) {
conv_buttons |= VPAD_BUTTON_X;
}
if (buttons & WPAD_PRO_BUTTON_Y) {
conv_buttons |= VPAD_BUTTON_Y;
}
if (buttons & WPAD_PRO_BUTTON_B) {
conv_buttons |= VPAD_BUTTON_B;
}
if (buttons & WPAD_PRO_BUTTON_A) {
conv_buttons |= VPAD_BUTTON_A;
}
if (buttons & WPAD_PRO_BUTTON_MINUS) {
conv_buttons |= VPAD_BUTTON_MINUS;
}
if (buttons & WPAD_PRO_BUTTON_HOME) {
conv_buttons |= VPAD_BUTTON_HOME;
}
if (buttons & WPAD_PRO_TRIGGER_ZR) {
conv_buttons |= VPAD_BUTTON_ZR;
}
if (buttons & WPAD_PRO_TRIGGER_ZL) {
conv_buttons |= VPAD_BUTTON_ZL;
}
if (buttons & WPAD_PRO_TRIGGER_R) {
conv_buttons |= VPAD_BUTTON_R;
}
if (buttons & WPAD_PRO_TRIGGER_L) {
conv_buttons |= VPAD_BUTTON_L;
}
if (buttons & WPAD_PRO_BUTTON_STICK_L) {
conv_buttons |= VPAD_BUTTON_STICK_L;
}
if (buttons & WPAD_PRO_BUTTON_STICK_R) {
conv_buttons |= VPAD_BUTTON_STICK_R;
}
if (buttons & WPAD_PRO_RESERVED) {
conv_buttons |= VPAD_BUTTON_RESERVED_BIT;
}
return conv_buttons;
}
bool checkButtonComboVPAD(VPADStatus *buffer, uint32_t buffer_size, uint32_t buttonCombo, uint32_t &wasHoldForXFrames) {
bool result = false;
bool wasPressed = false;
for (uint32_t i = 0; i < buffer_size; i++) {
if ((((buffer[i].hold & 0x000FFFFF) & buttonCombo) == buttonCombo)) {
wasPressed = true;
break;
}
}
if (wasPressed) {
if (wasHoldForXFrames == 0) {
result = true;
}
wasHoldForXFrames++;
} else {
wasHoldForXFrames = 0;
}
return result;
}
bool checkButtonComboWPAD(uint32_t buttonHold, uint32_t buttonCombo, uint32_t &wasHoldForXFrames) {
auto result = false;
if (((buttonHold & 0x000FFFFF) & buttonCombo) == buttonCombo) {
if (wasHoldForXFrames == 0) {
result = true;
}
wasHoldForXFrames++;
} else {
wasHoldForXFrames = 0;
}
return result;
}

14
src/utils/input.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include <padscore/kpad.h>
#include <vpad/input.h>
#define VPAD_BUTTON_RESERVED_BIT 0x80000
uint32_t remapWiiMoteButtons(uint32_t buttons);
uint32_t remapClassicButtons(uint32_t buttons);
uint32_t remapProButtons(uint32_t buttons);
bool checkButtonComboVPAD(VPADStatus *buffer, uint32_t buffer_size, uint32_t buttonCombo, uint32_t &wasHoldForXFrames);
bool checkButtonComboWPAD(uint32_t vpadButtonHold, uint32_t vpadButtonCombo, uint32_t &wasHoldForXFrames);

36
src/utils/logger.c Normal file
View File

@ -0,0 +1,36 @@
#ifdef DEBUG
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
void initLogging() {
#ifdef DEBUG
if (!(moduleLogInit = WHBLogModuleInit())) {
cafeLogInit = WHBLogCafeInit();
udpLogInit = WHBLogUdpInit();
}
#endif // DEBUG
}
void deinitLogging() {
#ifdef DEBUG
if (moduleLogInit) {
WHBLogModuleDeinit();
moduleLogInit = false;
}
if (cafeLogInit) {
WHBLogCafeDeinit();
cafeLogInit = false;
}
if (udpLogInit) {
WHBLogUdpDeinit();
udpLogInit = false;
}
#endif // DEBUG
}

68
src/utils/logger.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_APP_TYPE "P"
#define LOG_APP_NAME "SwipSwapMe"
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
do { \
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
} while (0)
#ifdef DEBUG
#ifdef VERBOSE_DEBUG
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#endif
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
#else
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus
}
#endif

12
src/utils/utils.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <coreinit/dynload.h>
inline bool isModuleLoaded(const char *name) {
OSDynLoad_Module module;
auto err = OSDynLoad_IsModuleLoaded(name, &module);
if (err != OS_DYNLOAD_OK || !module) {
return false;
}
return true;
}

View File

@ -1,30 +0,0 @@
/****************************************************************************
* Copyright (C) 2017,2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _VOICE_INFO_H_
#define _VOICE_INFO_H_
#define VOICE_INFO_MAX 100
#include <stdint.h>
typedef struct _VoiceInfo {
void* voice; /**< Pointer to the voice */
uint32_t mixTV[24]; /**< Mix to the TV */
uint32_t mixDRC[24]; /**< Mix of the DRC */
} VoiceInfo;
#endif //_VOICE_INFO_H_

View File

@ -1,65 +0,0 @@
/****************************************************************************
* Copyright (C) 2017,2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <utils/logger.h>
#include "voice_info.h"
#include "voice_swapper.h"
void VoiceSwapper_acquireVoice(void * voice){
for(int32_t i = 0;i<VOICE_INFO_MAX;i++){
if(gVoiceInfos[i].voice == NULL){
if(VOICE_SWAP_LOG == 1){log_printf("[VoiceSwapper] acquireVoice in slot %d for %08X!\n",i,voice);}
gVoiceInfos[i].voice = voice;
break;
}
}
}
void VoiceSwapper_freeVoice(void * voice){
for(int32_t i = 0;i<VOICE_INFO_MAX;i++){
if(gVoiceInfos[i].voice == voice){
if(VOICE_SWAP_LOG == 1){log_printf("[VoiceSwapper] freeVoice in slot %d for %08X!\n",i,voice);}
gVoiceInfos[i].voice = NULL;
break;
}
}
}
void VoiceSwapper_setMix(void * voice,uint32_t device, void* mix){
for(int32_t i = 0;i<VOICE_INFO_MAX;i++){
if(gVoiceInfos[i].voice == voice){
if(VOICE_SWAP_LOG == 1){log_printf("[VoiceSwapper] setMix in slot %d for %08X!\n",i,voice);}
if(device == 0){
memcpy(gVoiceInfos[i].mixTV,mix,sizeof(gVoiceInfos[i].mixTV));
}else if(device == 1){
memcpy(gVoiceInfos[i].mixDRC,mix,sizeof(gVoiceInfos[i].mixDRC));
}
break;
}
}
}
void VoiceSwapper_swapAll(){
for(int32_t i = 0;i<VOICE_INFO_MAX;i++){
if(gVoiceInfos[i].voice == NULL) continue;
if(VOICE_SWAP_LOG == 1){log_printf("[VoiceSwapper] swapping slot %d, voice %08X!\n",i,gVoiceInfos[i].voice);}
uint32_t buffer[24];
memcpy(buffer,gVoiceInfos[i].mixTV,sizeof(gVoiceInfos[i].mixTV));
memcpy(gVoiceInfos[i].mixTV,gVoiceInfos[i].mixDRC,sizeof(gVoiceInfos[i].mixTV));
memcpy(gVoiceInfos[i].mixDRC,buffer,sizeof(gVoiceInfos[i].mixTV));
}
}

View File

@ -1,34 +0,0 @@
/****************************************************************************
* Copyright (C) 2017,2018 Maschell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef _VOICE_SWAPPER_H_
#define _VOICE_SWAPPER_H_
#define VOICE_SWAP_LOG 0
#include "voice_info.h"
#include "common/c_retain_vars.h"
#include <stdio.h>
#include <string.h>
void VoiceSwapper_acquireVoice(void * voice);
void VoiceSwapper_freeVoice(void * voice);
void VoiceSwapper_setMix(void * voice,uint32_t device, void* mix);
void VoiceSwapper_swapAll();
#endif //_VOICE_SWAPPER_H_

2
src/version.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#define PLUGIN_VERSION_EXTRA ""