From 567e286b6ece5a4886914f9cc90efd0dc5c5d130 Mon Sep 17 00:00:00 2001 From: Maschell Date: Thu, 16 Feb 2023 10:52:22 +0100 Subject: [PATCH] Port plugin to Aroma --- .clang-format | 67 +++++ .github/workflows/ci.yml | 59 ++++ .github/workflows/pr.yml | 32 ++ .gitignore | 7 +- .travis.yml | 31 -- Dockerfile | 7 +- Makefile | 357 +++++++--------------- README.md | 79 +++-- makefile.mk | 66 ----- src/common/c_retain_vars.cpp | 24 -- src/common/c_retain_vars.h | 27 -- src/function_patcher.cpp | 377 ++++++++++++++++++------ src/main.cpp | 196 +++++------- src/main.h | 5 + src/retain_vars.cpp | 12 + src/retain_vars.hpp | 22 ++ src/utils/WUPSConfigItemButtonCombo.cpp | 265 +++++++++++++++++ src/utils/WUPSConfigItemButtonCombo.h | 43 +++ src/utils/config.cpp | 104 +++++++ src/utils/config.h | 53 ++++ src/utils/input.cpp | 187 ++++++++++++ src/utils/input.h | 14 + src/utils/logger.c | 36 +++ src/utils/logger.h | 68 +++++ src/utils/utils.h | 12 + src/utils/voice_info.h | 30 -- src/utils/voice_swapper.cpp | 65 ---- src/utils/voice_swapper.h | 34 --- src/version.h | 2 + 29 files changed, 1516 insertions(+), 765 deletions(-) create mode 100644 .clang-format create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/pr.yml delete mode 100644 .travis.yml delete mode 100644 makefile.mk delete mode 100644 src/common/c_retain_vars.cpp delete mode 100644 src/common/c_retain_vars.h create mode 100644 src/main.h create mode 100644 src/retain_vars.cpp create mode 100644 src/retain_vars.hpp create mode 100644 src/utils/WUPSConfigItemButtonCombo.cpp create mode 100644 src/utils/WUPSConfigItemButtonCombo.h create mode 100644 src/utils/config.cpp create mode 100644 src/utils/config.h create mode 100644 src/utils/input.cpp create mode 100644 src/utils/input.h create mode 100644 src/utils/logger.c create mode 100644 src/utils/logger.h create mode 100644 src/utils/utils.h delete mode 100644 src/utils/voice_info.h delete mode 100644 src/utils/voice_swapper.cpp delete mode 100644 src/utils/voice_swapper.h create mode 100644 src/version.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..56cc685 --- /dev/null +++ b/.clang-format @@ -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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5bdd642 --- /dev/null +++ b/.github/workflows/ci.yml @@ -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 < ./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 \ No newline at end of file diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..4026eba --- /dev/null +++ b/.github/workflows/pr.yml @@ -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 < ./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" \ No newline at end of file diff --git a/.gitignore b/.gitignore index fb82516..014c4a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ build/* -*.mod \ No newline at end of file +*.mod +cmake-build-debug/ +.idea/ +*.wps +*.elf +CMakeLists.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 88f09d3..0000000 --- a/.travis.yml +++ /dev/null @@ -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 diff --git a/Dockerfile b/Dockerfile index bb39974..b4572b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ -FROM wups/core-with-wut:0.1 +FROM wiiuenv/devkitppc:20221228 -# Get dependencies -COPY --from=wiiuwut/libutils:0.1 /artifacts $WUT_ROOT +COPY --from=wiiuenv/wiiupluginsystem:20230215 /artifacts $DEVKITPRO +COPY --from=wiiuenv/libnotifications:20230126 /artifacts $DEVKITPRO +COPY --from=wiiuenv/libmappedmemory:20220904 /artifacts $DEVKITPRO WORKDIR project diff --git a/Makefile b/Makefile index dd480be..902a4d4 100644 --- a/Makefile +++ b/Makefile @@ -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: -#--------------------------------------------------------------------------------- -ifeq ($(strip $(DEVKITPPC)),) -$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") -endif +#------------------------------------------------------------------------------- + ifeq ($(strip $(DEVKITPRO)),) -$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") endif -export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) -export PORTLIBS := $(DEVKITPRO)/portlibs/ppc -export WUPSDIR := $(DEVKITPRO)/wups -export GCC_VER := $(shell $(DEVKITPPC)/bin/powerpc-eabi-gcc -dumpversion) +TOPDIR ?= $(CURDIR) -PREFIX := powerpc-eabi- +include $(DEVKITPRO)/wups/share/wups_rules -export AS := $(PREFIX)as -export CC := $(PREFIX)gcc -export CXX := $(PREFIX)g++ -export LD := $(PREFIX)ld -export AR := $(PREFIX)ar -export OBJCOPY := $(PREFIX)objcopy +WUT_ROOT := $(DEVKITPRO)/wut +WUMS_ROOT := $(DEVKITPRO)/wums -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed # SOURCES is a list of directories containing source code -# INCLUDES is a list of directories containing extra header files -#--------------------------------------------------------------------------------- -TARGET := $(notdir $(CURDIR)) -BUILD := build +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#------------------------------------------------------------------------------- +TARGET := swipswapme +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 -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- +CFLAGS := -Wall -O2 -ffunction-sections \ + $(MACHDEP) -# -Os: optimise size -# -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) +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ -# -x c: compile as c code -# -std=c11: use the c11 standard -CFLAGS := $(COMMON_CFLAGS) -x c -std=gnu11 $(CFLAGS) +CXXFLAGS := $(CFLAGS) -std=c++20 -fno-exceptions -fno-rtti -# -x c: compile as c++ code -# -std=gnu++11: use the c++11 standard -CXXFLAGS := $(COMMON_CFLAGS) -x c++ -std=gnu++11 $(CXXFLAGS) +ASFLAGS := -g $(ARCH) +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUPSSPECS) -ifeq ($(DO_LOGGING), 1) - CFLAGS += -D__LOGGING__ - CXXFLAGS += -D__LOGGING__ +ifeq ($(DEBUG),1) +CXXFLAGS += -DDEBUG -g +CFLAGS += -DDEBUG -g endif -#--------------------------------------------------------------------------------- -# any extra ld flags -#-------------------------------------------------------------------------------- -# --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 +ifeq ($(DEBUG),VERBOSE) +CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g +CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g endif -ifeq ($(WUT_ENABLE_NEWLIB), 1) - LDFLAGS += -Wl,-whole-archive,-lwutnewlib,-no-whole-archive - NEEDS_WUT := 1 -endif +LIBS := -lwups -lnotifications -lmappedmemory -lwut -ifeq ($(WUT_DEFAULT_MALLOC), 1) - LDFLAGS += -Wl,-whole-archive,-lwutmalloc,-no-whole-archive - NEEDS_WUT := 1 -endif +#------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level +# containing include and lib +#------------------------------------------------------------------------------- +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=wut) - endif - CFLAGS += -D__WUT__ - CXXFLAGS += -D__WUT__ -endif - -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- 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) -.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): - @[ -d $@ ] || mkdir -p $@ + @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD)) @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -#--------------------------------------------------------------------------------- + +#------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(OUTPUT).mod $(OUTPUT) + @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- else +.PHONY: all DEPENDS := $(OFILES:.o=.d) -THIS_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +#------------------------------------------------------------------------------- +# main targets +#------------------------------------------------------------------------------- +all : $(OUTPUT).wps -############################################################################### -# Rule to make everything. -PHONY += all +$(OUTPUT).wps : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) -all : $(OUTPUT) -############################################################################### -# Special build rules +$(OFILES_SRC) : $(HFILES_BIN) - -# Rule to make the module file. -$(OUTPUT) : $(OFILES) - @echo "linking ... " $@ - @$(REAL_LD) $(OFILES) $(LDFLAGS) $(LIBS) $(LIBPATHS_FULL) -o $@ - -############################################################################### -# Standard build rules -#--------------------------------------------------------------------------------- -%.a: -#--------------------------------------------------------------------------------- - @echo $(notdir $@) - @rm -f $@ - @$(AR) -rc $@ $^ - -#--------------------------------------------------------------------------------- -%.o: %.cpp +#------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#------------------------------------------------------------------------------- @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) -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- endif -#--------------------------------------------------------------------------------- +#------------------------------------------------------------------------------- diff --git a/README.md b/README.md index cb93546..755ec89 100644 --- a/README.md +++ b/README.md @@ -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 -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: +**When this plugin is enabled, the audio output of your Wii U is forced to stereo** -``` -sd:/wiiu/plugins -``` -When the file is placed on the SDCard you can load it with [plugin loader](https://github.com/Maschell/WiiUPluginSystem/). +## Installation -# 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. -Otherwise it will use the default settings (TV button). +1. Copy the file `swipswapme.wps` into `sd:/wiiu/environments/[ENVIRONMENT]/plugins`. +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 -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. +For building you need: -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. ``` @@ -38,4 +75,8 @@ docker run -it --rm -v ${PWD}:/project swipswapme-builder make # make clean docker run -it --rm -v ${PWD}:/project swipswapme-builder make clean -``` \ No newline at end of file +``` + +## Format the code via docker + +`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./src -i` diff --git a/makefile.mk b/makefile.mk deleted file mode 100644 index 8a6833b..0000000 --- a/makefile.mk +++ /dev/null @@ -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 diff --git a/src/common/c_retain_vars.cpp b/src/common/c_retain_vars.cpp deleted file mode 100644 index 721bae3..0000000 --- a/src/common/c_retain_vars.cpp +++ /dev/null @@ -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 . - ****************************************************************************/ -#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"))); diff --git a/src/common/c_retain_vars.h b/src/common/c_retain_vars.h deleted file mode 100644 index d954135..0000000 --- a/src/common/c_retain_vars.h +++ /dev/null @@ -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 . - ****************************************************************************/ -#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_ diff --git a/src/function_patcher.cpp b/src/function_patcher.cpp index 97cda30..d0d0b15 100644 --- a/src/function_patcher.cpp +++ b/src/function_patcher.cpp @@ -14,106 +14,315 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ -#include +#include "retain_vars.hpp" +#include "utils/input.h" +#include "utils/logger.h" +#include +#include #include +#include +#include +#include #include -#include +#include -#include "utils/voice_swapper.h" -#include "common/c_retain_vars.h" +void UpdateAudioMode(); -DECL_FUNCTION(int32_t, AXSetVoiceDeviceMixOld, void *v, int32_t device, uint32_t id, void *mix){ - if(gSwap){ device = !device;} - if(VOICE_SWAP_LOG == 1){log_printf("AXSetVoiceDeviceMixOld voice: %08X device: %d, mix: %08X\n",v,device,mix);} - VoiceSwapper_setMix(v,device,mix); - return real_AXSetVoiceDeviceMixOld(v,device,id,mix); -} +DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) { + if (gEnabled && gDoScreenSwap) { + if (scan_target == GX2_SCAN_TARGET_TV) { + scan_target = GX2_SCAN_TARGET_DRC; + } 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){ - if(gSwap){ device = !device;} - if(VOICE_SWAP_LOG == 1){log_printf("AXSetVoiceDeviceMix voice: %08X device: %d, mix: %08X\n",v,device,mix);} - VoiceSwapper_setMix(v,device,mix); - return real_AXSetVoiceDeviceMix(v,device,id,mix); -} + tempSurface.image = MEMAllocFromMappedMemoryForGX2Ex(tempSurface.imageSize, tempSurface.alignment); + if (tempSurface.image != nullptr) { + GX2ResolveAAColorBuffer(colorBuffer, &tempSurface, 0, 0); -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; -} + auto surfaceCpy = colorBuffer->surface; + colorBuffer->surface = tempSurface; + real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target); + colorBuffer->surface = surfaceCpy; -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{ - scan_target = 1; + if (tempSurface.image != nullptr) { + MEMFreeToMappedMemory(tempSurface.image); + tempSurface.image = nullptr; + } + return; + } else { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate %d bytes for resolving AA", tempSurface.imageSize); + } } } - real_GX2CopyColorBufferToScanBuffer(colorBuffer,scan_target); + + real_GX2CopyColorBufferToScanBuffer(colorBuffer, scan_target); } -/* -DECL(int32_t, AXSetDefaultMixerSelectOld, uint32_t s){ - int32_t result = real_AXSetDefaultMixerSelectOld(s); - return result; -}*/ +void SwapScreens() { + gDoScreenSwap = !gDoScreenSwap; - -void swapVoices(){ - VoiceSwapper_swapAll(); - for(int32_t i = 0;i 0 && *error == VPAD_READ_SUCCESS && ((buffer[0].hold & gButtonCombo) == gButtonCombo) && gCallbackCooldown == 0 ){ - gCallbackCooldown = 0x3C; - if(gAppStatus == WUPS_APP_STATUS_FOREGROUND){ - gSwap = !gSwap; - swapVoices(); + if (gShowNotifications && gNotificationModuleInitDone) { + if (gDoScreenSwap) { + NotificationModule_AddInfoNotification("Swapping TV and GamePad screen"); + } else { + NotificationModule_AddInfoNotification("Stop swapping TV and GamePad screen"); } } - if(gCallbackCooldown > 0) gCallbackCooldown--; +} +void SwapVoices(); +extern "C" uint32_t VPADGetButtonProcMode(VPADChan chan); + +static uint32_t sSwapScreenWasHoldForXFrameGamePad; +static uint32_t sSwapVoicesWasHoldForXFrameGamePad; +DECL_FUNCTION(int32_t, VPADRead, VPADChan chan, VPADStatus *buffer, uint32_t buffer_size, VPADReadError *error) { + VPADReadError real_error; + 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 (error) { + *error = real_error; + } 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"; +} -WUPS_MUST_REPLACE(GX2CopyColorBufferToScanBuffer, WUPS_LOADER_LIBRARY_GX2, GX2CopyColorBufferToScanBuffer); -WUPS_MUST_REPLACE(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead); -WUPS_MUST_REPLACE(AXAcquireVoiceExOld, WUPS_LOADER_LIBRARY_SND_CORE, AXAcquireVoiceEx); -WUPS_MUST_REPLACE(AXFreeVoiceOld, WUPS_LOADER_LIBRARY_SND_CORE, AXFreeVoice); -WUPS_MUST_REPLACE(AXSetVoiceDeviceMixOld, WUPS_LOADER_LIBRARY_SND_CORE, AXSetVoiceDeviceMix); -//WUPS_MUST_REPLACE(AXSetDefaultMixerSelectOld, , WUPS_LOADER_LIBRARY_SND_CORE, AXSetDefaultMixerSelect), -WUPS_MUST_REPLACE(AXAcquireVoiceEx, WUPS_LOADER_LIBRARY_SNDCORE2, AXAcquireVoiceEx); -WUPS_MUST_REPLACE(AXFreeVoice, WUPS_LOADER_LIBRARY_SNDCORE2, AXFreeVoice); -WUPS_MUST_REPLACE(AXSetVoiceDeviceMix, WUPS_LOADER_LIBRARY_SNDCORE2, AXSetVoiceDeviceMix); +void SwapVoices() { + auto val = (uint32_t) gCurAudioMode; + val++; + if (val >= AUDIO_MODE_MAX_VALUE) { + val = 0; + } + gCurAudioMode = static_cast(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(VPADRead, WUPS_LOADER_LIBRARY_VPAD, VPADRead); +WUPS_MUST_REPLACE(WPADRead, WUPS_LOADER_LIBRARY_PADSCORE, WPADRead); + +WUPS_MUST_REPLACE_FOR_PROCESS(AIInitDMA, WUPS_LOADER_LIBRARY_SND_CORE, AIInitDMA, WUPS_FP_TARGET_PROCESS_ALL); +WUPS_MUST_REPLACE_FOR_PROCESS(AI2InitDMA, WUPS_LOADER_LIBRARY_SND_CORE, AI2InitDMA, WUPS_FP_TARGET_PROCESS_ALL); +WUPS_MUST_REPLACE_FOR_PROCESS(AIInitDMA2, WUPS_LOADER_LIBRARY_SNDCORE2, AIInitDMA, WUPS_FP_TARGET_PROCESS_ALL); +WUPS_MUST_REPLACE_FOR_PROCESS(AI2InitDMA2, WUPS_LOADER_LIBRARY_SNDCORE2, AI2InitDMA, WUPS_FP_TARGET_PROCESS_ALL); + +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); diff --git a/src/main.cpp b/src/main.cpp index 63e8e0c..3cdcdb9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,141 +14,85 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ - -#include -#include -#include -#include +#include "main.h" +#include "retain_vars.hpp" +#include "utils/WUPSConfigItemButtonCombo.h" +#include "utils/config.h" +#include "utils/logger.h" +#include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include - +// Mandatory plugin information. WUPS_PLUGIN_NAME("SwipSwapMe"); -WUPS_PLUGIN_DESCRIPTION("Swaps the gamepad and tv screen when pressing a certain button (TV is default)"); -WUPS_PLUGIN_VERSION("v1.0"); +WUPS_PLUGIN_DESCRIPTION("Swaps the GamePad and TV screen when pressing a certain button combination"); +WUPS_PLUGIN_VERSION(PLUGIN_VERSION_FULL); WUPS_PLUGIN_AUTHOR("Maschell"); WUPS_PLUGIN_LICENSE("GPL"); -WUPS_FS_ACCESS() +// FS Access +WUPS_USE_WUT_DEVOPTAB(); -uint32_t SplashScreen(int32_t time,int32_t combotime); - -/* Entry point */ -ON_APPLICATION_START(args) { - memset(gVoiceInfos,0,sizeof(gVoiceInfos)); - socket_lib_init(); - log_init(); -} - -ON_APP_STATUS_CHANGED(status) { - gAppStatus = status; -} +WUPS_USE_STORAGE("SwipSwapMeAroma"); +// Gets called once the loader exists. INITIALIZE_PLUGIN() { - uint32_t res = SplashScreen(10,2); - gButtonCombo = res; + initLogging(); + + if (NotificationModule_InitLibrary() == NOTIFICATION_MODULE_RESULT_SUCCESS) { + gNotificationModuleInitDone = true; + } else { + gNotificationModuleInitDone = false; + DEBUG_FUNCTION_LINE_ERR("Failed to init notification lib"); + } + + // Open storage to read values + 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"); + } + } + deinitLogging(); } -#define FPS 60 -uint32_t SplashScreen(int32_t time,int32_t combotime) { - 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 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::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= combotime*FPS) { - result = vpad_data.hold; - break; - } - i++; - OSSleepTicks(OSMicrosecondsToTicks(sleepingtime*1000)); - } - - if(screenbuffer0 != NULL) { - free(screenbuffer0); - } - if(screenbuffer1 != NULL) { - free(screenbuffer1); - } - - 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; + } +} \ No newline at end of file diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..20b0d0f --- /dev/null +++ b/src/main.h @@ -0,0 +1,5 @@ +#pragma once +#include "version.h" + +#define PLUGIN_VERSION "v0.1" +#define PLUGIN_VERSION_FULL PLUGIN_VERSION PLUGIN_VERSION_EXTRA diff --git a/src/retain_vars.cpp b/src/retain_vars.cpp new file mode 100644 index 0000000..bcbedbb --- /dev/null +++ b/src/retain_vars.cpp @@ -0,0 +1,12 @@ +#include "retain_vars.hpp" +#include + +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; \ No newline at end of file diff --git a/src/retain_vars.hpp b/src/retain_vars.hpp new file mode 100644 index 0000000..08f06c5 --- /dev/null +++ b/src/retain_vars.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +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; \ No newline at end of file diff --git a/src/utils/WUPSConfigItemButtonCombo.cpp b/src/utils/WUPSConfigItemButtonCombo.cpp new file mode 100644 index 0000000..a52cb63 --- /dev/null +++ b/src/utils/WUPSConfigItemButtonCombo.cpp @@ -0,0 +1,265 @@ +#include "WUPSConfigItemButtonCombo.h" +#include "utils/input.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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, "", 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); +} \ No newline at end of file diff --git a/src/utils/WUPSConfigItemButtonCombo.h b/src/utils/WUPSConfigItemButtonCombo.h new file mode 100644 index 0000000..80c90fb --- /dev/null +++ b/src/utils/WUPSConfigItemButtonCombo.h @@ -0,0 +1,43 @@ +#include +#include +#include + +#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 \ No newline at end of file diff --git a/src/utils/config.cpp b/src/utils/config.cpp new file mode 100644 index 0000000..a80e066 --- /dev/null +++ b/src/utils/config.cpp @@ -0,0 +1,104 @@ +#include "config.h" +#include "WUPSConfigItemButtonCombo.h" +#include "retain_vars.hpp" +#include +#include +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 &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(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 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"); + } +} \ No newline at end of file diff --git a/src/utils/config.h b/src/utils/config.h new file mode 100644 index 0000000..13851df --- /dev/null +++ b/src/utils/config.h @@ -0,0 +1,53 @@ +#pragma once +#include "logger.h" +#include +#include +#include + +#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) diff --git a/src/utils/input.cpp b/src/utils/input.cpp new file mode 100644 index 0000000..6fb82b0 --- /dev/null +++ b/src/utils/input.cpp @@ -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; +} \ No newline at end of file diff --git a/src/utils/input.h b/src/utils/input.h new file mode 100644 index 0000000..0254da4 --- /dev/null +++ b/src/utils/input.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include + +#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); \ No newline at end of file diff --git a/src/utils/logger.c b/src/utils/logger.c new file mode 100644 index 0000000..f700806 --- /dev/null +++ b/src/utils/logger.c @@ -0,0 +1,36 @@ +#ifdef DEBUG +#include +#include +#include +#include + +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 +} \ No newline at end of file diff --git a/src/utils/logger.h b/src/utils/logger.h new file mode 100644 index 0000000..e1b18f6 --- /dev/null +++ b/src/utils/logger.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include + +#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 diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..69834a0 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,12 @@ +#pragma once +#include + +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; +} \ No newline at end of file diff --git a/src/utils/voice_info.h b/src/utils/voice_info.h deleted file mode 100644 index c1eb5f6..0000000 --- a/src/utils/voice_info.h +++ /dev/null @@ -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 . - ****************************************************************************/ -#ifndef _VOICE_INFO_H_ -#define _VOICE_INFO_H_ - -#define VOICE_INFO_MAX 100 - -#include - -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_ diff --git a/src/utils/voice_swapper.cpp b/src/utils/voice_swapper.cpp deleted file mode 100644 index 93d54f8..0000000 --- a/src/utils/voice_swapper.cpp +++ /dev/null @@ -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 . - ****************************************************************************/ - -#include -#include "voice_info.h" -#include "voice_swapper.h" - -void VoiceSwapper_acquireVoice(void * voice){ - for(int32_t i = 0;i. - ****************************************************************************/ -#ifndef _VOICE_SWAPPER_H_ -#define _VOICE_SWAPPER_H_ -#define VOICE_SWAP_LOG 0 -#include "voice_info.h" -#include "common/c_retain_vars.h" - -#include -#include - -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_ diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..d5abc29 --- /dev/null +++ b/src/version.h @@ -0,0 +1,2 @@ +#pragma once +#define PLUGIN_VERSION_EXTRA ""