mirror of
https://github.com/libretro/beetle-finalarcade2019.git
synced 2026-11-07 10:15:58 -10:00
(libretro) Add libretro files
This commit is contained in:
1 parent
085b393fea
commit
ba5b3770c5
354 files changed
+376823
-6084
No files matched your search
@@ -0,0 +1,648 @@
|
||||
DEBUG = 0
|
||||
DEBUG_ASAN = 0
|
||||
DEBUG_UBSAN = 0
|
||||
FRONTEND_SUPPORTS_RGB565 = 1
|
||||
HAVE_GRIFFIN = 0
|
||||
# fastcall only works on x86_32
|
||||
FASTCALL = 0
|
||||
# fastmath should improve performance with every arch, and there is no known issue with fbalpha
|
||||
FASTMATH = 1
|
||||
USE_SPEEDHACKS = 1
|
||||
EXTERNAL_ZLIB = 0
|
||||
INCLUDE_7Z_SUPPORT = 1
|
||||
PTR64 ?= 1
|
||||
INCLUDE_CPLUSPLUS11_FILES = 0
|
||||
BUILD_X64_EXE = 0
|
||||
AUTOGEN_DATS = 0
|
||||
HAVE_NEON = 0
|
||||
|
||||
SPACE :=
|
||||
SPACE := $(SPACE) $(SPACE)
|
||||
BACKSLASH :=
|
||||
BACKSLASH := \$(BACKSLASH)
|
||||
filter_out1 = $(filter-out $(firstword $1),$1)
|
||||
filter_out2 = $(call filter_out1,$(call filter_out1,$1))
|
||||
|
||||
# system platform
|
||||
ifeq ($(platform),)
|
||||
platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
platform = win
|
||||
EXE_EXT=.exe
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
platform = osx
|
||||
arch = intel
|
||||
ifeq ($(shell uname -p),powerpc)
|
||||
arch = ppc
|
||||
endif
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
platform = win
|
||||
EXE_EXT=.exe
|
||||
endif
|
||||
else ifneq (,$(findstring armv,$(platform)))
|
||||
ifeq (,$(findstring classic_,$(platform)))
|
||||
override platform += unix
|
||||
endif
|
||||
else ifneq (,$(findstring rpi,$(platform)))
|
||||
override platform += unix
|
||||
endif
|
||||
|
||||
MAIN_FBA_DIR := src
|
||||
VERSION_SCRIPT := $(MAIN_FBA_DIR)/burner/libretro/link.T
|
||||
|
||||
INLINE_LIMIT=-finline-limit=1200
|
||||
|
||||
# GCC < 4.9 and clang does not support -fno-tree-loop-vectorize
|
||||
ifeq ($(shell expr `gcc -dumpversion | cut -f1` \< 4.9), 1)
|
||||
INLINE_LIMIT=
|
||||
endif
|
||||
ifneq (, $(findstring clang,$(CC)))
|
||||
INLINE_LIMIT=
|
||||
endif
|
||||
ifneq (, $(findstring clang,$(CXX)))
|
||||
INLINE_LIMIT=
|
||||
endif
|
||||
|
||||
# TARGET
|
||||
TARGET_NAME := fbalpha
|
||||
|
||||
ifeq ($(PTR64), 1)
|
||||
FBA_DEFINES += -DPTR64
|
||||
endif
|
||||
|
||||
# Unix
|
||||
ifneq (,$(findstring unix,$(platform)))
|
||||
TARGET := $(TARGET_NAME)_libretro.so
|
||||
fpic := -fPIC
|
||||
SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(VERSION_SCRIPT)
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
|
||||
# Raspberry Pi
|
||||
ifneq (,$(findstring rpi2,$(platform)))
|
||||
PLATFORM_DEFINES := -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
|
||||
HAVE_NEON = 1
|
||||
else ifneq (,$(findstring rpi3,$(platform)))
|
||||
PLATFORM_DEFINES := -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
|
||||
HAVE_NEON = 1
|
||||
endif
|
||||
|
||||
# Solaris
|
||||
ifneq (,$(findstring solaris,$(platform)))
|
||||
CC := gcc
|
||||
SHARED := -shared
|
||||
endif
|
||||
|
||||
# Generic ARM
|
||||
ifneq (,$(findstring armv,$(platform)))
|
||||
PLATFORM_DEFINES :=
|
||||
ifneq (,$(findstring android,$(platform)))
|
||||
CC = arm-linux-androideabi-gcc
|
||||
CXX = arm-linux-androideabi-g++
|
||||
PLATFORM_DEFINES += -DANDROID -Dlog2\(x\)=\(log\(x\)/1.4426950408889634\)
|
||||
endif
|
||||
endif
|
||||
|
||||
# OS X
|
||||
else ifeq ($(platform), osx)
|
||||
TARGET := $(TARGET_NAME)_libretro.dylib
|
||||
fpic := -fPIC
|
||||
SHARED := -dynamiclib
|
||||
ifeq ($(arch),ppc)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
else
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
endif
|
||||
OSXVER = `sw_vers -productVersion | cut -d. -f 2`
|
||||
OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
|
||||
ifeq ($(OSX_LT_MAVERICKS),"YES")
|
||||
fpic += -mmacosx-version-min=10.5
|
||||
endif
|
||||
ifndef ($(NOUNIVERSAL))
|
||||
CFLAGS += $(ARCHFLAGS)
|
||||
CXXFLAGS += $(ARCHFLAGS)
|
||||
LDFLAGS += $(ARCHFLAGS)
|
||||
endif
|
||||
|
||||
# iOS
|
||||
else ifneq (,$(findstring ios,$(platform)))
|
||||
TARGET := $(TARGET_NAME)_libretro_ios.dylib
|
||||
fpic := -fPIC
|
||||
SHARED := -dynamiclib
|
||||
ifeq ($(IOSSDK),)
|
||||
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
|
||||
endif
|
||||
ifeq ($(platform),ios-arm64)
|
||||
CC = cc -arch arm64 -isysroot $(IOSSDK)
|
||||
CXX = c++ -arch arm64 -isysroot $(IOSSDK)
|
||||
else
|
||||
CC = cc -arch armv7 -isysroot $(IOSSDK)
|
||||
CXX = c++ -arch armv7 -isysroot $(IOSSDK)
|
||||
endif
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
ifeq ($(platform),$(filter $(platform),ios9 ios-arm64))
|
||||
CFLAGS += -DIOS9
|
||||
CXXFLAGS += -DIOS9
|
||||
CC += -miphoneos-version-min=8.0
|
||||
CXX += -miphoneos-version-min=8.0
|
||||
CFLAGS += -miphoneos-version-min=8.0
|
||||
else
|
||||
CFLAGS += -DIOS
|
||||
CXXFLAGS += -DIOS
|
||||
CC += -miphoneos-version-min=5.0
|
||||
CXX += -miphoneos-version-min=5.0
|
||||
CFLAGS += -miphoneos-version-min=5.0
|
||||
endif
|
||||
|
||||
# Theos iOS
|
||||
else ifeq ($(platform), theos_ios)
|
||||
DEPLOYMENT_IOSVERSION = 5.0
|
||||
TARGET = iphone:latest:$(DEPLOYMENT_IOSVERSION)
|
||||
ARCHS = armv7 armv7s
|
||||
TARGET_IPHONEOS_DEPLOYMENT_VERSION=$(DEPLOYMENT_IOSVERSION)
|
||||
THEOS_BUILD_DIR := objs
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
LIBRARY_NAME = $(TARGET_NAME)_libretro_ios
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
CFLAGS += -DIOS
|
||||
|
||||
# QNX
|
||||
else ifeq ($(platform), qnx)
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).so
|
||||
fpic := -fPIC
|
||||
SHARED := -lcpp -lm -shared -Wl,-no-undefined -Wl,--version-script=$(VERSION_SCRIPT)
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
CC = qcc -Vgcc_ntoarmv7le
|
||||
CXX = QCC -Vgcc_ntoarmv7le_cpp
|
||||
AR = qcc -Vgcc_ntoarmv7le
|
||||
PLATFORM_DEFINES := -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
|
||||
HAVE_NEON = 1
|
||||
|
||||
# PS3
|
||||
else ifneq (,$(filter $(platform), ps3 sncps3 psl1ght))
|
||||
TARGET := $(TARGET_NAME)_libretro_ps3.a
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES += -D__CELLOS_LV2__
|
||||
EXTERNAL_ZLIB = 1
|
||||
STATIC_LINKING = 1
|
||||
|
||||
# sncps3
|
||||
ifneq (,$(findstring sncps3,$(platform)))
|
||||
PLATFORM_DEFINES += -DSN_TARGET_PS3
|
||||
CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
|
||||
CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
|
||||
AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
|
||||
|
||||
# PS3
|
||||
else ifneq (,$(findstring ps3,$(platform)))
|
||||
CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
|
||||
CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe
|
||||
AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
|
||||
|
||||
# Lightweight PS3 Homebrew SDK
|
||||
else ifneq (,$(findstring psl1ght,$(platform)))
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
|
||||
CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT)
|
||||
AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
|
||||
endif
|
||||
|
||||
# Vita
|
||||
else ifeq ($(platform), vita)
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
CC = arm-vita-eabi-gcc$(EXE_EXT)
|
||||
CC_AS = arm-vita-eabi-gcc$(EXE_EXT)
|
||||
CXX = arm-vita-eabi-g++$(EXE_EXT)
|
||||
AR = arm-vita-eabi-ar$(EXE_EXT)
|
||||
PLATFORM_DEFINES += -DVITA
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
CFLAGS += -mfloat-abi=hard -fsingle-precision-constant
|
||||
CXXFLAGS += -mfloat-abi=hard -fsingle-precision-constant -fpermissive -fno-rtti -fno-exceptions
|
||||
EXTERNAL_ZLIB = 1
|
||||
STATIC_LINKING = 1
|
||||
|
||||
# Xbox 360
|
||||
else ifeq ($(platform), xenon)
|
||||
TARGET := $(TARGET_NAME)_libretro_xenon360.a
|
||||
CC = xenon-gcc$(EXE_EXT)
|
||||
CXX = xenon-g++$(EXE_EXT)
|
||||
AR = xenon-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES := -D__LIBXENON__ -m32 -D__ppc__
|
||||
STATIC_LINKING = 1
|
||||
|
||||
# Nintendo Switch (libtransistor)
|
||||
else ifeq ($(platform), switch)
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
include $(LIBTRANSISTOR_HOME)/libtransistor.mk
|
||||
STATIC_LINKING=1
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
PLATFORM_DEFINES := -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
|
||||
HAVE_NEON = 1
|
||||
|
||||
# Nintendo Switch (libnx)
|
||||
else ifeq ($(platform), libnx)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
EXT=a
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).$(EXT)
|
||||
DEFINES := -DSWITCH=1 -U__linux__ -U__linux -DRARCH_INTERNAL
|
||||
CFLAGS := $(DEFINES) -g \
|
||||
-O2 \
|
||||
-fPIE -I$(LIBNX)/include/ -ffunction-sections -fdata-sections -ftls-model=local-exec -Wl,--allow-multiple-definition -specs=$(LIBNX)/switch.specs
|
||||
CFLAGS += $(INCDIRS)
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -DHAVE_LIBNX
|
||||
CXXFLAGS := $(ASFLAGS) $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
CFLAGS += -std=gnu11
|
||||
STATIC_LINKING = 1
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
|
||||
# Classic Platforms ####################
|
||||
# Platform affix = classic_<ISA>_<µARCH>
|
||||
# Help at https://modmyclassic.com/comp
|
||||
|
||||
# (armv7 a7, hard point, neon based) ###
|
||||
# NESC, SNESC, C64 mini
|
||||
else ifeq ($(platform), classic_armv7_a7)
|
||||
TARGET := $(TARGET_NAME)_libretro.so
|
||||
fpic := -fPIC
|
||||
SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(VERSION_SCRIPT)
|
||||
CFLAGS += -Ofast \
|
||||
-flto=4 -fwhole-program -fuse-linker-plugin \
|
||||
-fdata-sections -ffunction-sections -Wl,--gc-sections \
|
||||
-fno-stack-protector -fno-ident -fomit-frame-pointer \
|
||||
-falign-functions=1 -falign-jumps=1 -falign-loops=1 \
|
||||
-fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \
|
||||
-fmerge-all-constants -fno-math-errno \
|
||||
-marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
CPPFLAGS += $(CFLAGS)
|
||||
ASFLAGS += $(CFLAGS)
|
||||
CXXFLAGS := -std=gnu++11
|
||||
CFLAGS := -std=gnu11
|
||||
HAVE_NEON = 1
|
||||
ARCH = arm
|
||||
BUILTIN_GPU = neon
|
||||
USE_DYNAREC = 1
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1)
|
||||
CFLAGS += -march=armv7-a
|
||||
else
|
||||
CFLAGS += -march=armv7ve
|
||||
# If gcc is 5.0 or later
|
||||
ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1)
|
||||
LDFLAGS += -static-libgcc -static-libstdc++
|
||||
endif
|
||||
endif
|
||||
#######################################
|
||||
|
||||
# Nintendo Game Cube / Wii / WiiU
|
||||
else ifneq (,$(filter $(platform), ngc wii wiiu))
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).a
|
||||
PATH := $(PATH):$(DEVKITPPC)/bin
|
||||
CC = powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = powerpc-eabi-g++$(EXE_EXT)
|
||||
AR = powerpc-eabi-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES := -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int -UPPC
|
||||
EXTERNAL_ZLIB = 1
|
||||
STATIC_LINKING = 1
|
||||
PTR64 = 0
|
||||
|
||||
# Nintendo WiiU
|
||||
ifneq (,$(findstring wiiu,$(platform)))
|
||||
PLATFORM_DEFINES += -DGEKKO -DWIIU -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float
|
||||
|
||||
# Nintendo Wii
|
||||
else ifneq (,$(findstring wii,$(platform)))
|
||||
PLATFORM_DEFINES += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float
|
||||
NO_MD = 1
|
||||
NO_CAPCOM = 1
|
||||
NO_NEOGEO = 1
|
||||
NO_PCE = 1
|
||||
|
||||
# Nintendo Game Cube
|
||||
else ifneq (,$(findstring ngc,$(platform)))
|
||||
PLATFORM_DEFINES += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float
|
||||
NO_MD = 1
|
||||
NO_CAPCOM = 1
|
||||
NO_NEOGEO = 1
|
||||
NO_PCE = 1
|
||||
endif
|
||||
|
||||
# Emscripten
|
||||
else ifeq ($(platform), emscripten)
|
||||
TARGET := $(TARGET_NAME)_libretro_$(platform).bc
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST -DNO_UNALIGNED_MEM
|
||||
|
||||
# Windows MSVC 2017 all architectures
|
||||
else ifneq (,$(findstring windows_msvc2017,$(platform)))
|
||||
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
|
||||
PlatformSuffix = $(subst windows_msvc2017_,,$(platform))
|
||||
ifneq (,$(findstring desktop,$(PlatformSuffix)))
|
||||
WinPartition = desktop
|
||||
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS -D_USE_MATH_DEFINES
|
||||
LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1
|
||||
LIBS := kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib
|
||||
else ifneq (,$(findstring uwp,$(PlatformSuffix)))
|
||||
WinPartition = uwp
|
||||
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WINDLL -D_UNICODE -DUNICODE -D__WRL_NO_DEFAULT_LIB__ -EHsc -FS -D_USE_MATH_DEFINES
|
||||
LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO
|
||||
LIBS := WindowsApp.lib
|
||||
endif
|
||||
|
||||
CFLAGS += $(MSVC2017CompileFlags)
|
||||
CXXFLAGS += $(MSVC2017CompileFlags)
|
||||
|
||||
TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix))
|
||||
|
||||
CC = cl.exe
|
||||
CXX = cl.exe
|
||||
LD = link.exe
|
||||
|
||||
reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul)))
|
||||
fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1))
|
||||
|
||||
ProgramFiles86w := $(shell cmd /c "echo %PROGRAMFILES(x86)%")
|
||||
ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)")
|
||||
|
||||
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
|
||||
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
|
||||
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
|
||||
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
|
||||
WindowsSdkDir := $(WindowsSdkDir)
|
||||
|
||||
WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH)
|
||||
WindowsSDKVersion := $(WindowsSDKVersion)
|
||||
|
||||
VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools
|
||||
VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise
|
||||
VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional
|
||||
VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community
|
||||
|
||||
VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi)
|
||||
ifeq ($(VsInstallRoot), )
|
||||
VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi)
|
||||
endif
|
||||
ifeq ($(VsInstallRoot), )
|
||||
VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi)
|
||||
endif
|
||||
ifeq ($(VsInstallRoot), )
|
||||
VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi)
|
||||
endif
|
||||
VsInstallRoot := $(VsInstallRoot)
|
||||
|
||||
VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*')
|
||||
VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer)
|
||||
|
||||
WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared")
|
||||
WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt")
|
||||
WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um")
|
||||
WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)")
|
||||
WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)")
|
||||
|
||||
# For some reason the HostX86 compiler doesn't like compiling for x64
|
||||
# ("no such file" opening a shared library), and vice-versa.
|
||||
# Work around it for now by using the strictly x86 compiler for x86, and x64 for x64.
|
||||
# NOTE: What about ARM?
|
||||
ifneq (,$(findstring x64,$(TargetArchMoniker)))
|
||||
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64
|
||||
else
|
||||
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86
|
||||
endif
|
||||
|
||||
PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH)
|
||||
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE")
|
||||
INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include")
|
||||
LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)")
|
||||
ifneq (,$(findstring uwp,$(PlatformSuffix)))
|
||||
LIB := $(shell IFS=$$'\n'; cygpath -w "$(LIB)/store")
|
||||
endif
|
||||
|
||||
export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir)
|
||||
export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir)
|
||||
TARGET := $(TARGET_NAME)_libretro.dll
|
||||
PSS_STYLE :=2
|
||||
LDFLAGS += -DLL
|
||||
|
||||
# Windows
|
||||
else
|
||||
TARGET := $(TARGET_NAME)_libretro.dll
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(VERSION_SCRIPT)
|
||||
LDFLAGS += -static-libgcc -static-libstdc++
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
|
||||
endif
|
||||
|
||||
CC_SYSTEM = gcc
|
||||
CXX_SYSTEM = g++
|
||||
|
||||
include Makefile.common
|
||||
|
||||
FBA_CXXOBJ := $(SOURCES_CXX:.cpp=.o)
|
||||
FBA_COBJ := $(SOURCES_C:.c=.o)
|
||||
FBA_SOBJ := $(SOURCES_S:.S=.o)
|
||||
|
||||
OBJS := $(FBA_COBJ) $(FBA_CXXOBJ) $(FBA_SOBJ)
|
||||
|
||||
FBA_DEFINES += -D__LIBRETRO__ \
|
||||
$(ENDIANNESS_DEFINES) \
|
||||
$(PLATFORM_DEFINES)
|
||||
|
||||
INCFLAGS := $(foreach dir,$(INCLUDE_DIRS),-I$(dir))
|
||||
|
||||
ifeq ($(USE_SPEEDHACKS), 1)
|
||||
FBA_DEFINES += -DUSE_SPEEDHACKS
|
||||
endif
|
||||
|
||||
ifeq ($(FASTCALL), 1)
|
||||
FBA_DEFINES += -DFASTCALL
|
||||
endif
|
||||
|
||||
ifeq ($(FASTMATH), 1)
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CFLAGS += -ffast-math
|
||||
CXXFLAGS += -ffast-math
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG_ASAN), 1)
|
||||
DEBUG = 1
|
||||
DEBUG_UBSAN = 0
|
||||
CFLAGS += -lasan -fsanitize=address
|
||||
CXXFLAGS += -lasan -fsanitize=address
|
||||
LDFLAGS += -lasan -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG_UBSAN), 1)
|
||||
DEBUG = 1
|
||||
CFLAGS += -lubsan -fsanitize=undefined
|
||||
CXXFLAGS += -lubsan -fsanitize=undefined
|
||||
LDFLAGS += -lubsan -fsanitize=undefined
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g -DFBA_DEBUG
|
||||
CXXFLAGS += -O0 -g -DFBA_DEBUG
|
||||
else
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CFLAGS += -O3 -DNDEBUG
|
||||
CXXFLAGS += -O3 -DNDEBUG
|
||||
else
|
||||
CFLAGS += -O2 -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += $(fpic) $(FBA_DEFINES)
|
||||
CXXFLAGS += $(fpic) $(FBA_DEFINES)
|
||||
LDFLAGS += $(fpic)
|
||||
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CFLAGS += -fforce-addr $(INLINE_LIMIT) \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
-Wno-sequence-point -Wno-strict-aliasing
|
||||
CXXFLAGS += -fforce-addr $(INLINE_LIMIT) \
|
||||
-fcheck-new \
|
||||
-Wall -W -Wshadow -Wno-long-long -Wno-write-strings \
|
||||
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
|
||||
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-unused-value \
|
||||
-Wno-sequence-point -Wno-extra -Wno-strict-aliasing
|
||||
|
||||
ifeq (,$(filter $(platform), ps3 sncps3))
|
||||
CFLAGS += -Wno-write-strings -Wno-pedantic
|
||||
CXXFLAGS += -Wno-write-strings -pedantic -Wno-address -Wno-unused-but-set-variable -Wno-narrowing -Wno-pedantic
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(FRONTEND_SUPPORTS_RGB565), 1)
|
||||
CFLAGS += -DFRONTEND_SUPPORTS_RGB565
|
||||
CXXFLAGS += -DFRONTEND_SUPPORTS_RGB565
|
||||
endif
|
||||
|
||||
PERL = perl$(EXE_EXT)
|
||||
M68KMAKE_EXE = m68kmake$(EXE_EXT)
|
||||
CTVMAKE_EXE = ctvmake$(EXE_EXT)
|
||||
PGM_SPRITE_CREATE_EXE = pgmspritecreate$(EXE_EXT)
|
||||
EXE_PREFIX = ./
|
||||
|
||||
.PHONY: clean generate-files generate-files-clean clean-objs
|
||||
|
||||
ifeq ($(platform), theos_ios)
|
||||
COMMON_FLAGS := -DIOS -DARM $(COMMON_DEFINES) $(INCFLAGS) -I$(THEOS_INCLUDE_PATH) -Wno-error
|
||||
$(LIBRARY_NAME)_CFLAGS += $(CFLAGS) $(COMMON_FLAGS)
|
||||
$(LIBRARY_NAME)_CXXFLAGS += $(CXXFLAGS) $(COMMON_FLAGS)
|
||||
${LIBRARY_NAME}_FILES = $(SOURCES_CXX) $(SOURCES_C)
|
||||
include $(THEOS_MAKE_PATH)/library.mk
|
||||
else
|
||||
all: $(TARGET)
|
||||
|
||||
|
||||
generate-files-clean:
|
||||
rm -rf $(FBA_GENERATED_DIR)/
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kops.c
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kops.h
|
||||
rm -rf gamelist.txt
|
||||
|
||||
generate-files:
|
||||
@mkdir -p $(FBA_GENERATED_DIR) 2>/dev/null || /bin/true
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/driverlist.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/gamelist.pl -o $(FBA_GENERATED_DIR)/driverlist.h -l gamelist.txt $(FBA_BURN_DRIVERS_DIR) $(FBA_BURN_DRIVERS_DIR)/capcom $(FBA_BURN_DRIVERS_DIR)/cave $(FBA_BURN_DRIVERS_DIR)/coleco $(FBA_BURN_DRIVERS_DIR)/cps3 $(FBA_BURN_DRIVERS_DIR)/dataeast $(FBA_BURN_DRIVERS_DIR)/galaxian $(FBA_BURN_DRIVERS_DIR)/irem $(FBA_BURN_DRIVERS_DIR)/konami $(FBA_BURN_DRIVERS_DIR)/megadrive $(MIDWAY_DIR) $(FBA_BURN_DRIVERS_DIR)/msx $(FBA_BURN_DRIVERS_DIR)/neogeo $(FBA_BURN_DRIVERS_DIR)/pce $(FBA_BURN_DRIVERS_DIR)/pgm $(FBA_BURN_DRIVERS_DIR)/pre90s $(FBA_BURN_DRIVERS_DIR)/psikyo $(FBA_BURN_DRIVERS_DIR)/pst90s $(FBA_BURN_DRIVERS_DIR)/sega $(FBA_BURN_DRIVERS_DIR)/sg1000 $(SMS_DIR) $(FBA_BURN_DRIVERS_DIR)/snes $(FBA_BURN_DRIVERS_DIR)/taito $(FBA_BURN_DRIVERS_DIR)/toaplan
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/neo_sprite_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/neo_sprite_func_table.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/neo_sprite_func.pl -o $(FBA_GENERATED_DIR)/neo_sprite_func.h
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/psikyo_tile_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/psikyo_tile_func_table.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/psikyo_tile_func.pl -o $(FBA_GENERATED_DIR)/psikyo_tile_func.h
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/cave_sprite_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating[ $(FBA_GENERATED_DIR)/cave_tile_func_table.h"
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/cave_sprite_func.pl -o $(FBA_GENERATED_DIR)/cave_sprite_func.h
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/cave_tile_func.pl -o $(FBA_GENERATED_DIR)/cave_tile_func.h
|
||||
@echo ""
|
||||
@echo "Generate $(FBA_GENERATED_DIR)/toa_gp9001_func_table.h"
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/toa_gp9001_func.pl -o $(FBA_GENERATED_DIR)/toa_gp9001_func.h
|
||||
$(CXX_SYSTEM) $(GENERATE_OPTS) -o $(PGM_SPRITE_CREATE_EXE) $(FBA_BURN_DRIVERS_DIR)/pgm/pgm_sprite_create.cpp
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/pgm_sprite.h..."
|
||||
@echo ""
|
||||
$(EXE_PREFIX)$(PGM_SPRITE_CREATE_EXE) > $(FBA_GENERATED_DIR)/pgm_sprite.h
|
||||
$(CC_SYSTEM) $(GENERATE_OPTS) -o $(M68KMAKE_EXE) $(FBA_CPU_DIR)/m68k/m68kmake.c
|
||||
$(EXE_PREFIX)$(M68KMAKE_EXE) $(FBA_CPU_DIR)/m68k/ $(FBA_CPU_DIR)/m68k/m68k_in.c
|
||||
$(CXX_SYSTEM) $(GENERATE_OPTS) -o $(CTVMAKE_EXE) $(FBA_BURN_DRIVERS_DIR)/capcom/ctv_make.cpp
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/ctv.h..."
|
||||
@echo ""
|
||||
$(EXE_PREFIX)$(CTVMAKE_EXE) > $(FBA_GENERATED_DIR)/ctv.h
|
||||
|
||||
OBJOUT = -o
|
||||
LINKOUT = -o
|
||||
|
||||
ifneq (,$(findstring msvc,$(platform)))
|
||||
OBJOUT = -Fo
|
||||
LINKOUT = -out:
|
||||
ifeq ($(STATIC_LINKING),1)
|
||||
LD ?= lib.exe
|
||||
STATIC_LINKING=0
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -MTd
|
||||
CXXFLAGS += -MTd
|
||||
else
|
||||
CFLAGS += -MT
|
||||
CXXFLAGS += -MT
|
||||
endif
|
||||
else
|
||||
LD = link.exe
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -MDd
|
||||
CXXFLAGS += -MDd
|
||||
else
|
||||
CFLAGS += -MD
|
||||
CXXFLAGS += -MD
|
||||
endif
|
||||
endif
|
||||
else
|
||||
LD = $(CXX)
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(INCFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(OBJOUT)$@ $< $(CXXFLAGS) $(INCFLAGS)
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) $(INCFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@echo "** BUILDING $(TARGET) FOR PLATFORM $(platform) **"
|
||||
ifeq ($(STATIC_LINKING), 1)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
else
|
||||
$(LD) $(LINKOUT)$@ $(SHARED) $^ $(LDFLAGS) $(LIBS)
|
||||
endif
|
||||
@echo "** BUILD SUCCESSFUL! **"
|
||||
|
||||
clean-objs:
|
||||
rm -f $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
rm -f $(OBJS)
|
||||
rm -f $(M68KMAKE_EXE)
|
||||
rm -f $(PGM_SPRITE_CREATE_EXE)
|
||||
rm -f $(CTVMAKE_EXE)
|
||||
endif
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
FBA_BURN_DIR := $(MAIN_FBA_DIR)/burn
|
||||
FBA_BURN_DRIVERS_DIR := $(MAIN_FBA_DIR)/burn/drv
|
||||
FBA_BURNER_DIR := $(MAIN_FBA_DIR)/burner
|
||||
FBA_CPU_DIR := $(MAIN_FBA_DIR)/cpu
|
||||
FBA_GENERATED_DIR := $(MAIN_FBA_DIR)/dep/generated
|
||||
FBA_INTERFACE_DIR := $(MAIN_FBA_DIR)/intf
|
||||
FBA_LIB_DIR := $(MAIN_FBA_DIR)/dep/libs
|
||||
FBA_SCRIPTS_DIR := $(MAIN_FBA_DIR)/dep/scripts
|
||||
LIBRETRO_DIR := $(FBA_BURNER_DIR)/libretro
|
||||
LIBRETRO_COMM_DIR := $(LIBRETRO_DIR)/libretro-common
|
||||
|
||||
CAPCOM_DIR := $(FBA_BURN_DRIVERS_DIR)/capcom
|
||||
CPS3_DIR := $(FBA_BURN_DRIVERS_DIR)/cps3
|
||||
GALAXIAN_DIR := $(FBA_BURN_DRIVERS_DIR)/galaxian
|
||||
NEOGEO_DIR := $(FBA_BURN_DRIVERS_DIR)/neogeo
|
||||
PGM_DIR := $(FBA_BURN_DRIVERS_DIR)/pgm
|
||||
SNES_DIR := $(FBA_BURN_DRIVERS_DIR)/snes
|
||||
SMS_DIR := $(FBA_BURN_DRIVERS_DIR)/sms
|
||||
MD_DIR := $(FBA_BURN_DRIVERS_DIR)/megadrive
|
||||
MIDWAY_DIR := $(FBA_BURN_DRIVERS_DIR)/midway
|
||||
PCE_DIR := $(FBA_BURN_DRIVERS_DIR)/pce
|
||||
M68K_DIR := $(FBA_CPU_DIR)/m68k
|
||||
MIPS3_DIR := $(FBA_CPU_DIR)/mips3
|
||||
MIPS3_X64_DYNAREC_DIR := $(FBA_CPU_DIR)/mips3/x64
|
||||
TMS34010_DIR := $(FBA_CPU_DIR)/tms34010
|
||||
ADSP2100_DIR := $(FBA_CPU_DIR)/adsp2100
|
||||
|
||||
BURN_BLACKLIST := $(FBA_CPU_DIR)/arm7/arm7exec.c \
|
||||
$(FBA_CPU_DIR)/arm7/arm7core.c \
|
||||
$(FBA_CPU_DIR)/adsp2100/2100ops.c \
|
||||
$(FBA_CPU_DIR)/hd6309/6309tbl.c \
|
||||
$(FBA_CPU_DIR)/hd6309/6309ops.c \
|
||||
$(FBA_CPU_DIR)/konami/konamtbl.c \
|
||||
$(FBA_CPU_DIR)/konami/konamops.c \
|
||||
$(FBA_CPU_DIR)/m68k/m68k_in.c \
|
||||
$(FBA_CPU_DIR)/m6800/6800ops.c \
|
||||
$(FBA_CPU_DIR)/m6800/6800tbl.c \
|
||||
$(FBA_CPU_DIR)/m6805/6805ops.c \
|
||||
$(FBA_CPU_DIR)/m6809/6809ops.c \
|
||||
$(FBA_CPU_DIR)/m6809/6809tbl.c \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2.cpp \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2-x86.cpp \
|
||||
$(FBA_CPU_DIR)/m68k/m68kmake.c \
|
||||
$(FBA_CPU_DIR)/m68k/m68kfpu.c \
|
||||
$(FBA_BURNER_DIR)/wave_writer.cpp \
|
||||
$(FBA_CPU_DIR)/m68k/m68kdasm.c \
|
||||
$(FBA_LIBRETRO_DIR)/menu.cpp \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2.cpp \
|
||||
$(FBA_BURNER_DIR)/sshot.cpp \
|
||||
$(FBA_BURNER_DIR)/conc.cpp \
|
||||
$(FBA_BURNER_DIR)/cong.cpp \
|
||||
$(FBA_BURNER_DIR)/image.cpp \
|
||||
$(FBA_BURNER_DIR)/misc.cpp \
|
||||
$(FBA_BURNER_DIR)/state.cpp \
|
||||
$(FBA_BURNER_DIR)/gami.cpp \
|
||||
$(FBA_BURNER_DIR)/gamc.cpp \
|
||||
$(FBA_CPU_DIR)/h6280/tblh6280.c \
|
||||
$(FBA_CPU_DIR)/m6502/t65sc02.c \
|
||||
$(FBA_CPU_DIR)/m6502/t65c02.c \
|
||||
$(FBA_CPU_DIR)/m6502/tdeco16.c \
|
||||
$(FBA_CPU_DIR)/m6502/tn2a03.c \
|
||||
$(FBA_CPU_DIR)/m6502/t6502.c \
|
||||
$(FBA_CPU_DIR)/nec/v25sfr.c \
|
||||
$(FBA_CPU_DIR)/nec/v25instr.c \
|
||||
$(FBA_CPU_DIR)/nec/necinstr.c \
|
||||
$(FBA_CPU_DIR)/mips3/mips3_dasm.cpp \
|
||||
$(FBA_CPU_DIR)/tms34010/tms34010_dasm.cpp \
|
||||
$(FBA_CPU_DIR)/tms34010/tms34010_newdasm.cpp \
|
||||
$(FBA_BURN_DIR)/drv/capcom/ctv_make.cpp \
|
||||
$(FBA_BURN_DIR)/drv/pgm/pgm_sprite_create.cpp \
|
||||
$(FBA_INTERFACE_DIR)/audio/aud_interface.cpp \
|
||||
$(FBA_CPU_DIR)/i8051/mcs51ops.c \
|
||||
$(FBA_CPU_DIR)/upd7810/7810ops.c \
|
||||
$(FBA_CPU_DIR)/upd7810/7810tbl.c \
|
||||
$(FBA_CPU_DIR)/v60/op12.c \
|
||||
$(FBA_CPU_DIR)/v60/am.c \
|
||||
$(FBA_CPU_DIR)/v60/am1.c \
|
||||
$(FBA_CPU_DIR)/v60/am2.c \
|
||||
$(FBA_CPU_DIR)/v60/op7a.c \
|
||||
$(FBA_CPU_DIR)/v60/am3.c \
|
||||
$(FBA_CPU_DIR)/v60/op2.c \
|
||||
$(FBA_CPU_DIR)/v60/op4.c \
|
||||
$(FBA_CPU_DIR)/v60/op6.c \
|
||||
$(FBA_CPU_DIR)/v60/op3.c \
|
||||
$(FBA_CPU_DIR)/v60/op5.c \
|
||||
$(FBA_CPU_DIR)/v60/optable.c \
|
||||
$(FBA_CPU_DIR)/v60/v60mem.c \
|
||||
$(FBA_CPU_DIR)/v60/v60d.c \
|
||||
$(FBA_CPU_DIR)/i8x41/8x41dasm.c \
|
||||
$(FBA_CPU_DIR)/z180/z180xy.c \
|
||||
$(FBA_CPU_DIR)/z180/z180fd.c \
|
||||
$(FBA_CPU_DIR)/z180/z180op.c \
|
||||
$(FBA_CPU_DIR)/z180/z180ed.c \
|
||||
$(FBA_CPU_DIR)/z180/z180dd.c \
|
||||
$(FBA_CPU_DIR)/z180/z180cb.c
|
||||
|
||||
ifeq ($(AUTOGEN_DATS), 0)
|
||||
BURN_BLACKLIST += $(FBA_BURNER_DIR)/dat.cpp
|
||||
else
|
||||
FBA_DEFINES += -DAUTOGEN_DATS
|
||||
endif
|
||||
|
||||
ifeq ($(NO_MD), 1)
|
||||
MD_DIR :=
|
||||
endif
|
||||
|
||||
ifeq ($(NO_PCE), 1)
|
||||
PCE_DIR :=
|
||||
endif
|
||||
|
||||
ifeq ($(NO_SMS), 1)
|
||||
SMS_DIR :=
|
||||
endif
|
||||
|
||||
ifeq ($(NO_CAPCOM), 1)
|
||||
CAPCOM_DIR :=
|
||||
endif
|
||||
|
||||
ifeq ($(NO_NEOGEO), 1)
|
||||
NEOGEO_DIR :=
|
||||
endif
|
||||
|
||||
ifeq ($(INCLUDE_CPLUSPLUS11_FILES), 1)
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CXXFLAGS += -std=gnu++11
|
||||
endif
|
||||
ifeq ($(BUILD_X64_EXE), 1)
|
||||
FBA_DEFINES += -DXBYAK_NO_OP_NAMES -DMIPS3_X64_DRC
|
||||
else
|
||||
MIPS3_X64_DYNAREC_DIR :=
|
||||
endif
|
||||
else
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CXXFLAGS += -std=gnu++98
|
||||
endif
|
||||
ADSP2100_DIR :=
|
||||
MIDWAY_DIR :=
|
||||
MIPS3_DIR :=
|
||||
MIPS3_X64_DYNAREC_DIR :=
|
||||
TMS34010_DIR :=
|
||||
BURN_BLACKLIST += $(FBA_CPU_DIR)/adsp2100_intf.cpp \
|
||||
$(FBA_CPU_DIR)/tms34010_intf.cpp \
|
||||
$(FBA_CPU_DIR)/mips3_intf.cpp
|
||||
endif
|
||||
|
||||
FBA_BURN_DIRS := $(FBA_BURN_DIR) \
|
||||
$(FBA_BURN_DIR)/devices \
|
||||
$(FBA_BURN_DIR)/snd \
|
||||
$(CAPCOM_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/cave \
|
||||
$(FBA_BURN_DRIVERS_DIR)/coleco \
|
||||
$(CPS3_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/dataeast \
|
||||
$(GALAXIAN_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/irem \
|
||||
$(FBA_BURN_DRIVERS_DIR)/konami \
|
||||
$(MD_DIR) \
|
||||
$(MIDWAY_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/msx \
|
||||
$(NEOGEO_DIR) \
|
||||
$(PCE_DIR) \
|
||||
$(PGM_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/pre90s \
|
||||
$(FBA_BURN_DRIVERS_DIR)/psikyo \
|
||||
$(FBA_BURN_DRIVERS_DIR)/pst90s \
|
||||
$(FBA_BURN_DRIVERS_DIR)/sega \
|
||||
$(FBA_BURN_DRIVERS_DIR)/sg1000 \
|
||||
$(SMS_DIR) \
|
||||
$(SNES_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/spectrum \
|
||||
$(FBA_BURN_DRIVERS_DIR)/taito \
|
||||
$(FBA_BURN_DRIVERS_DIR)/toaplan \
|
||||
$(FBA_BURN_DRIVERS_DIR)
|
||||
|
||||
FBA_CPU_DIRS := $(FBA_CPU_DIR) \
|
||||
$(ADSP2100_DIR) \
|
||||
$(FBA_CPU_DIR)/arm \
|
||||
$(FBA_CPU_DIR)/arm7 \
|
||||
$(FBA_CPU_DIR)/h6280 \
|
||||
$(FBA_CPU_DIR)/hd6309 \
|
||||
$(FBA_CPU_DIR)/i8x41 \
|
||||
$(FBA_CPU_DIR)/i8039 \
|
||||
$(FBA_CPU_DIR)/i8051 \
|
||||
$(FBA_CPU_DIR)/konami \
|
||||
$(FBA_CPU_DIR)/m6502 \
|
||||
$(FBA_CPU_DIR)/m6800 \
|
||||
$(FBA_CPU_DIR)/m6805 \
|
||||
$(FBA_CPU_DIR)/m6809 \
|
||||
$(M68K_DIR) \
|
||||
$(MIPS3_DIR) \
|
||||
$(MIPS3_X64_DYNAREC_DIR) \
|
||||
$(FBA_CPU_DIR)/nec \
|
||||
$(FBA_CPU_DIR)/pic16c5x \
|
||||
$(FBA_CPU_DIR)/s2650 \
|
||||
$(FBA_CPU_DIR)/sh2 \
|
||||
$(FBA_CPU_DIR)/tlcs90 \
|
||||
$(FBA_CPU_DIR)/tms32010 \
|
||||
$(TMS34010_DIR) \
|
||||
$(FBA_CPU_DIR)/upd7725 \
|
||||
$(FBA_CPU_DIR)/upd7810 \
|
||||
$(FBA_CPU_DIR)/v60 \
|
||||
$(FBA_CPU_DIR)/z80 \
|
||||
$(FBA_CPU_DIR)/z180
|
||||
|
||||
FBA_INTERFACE_DIRS := $(FBA_INTERFACE_DIR)/audio
|
||||
|
||||
FBA_SRC_DIRS := $(FBA_BURNER_DIR) $(FBA_BURN_DIRS) $(FBA_CPU_DIRS) $(FBA_BURNER_DIRS) $(FBA_INTERFACE_DIRS)
|
||||
|
||||
ifeq ($(EXTERNAL_ZLIB), 1)
|
||||
FBA_DEFINES += -DEXTERNAL_ZLIB
|
||||
LDFLAGS += -lz
|
||||
else
|
||||
FBA_SRC_DIRS += $(FBA_LIB_DIR)/zlib
|
||||
endif
|
||||
|
||||
ifeq ($(INCLUDE_7Z_SUPPORT), 1)
|
||||
FBA_DEFINES += -DINCLUDE_7Z_SUPPORT
|
||||
FBA_SRC_DIRS += $(FBA_LIB_DIR)/lib7z
|
||||
BURN_BLACKLIST += $(FBA_LIB_DIR)/lib7z/LzFindMt.c \
|
||||
$(FBA_LIB_DIR)/lib7z/LzmaEnc.c \
|
||||
$(FBA_LIB_DIR)/lib7z/MtCoder.c \
|
||||
$(FBA_LIB_DIR)/lib7z/Lzma2Enc.c \
|
||||
$(FBA_LIB_DIR)/lib7z/Bcj2Enc.c \
|
||||
$(FBA_LIB_DIR)/lib7z/Threads.c \
|
||||
$(FBA_LIB_DIR)/lib7z/Lzma86Enc.c \
|
||||
$(FBA_LIB_DIR)/lib7z/LzmaLib.c \
|
||||
$(FBA_LIB_DIR)/lib7z/XzEnc.c
|
||||
else
|
||||
BURN_BLACKLIST += $(FBA_BURNER_DIR)/un7z.cpp
|
||||
endif
|
||||
|
||||
SOURCES_C += $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.c)))
|
||||
|
||||
ifneq ($(STATIC_LINKING), 1)
|
||||
SOURCES_C += $(LIBRETRO_COMM_DIR)/file/file_path.c \
|
||||
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
|
||||
$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
|
||||
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
|
||||
$(LIBRETRO_COMM_DIR)/streams/file_stream.c \
|
||||
$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
|
||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
|
||||
$(LIBRETRO_COMM_DIR)/audio/audio_mixer.c \
|
||||
$(LIBRETRO_COMM_DIR)/audio/resampler/audio_resampler.c \
|
||||
$(LIBRETRO_COMM_DIR)/audio/resampler/drivers/nearest_resampler.c \
|
||||
$(LIBRETRO_COMM_DIR)/audio/resampler/drivers/null_resampler.c \
|
||||
$(LIBRETRO_COMM_DIR)/audio/resampler/drivers/sinc_resampler.c \
|
||||
$(LIBRETRO_COMM_DIR)/features/features_cpu.c \
|
||||
$(LIBRETRO_COMM_DIR)/file/config_file.c \
|
||||
$(LIBRETRO_COMM_DIR)/file/config_file_userdata.c \
|
||||
$(LIBRETRO_COMM_DIR)/formats/wav/rwav.c \
|
||||
$(LIBRETRO_COMM_DIR)/lists/string_list.c \
|
||||
$(LIBRETRO_COMM_DIR)/memmap/memalign.c
|
||||
endif
|
||||
|
||||
SOURCES_CXX += $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.cpp)))
|
||||
SOURCES_CXX += $(LIBRETRO_DIR)/libretro.cpp \
|
||||
$(LIBRETRO_DIR)/cd_emu.cpp \
|
||||
$(LIBRETRO_DIR)/retro_mem.cpp
|
||||
|
||||
ifeq ($(HAVE_NEON), 1)
|
||||
SOURCES_S := $(LIBRETRO_COMM_DIR)/audio/resampler/drivers/sinc_resampler_neon.S
|
||||
else
|
||||
SOURCES_S :=
|
||||
endif
|
||||
|
||||
INCLUDE_DIRS := $(FBA_BURNER_DIR)/win32 \
|
||||
$(LIBRETRO_COMM_DIR)/include \
|
||||
$(LIBRETRO_DIR) \
|
||||
$(FBA_BURN_DIR) \
|
||||
$(MAIN_FBA_DIR)/cpu \
|
||||
$(FBA_BURN_DIR)/snd \
|
||||
$(FBA_BURN_DIR)/devices \
|
||||
$(FBA_INTERFACE_DIR) \
|
||||
$(FBA_INTERFACE_DIR)/input \
|
||||
$(FBA_INTERFACE_DIR)/cd \
|
||||
$(FBA_INTERFACE_DIR)/audio \
|
||||
$(FBA_BURNER_DIR) \
|
||||
$(FBA_CPU_DIR) \
|
||||
$(FBA_CPU_DIR)/i8039 \
|
||||
$(FBA_CPU_DIR)/i8051 \
|
||||
$(FBA_CPU_DIR)/i8x41 \
|
||||
$(FBA_CPU_DIR)/m6805 \
|
||||
$(FBA_CPU_DIR)/tms32010 \
|
||||
$(FBA_CPU_DIR)/upd7725 \
|
||||
$(FBA_CPU_DIR)/upd7810 \
|
||||
$(FBA_CPU_DIR)/v60 \
|
||||
$(FBA_CPU_DIR)/z80 \
|
||||
$(FBA_CPU_DIR)/z180 \
|
||||
$(FBA_LIB_DIR)/zlib \
|
||||
$(FBA_LIB_DIR)/lib7z \
|
||||
$(FBA_BURN_DIR)/drv/capcom \
|
||||
$(FBA_BURN_DIR)/drv/konami \
|
||||
$(FBA_BURN_DIR)/drv/dataeast \
|
||||
$(FBA_BURN_DIR)/drv/cave \
|
||||
$(FBA_BURN_DIR)/drv/neogeo \
|
||||
$(FBA_BURN_DIR)/drv/psikyo \
|
||||
$(FBA_BURN_DIR)/drv/sega \
|
||||
$(FBA_BURN_DIR)/drv/toaplan \
|
||||
$(FBA_BURN_DIR)/drv/taito \
|
||||
$(FBA_BURN_DIR)/drv/irem \
|
||||
$(FBA_GENERATED_DIR) \
|
||||
$(FBA_LIB_DIR)
|
||||
|
||||
ifeq (,$(findstring msvc,$(platform)))
|
||||
CFLAGS += -std=gnu99
|
||||
endif
|
||||
|
||||
# GIT HASH
|
||||
GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
|
||||
ifneq ($(GIT_VERSION)," unknown")
|
||||
CXXFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
|
||||
endif
|
||||
@@ -1,6 +1,85 @@
|
||||
# FBAlpha
|
||||
[](https://travis-ci.org/libretro/fbalpha)
|
||||
[](https://ci.appveyor.com/project/bparker06/fbalpha/branch/master)
|
||||
|
||||
# FBAlpha-libretro
|
||||
https://www.fbalpha.com
|
||||
|
||||
This is the official repository of the FB Alpha Emulator.
|
||||
This is a fork of the official repository of the FB Alpha Emulator.
|
||||
|
||||
Use of this program and it's source code is subject to the license conditions provided in the [license.txt](/src/license.txt) file in the src folder.
|
||||
|
||||
## Roms
|
||||
|
||||
Use clrmamepro (which runs fine on linux with wine and on mac with crossover) to build valid romsets with dats from the [dats](dats/) directory.
|
||||
Don't report issues if you didn't build a valid romset.
|
||||
Also, i don't provide a "parent-only" dat file, this is usually a bad idea to only use parent roms (some don't work, and some clones are interesting)
|
||||
|
||||
## Emulating consoles
|
||||
|
||||
You can emulate consoles (with specific romsets, dats are also in the [dats](dats/) directory) by prefixing the name of the roms with `XXX_` and removing the `zip|7z` extension, or using the `--subsystem XXX` argument in the command line, here is the list of available prefix :
|
||||
* CBS ColecoVision : `cv`
|
||||
* MSX 1 : `msx`
|
||||
* Nec PC-Engine : `pce`
|
||||
* Nec SuperGrafX : `sgx`
|
||||
* Nec TurboGrafx-16 : `tg`
|
||||
* Sega GameGear : `gg`
|
||||
* Sega Master System : `sms`
|
||||
* Sega Megadrive : `md`
|
||||
* Sega SG-1000 : `sg1k`
|
||||
|
||||
## Samples
|
||||
|
||||
Samples should be put under SYSTEM_DIRECTORY/fba/samples
|
||||
|
||||
## hiscore.dat
|
||||
|
||||
Copy [hiscore.dat](metadata/hiscore.dat) to SYSTEM_DIRECTORY/fba/
|
||||
|
||||
## Mapping
|
||||
|
||||
We don't have a convenient tool like the MAME OSD, instead we use the retroarch api to customize mappings, you can do that by going into `Quick menu > Controls`.
|
||||
For those who don't want to fully customize their mapping, there are 2 convenient presets you can apply by changing the "device type" for a player in this menu :
|
||||
* **Classic** : it will apply the original neogeo cd "square" mapping in neogeo games, and use L/R as 5th and 6th button for 6 buttons games like Street Fighter II.
|
||||
* **Modern** : it will apply the King of fighters mapping from Playstation 1 and above in neogeo fighting games, and it will use R1/R2 as 5th and 6th button for 6 buttons games like Street Fighter II (for the same reason as the neogeo games), this is really convenient for most arcade sticks.
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
### Where can i find the XXX roms ?
|
||||
We don't provide links for roms. Google is your friend.
|
||||
|
||||
### I can't launch Killer Instinct, Rampage, Mortal Kombat 3 and other MIDWAY games, why ?
|
||||
Support for those games was removed from the libretro port.
|
||||
They are buggy in FB Alpha and have serious compatibility issues with this port.
|
||||
Let's hope someone will fix them in a future release of FB Alpha.
|
||||
|
||||
### Game XXX is not launching, why ?
|
||||
It is either not supported or you have a bad rom. Build a valid romset with clrmamepro as said above.
|
||||
There is also a few games marked as not working, try one of their clones.
|
||||
|
||||
### Game XXX has graphical glitches, why ?
|
||||
Most likely the same as above, make sure you have the right romset.
|
||||
If the problem persist, write a report with a screenshot and the name of the platform you are using.
|
||||
|
||||
### Game XXX runs slowly, why ?
|
||||
Your hardware is probably too slow to run the game with normal settings. Try the following :
|
||||
* Check if there is a speedhack dipswitch in the core options, set it to "yes".
|
||||
* Try disabling rewind, runahead, and anything related to the savestates system in retroarch.
|
||||
* Try lowering audio settings in the core options.
|
||||
If it is not enough, upgrade or overclock your hardware.
|
||||
|
||||
### Game XXX has choppy sound, why ?
|
||||
Most likely for the same reason as above.
|
||||
|
||||
### Game XXX runs faster in MAME2003/MAME2010, why ?
|
||||
This is not MAME, we are using different code.
|
||||
Overall, FB Alpha is slower than old MAME version but more accurate and less buggy.
|
||||
This libretro port also support various features which are usually buggy or absent in MAME cores (netplay, rewind, retroachievements, ...). It takes some resources.
|
||||
|
||||
### Cheat code doesn't work, why ?
|
||||
This is not implemented yet.
|
||||
|
||||
### Neogeo CD doesn't work, why ?
|
||||
The support is still a work in progress, there are several things to know :
|
||||
* You need a copy of neocdz.zip and neogeo.zip in your libretro system directory
|
||||
* You need to add `--subsystem neocd` to the command line
|
||||
* you can only load `MODE1/2048` tracks at the moment
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE datafile PUBLIC "-//FB Alpha//DTD ROM Management Datafile//EN" "http://www.logiqx.com/Dats/datafile.dtd">
|
||||
|
||||
<datafile>
|
||||
<header>
|
||||
<name>FB Alpha - SuprGrafx Games</name>
|
||||
<description>FB Alpha v0.2.97.44 SuprGrafx Games</description>
|
||||
<category>Standard DatFile</category>
|
||||
<version>0.2.97.44</version>
|
||||
<author>FB Alpha</author>
|
||||
<homepage>https://www.fbalpha.com/</homepage>
|
||||
<url>https://www.fbalpha.com/</url>
|
||||
<clrmamepro forcenodump="ignore"/>
|
||||
</header>
|
||||
<game name="1941">
|
||||
<description>1941 - Counter Attack</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Hudson</manufacturer>
|
||||
<rom name="1941 - counter attack (japan).pce" size="1048576" crc="8c4588e2"/>
|
||||
</game>
|
||||
<game name="aldynes">
|
||||
<description>Aldynes</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Hudson</manufacturer>
|
||||
<rom name="aldynes (japan).pce" size="1048576" crc="4c2126b0"/>
|
||||
</game>
|
||||
<game name="battlace">
|
||||
<description>Battle Ace</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>Hudson</manufacturer>
|
||||
<rom name="battle ace (japan).pce" size="524288" crc="3b13af61"/>
|
||||
</game>
|
||||
<game name="daimakai">
|
||||
<description>Dai Makaimura</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC Avenue</manufacturer>
|
||||
<rom name="daimakai mura (japan).pce" size="1048576" crc="b486a8ed"/>
|
||||
</game>
|
||||
<game name="daimakai1" cloneof="daimakai" romof="daimakai">
|
||||
<description>Dai Makaimura (Alt)</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC Avenue</manufacturer>
|
||||
<rom name="daimakai mura (japan)[a].pce" size="1049088" crc="8e961f63"/>
|
||||
</game>
|
||||
<game name="daimakaid" cloneof="daimakai" romof="daimakai">
|
||||
<description>Dai Makaimura (Chris Covell's Debug Menu Hack)</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC Avenue</manufacturer>
|
||||
<rom name="daimakai mura (japan)[debug].pce" size="1048576" crc="d6722c04"/>
|
||||
</game>
|
||||
<game name="granzort">
|
||||
<description>Madou Ou Granzort</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>Hudson</manufacturer>
|
||||
<rom name="madou ou granzort (japan).pce" size="524288" crc="1f041166"/>
|
||||
</game>
|
||||
</datafile>
|
||||
@@ -0,0 +1,573 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE datafile PUBLIC "-//FB Alpha//DTD ROM Management Datafile//EN" "http://www.logiqx.com/Dats/datafile.dtd">
|
||||
|
||||
<datafile>
|
||||
<header>
|
||||
<name>FB Alpha - TurboGrafx 16 Games</name>
|
||||
<description>FB Alpha v0.2.97.44 TurboGrafx 16 Games</description>
|
||||
<category>Standard DatFile</category>
|
||||
<version>0.2.97.44</version>
|
||||
<author>FB Alpha</author>
|
||||
<homepage>https://www.fbalpha.com/</homepage>
|
||||
<url>https://www.fbalpha.com/</url>
|
||||
<clrmamepro forcenodump="ignore"/>
|
||||
</header>
|
||||
<game name="aeroblst">
|
||||
<description>Aero Blasters</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="aero blasters (usa).pce" size="524288" crc="b03e0b32"/>
|
||||
</game>
|
||||
<game name="acrush">
|
||||
<description>Alien Crush</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="alien crush (usa).pce" size="262144" crc="ea488494"/>
|
||||
</game>
|
||||
<game name="ballistx">
|
||||
<description>Ballistix</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="ballistix (usa).pce" size="262144" crc="420fa189"/>
|
||||
</game>
|
||||
<game name="batlroyl">
|
||||
<description>Battle Royale</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="battle royale (usa).pce" size="524288" crc="e70b01af"/>
|
||||
</game>
|
||||
<game name="blazlazr">
|
||||
<description>Blazing Lazers</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="blazing lazers (usa).pce" size="393216" crc="b4a1b0f6"/>
|
||||
</game>
|
||||
<game name="blodwolf">
|
||||
<description>Bloody Wolf</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="bloody wolf (usa).pce" size="524288" crc="37baf6bc"/>
|
||||
</game>
|
||||
<game name="bombman">
|
||||
<description>Bomberman</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="bomberman (usa).pce" size="262144" crc="5f6f3c2a"/>
|
||||
</game>
|
||||
<game name="bombmn93">
|
||||
<description>Bomberman '93</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>Hudson Soft</manufacturer>
|
||||
<rom name="bomberman '93 (usa).pce" size="524288" crc="56171c1c"/>
|
||||
</game>
|
||||
<game name="bonk3">
|
||||
<description>Bonk III - Bonk's Big Adventure</description>
|
||||
<year>1993</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="bonk iii - bonk's big adventure (usa).pce" size="1048576" crc="5a3f76d8"/>
|
||||
</game>
|
||||
<game name="bonk">
|
||||
<description>Bonk's Adventure</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="bonk's adventure (usa).pce" size="393216" crc="599ead9b"/>
|
||||
</game>
|
||||
<game name="bonk2">
|
||||
<description>Bonk's Revenge</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="bonk's revenge (usa).pce" size="524288" crc="14250f9a"/>
|
||||
</game>
|
||||
<game name="boxyboy">
|
||||
<description>Boxyboy</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="boxyboy (usa).pce" size="131072" crc="605be213"/>
|
||||
</game>
|
||||
<game name="bravoman">
|
||||
<description>Bravoman</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="bravoman (usa).pce" size="524288" crc="cca08b02"/>
|
||||
</game>
|
||||
<game name="cadash">
|
||||
<description>Cadash [Bad graphics]</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Working Designs</manufacturer>
|
||||
<rom name="cadash (usa).pce" size="524288" crc="bb0b3aef"/>
|
||||
</game>
|
||||
<game name="forevbox">
|
||||
<description>Champions Forever Boxing [Bad sound]</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="champions forever boxing (usa).pce" size="524288" crc="15ee889a"/>
|
||||
</game>
|
||||
<game name="chewman">
|
||||
<description>Chew Man Fu</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="chew man fu (usa).pce" size="262144" crc="8cd13e9a"/>
|
||||
</game>
|
||||
<game name="chinawar">
|
||||
<description>China Warrior</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="china warrior (usa).pce" size="262144" crc="a2ee361d"/>
|
||||
</game>
|
||||
<game name="cratermz">
|
||||
<description>Cratermaze</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="cratermaze (usa).pce" size="262144" crc="9033e83a"/>
|
||||
</game>
|
||||
<game name="cybrcore">
|
||||
<description>Cyber Core</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="cyber core (usa).pce" size="393216" crc="4cfb6e3e"/>
|
||||
</game>
|
||||
<game name="darkwing">
|
||||
<description>Darkwing Duck</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="darkwing duck (usa).pce" size="524288" crc="4ac97606"/>
|
||||
</game>
|
||||
<game name="daviscup">
|
||||
<description>Davis Cup Tennis</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="davis cup tennis (usa).pce" size="524288" crc="9edab596"/>
|
||||
</game>
|
||||
<game name="deadmoon">
|
||||
<description>Dead Moon</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="dead moon (usa).pce" size="524288" crc="f5d98b0b"/>
|
||||
</game>
|
||||
<game name="deepblue">
|
||||
<description>Deep Blue</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="deep blue (usa).pce" size="262144" crc="16b40b44"/>
|
||||
</game>
|
||||
<game name="devlcrsh">
|
||||
<description>Devil's Crush - Naxat Pinball</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="devil's crush - naxat pinball (usa).pce" size="393216" crc="157b4492"/>
|
||||
</game>
|
||||
<game name="ddungw">
|
||||
<description>Double Dungeons - W</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="double dungeons - w (usa).pce" size="262144" crc="4a1a8c60"/>
|
||||
</game>
|
||||
<game name="dspirit">
|
||||
<description>Dragon Spirit</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="dragon spirit (usa).pce" size="262144" crc="086f148c"/>
|
||||
</game>
|
||||
<game name="dragcrse">
|
||||
<description>Dragon's Curse</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="dragon's curse (usa).pce" size="262144" crc="7d2c4b09"/>
|
||||
</game>
|
||||
<game name="dropoff">
|
||||
<description>Drop.Off</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="drop.off (usa).pce" size="262144" crc="fea27b32"/>
|
||||
</game>
|
||||
<game name="dungexpl">
|
||||
<description>Dungeon Explorer</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="dungeon explorer (usa).pce" size="393216" crc="4ff01515"/>
|
||||
</game>
|
||||
<game name="falcon">
|
||||
<description>Falcon</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="falcon (usa).pce" size="524288" crc="0bc0a12b"/>
|
||||
</game>
|
||||
<game name="fantzone">
|
||||
<description>Fantasy Zone</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="fantasy zone (usa).pce" size="262144" crc="e8c3573d"/>
|
||||
</game>
|
||||
<game name="finallap">
|
||||
<description>Final Lap Twin</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="final lap twin (usa).pce" size="393216" crc="26408ea3"/>
|
||||
</game>
|
||||
<game name="galaga90">
|
||||
<description>Galaga '90</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="galaga '90 (usa).pce" size="262144" crc="2909dec6"/>
|
||||
</game>
|
||||
<game name="ghostman">
|
||||
<description>Ghost Manor [game randomly locks up]</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="ghost manor (usa).pce" size="524288" crc="2db4c1fd"/>
|
||||
</game>
|
||||
<game name="gunboat">
|
||||
<description>Gunboat</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="gunboat (usa).pce" size="524288" crc="f370b58e"/>
|
||||
</game>
|
||||
<game name="hitice">
|
||||
<description>Hit the Ice - VHL - The Official Video Hockey League</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="hit the ice - vhl the official video hockey league (usa).pce" size="393216" crc="8b29c3aa"/>
|
||||
</game>
|
||||
<game name="impossam">
|
||||
<description>Impossamole</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="impossamole (usa).pce" size="524288" crc="e2470f5f"/>
|
||||
</game>
|
||||
<game name="jjnjeff">
|
||||
<description>J.J. & Jeff</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="j.j. & jeff (usa).pce" size="262144" crc="e01c5127"/>
|
||||
</game>
|
||||
<game name="nicklaus">
|
||||
<description>Jack Nicklaus' Turbo Golf</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>Accolade</manufacturer>
|
||||
<rom name="jack nicklaus' turbo golf (usa).pce" size="262144" crc="83384572"/>
|
||||
</game>
|
||||
<game name="jchan">
|
||||
<description>Jackie Chan's Action Kung Fu</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>Hudson Soft</manufacturer>
|
||||
<rom name="jackie chan's action kung fu (usa).pce" size="524288" crc="9d2f6193"/>
|
||||
</game>
|
||||
<game name="keithcor">
|
||||
<description>Keith Courage in Alpha Zones</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="keith courage in alpha zones (usa).pce" size="262144" crc="474d7a72"/>
|
||||
</game>
|
||||
<game name="kingcasn">
|
||||
<description>King of Casino</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="king of casino (usa).pce" size="262144" crc="2f2e2240"/>
|
||||
</game>
|
||||
<game name="klax">
|
||||
<description>Klax</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>Tengen</manufacturer>
|
||||
<rom name="klax (usa).pce" size="262144" crc="0f1b59b4"/>
|
||||
</game>
|
||||
<game name="loht">
|
||||
<description>Legend of Hero Tonma</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="legend of hero tonma (usa).pce" size="524288" crc="3c131486"/>
|
||||
</game>
|
||||
<game name="magchase">
|
||||
<description>Magical Chase</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="magical chase (usa).pce" size="524288" crc="95cd2979"/>
|
||||
</game>
|
||||
<game name="miltrymd">
|
||||
<description>Military Madness</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="military madness (usa).pce" size="393216" crc="93f316f7"/>
|
||||
</game>
|
||||
<game name="motoroad">
|
||||
<description>Moto Roader</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="moto roader (usa).pce" size="262144" crc="e2b0d544"/>
|
||||
</game>
|
||||
<game name="neutopia">
|
||||
<description>Neutopia</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="neutopia (usa).pce" size="393216" crc="a9a94e1b"/>
|
||||
</game>
|
||||
<game name="neutopi2">
|
||||
<description>Neutopia II</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="neutopia ii (usa).pce" size="786432" crc="c4ed4307"/>
|
||||
</game>
|
||||
<game name="advislnd">
|
||||
<description>New Adventure Island</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="new adventure island (usa).pce" size="524288" crc="756a1802"/>
|
||||
</game>
|
||||
<game name="nightcr">
|
||||
<description>Night Creatures</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="night creatures (usa).pce" size="524288" crc="c159761b"/>
|
||||
</game>
|
||||
<game name="nspirit">
|
||||
<description>Ninja Spirit</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="ninja spirit (usa).pce" size="524288" crc="de8af1c1"/>
|
||||
</game>
|
||||
<game name="griffon">
|
||||
<description>Order of the Griffon</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="order of the griffon (usa).pce" size="524288" crc="fae0fc60"/>
|
||||
</game>
|
||||
<game name="ordyne">
|
||||
<description>Ordyne</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="ordyne (usa).pce" size="524288" crc="e7bf2a74"/>
|
||||
</game>
|
||||
<game name="pacland">
|
||||
<description>Pac-Land</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="pac-land (usa).pce" size="262144" crc="d6e30ccd"/>
|
||||
</game>
|
||||
<game name="panzakb">
|
||||
<description>Panza Kick Boxing</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="panza kick boxing (usa).pce" size="524288" crc="a980e0e9"/>
|
||||
</game>
|
||||
<game name="parasol">
|
||||
<description>Parasol Stars - The Story of Bubble Bobble III</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Working Designs</manufacturer>
|
||||
<rom name="parasol stars - the story of bubble bobble iii (usa).pce" size="393216" crc="e6458212"/>
|
||||
</game>
|
||||
<game name="pgolf">
|
||||
<description>Power Golf</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="power golf (usa).pce" size="393216" crc="ed1d3843"/>
|
||||
</game>
|
||||
<game name="psychos">
|
||||
<description>Psychosis</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="psychosis (usa).pce" size="262144" crc="6cc10824"/>
|
||||
</game>
|
||||
<game name="rtype">
|
||||
<description>R-Type</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="r-type (usa).pce" size="524288" crc="91ce5156"/>
|
||||
</game>
|
||||
<game name="raiden">
|
||||
<description>Raiden</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="raiden (usa).pce" size="786432" crc="bc59c31e"/>
|
||||
</game>
|
||||
<game name="samuraig">
|
||||
<description>Samurai-Ghost</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="samurai-ghost (usa).pce" size="524288" crc="77a924b7"/>
|
||||
</game>
|
||||
<game name="shockman">
|
||||
<description>Shockman</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="shockman (usa).pce" size="524288" crc="2774462c"/>
|
||||
</game>
|
||||
<game name="sidearms">
|
||||
<description>Sidearms - Hyper Dyne</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>Radiance Software</manufacturer>
|
||||
<rom name="sidearms - hyper dyne (usa).pce" size="262144" crc="d1993c9f"/>
|
||||
</game>
|
||||
<game name="silentd">
|
||||
<description>Silent Debuggers</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Hudson Soft</manufacturer>
|
||||
<rom name="silent debuggers (usa).pce" size="524288" crc="fa7e5d66"/>
|
||||
</game>
|
||||
<game name="sinistrn">
|
||||
<description>Sinistron</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="sinistron (usa).pce" size="393216" crc="4f6e2dbd"/>
|
||||
</game>
|
||||
<game name="soldblad">
|
||||
<description>Soldier Blade [Hangs at first boss]</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="soldier blade (usa).pce" size="524288" crc="4bb68b13"/>
|
||||
</game>
|
||||
<game name="somerass">
|
||||
<description>Somer Assault</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>Atlus</manufacturer>
|
||||
<rom name="somer assault (usa).pce" size="524288" crc="8fcaf2e9"/>
|
||||
</game>
|
||||
<game name="wbeach">
|
||||
<description>Sonic Spike - World Championship Beach Volleyball</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="sonic spike - world championship beach volleyball (usa).pce" size="262144" crc="f74e5eb3"/>
|
||||
</game>
|
||||
<game name="sharrier">
|
||||
<description>Space Harrier</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="space harrier (usa).pce" size="524288" crc="43b05eb8"/>
|
||||
</game>
|
||||
<game name="splatth">
|
||||
<description>Splatterhouse</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="splatterhouse (usa).pce" size="524288" crc="d00ca74f"/>
|
||||
</game>
|
||||
<game name="sssoldr">
|
||||
<description>Super Star Soldier</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="super star soldier (usa).pce" size="524288" crc="db29486f"/>
|
||||
</game>
|
||||
<game name="svolley">
|
||||
<description>Super Volleyball</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="super volleyball (usa).pce" size="262144" crc="245040b3"/>
|
||||
</game>
|
||||
<game name="chasehq">
|
||||
<description>Taito Chase H.Q.</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="taito chase h.q. (usa).pce" size="393216" crc="9298254c"/>
|
||||
</game>
|
||||
<game name="taknhoop">
|
||||
<description>Takin' It to the Hoop</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="takin' it to the hoop (usa).pce" size="262144" crc="e9d51797"/>
|
||||
</game>
|
||||
<game name="talespin">
|
||||
<description>TaleSpin</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="talespin (usa).pce" size="524288" crc="bae9cecc"/>
|
||||
</game>
|
||||
<game name="legaxe">
|
||||
<description>The Legendary Axe</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="legendary axe, the (usa).pce" size="262144" crc="2d211007"/>
|
||||
</game>
|
||||
<game name="legaxe2">
|
||||
<description>The Legendary Axe II</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="legendary axe ii, the (usa).pce" size="262144" crc="220ebf91"/>
|
||||
</game>
|
||||
<game name="tigerrod">
|
||||
<description>Tiger Road</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="tiger road (usa).pce" size="393216" crc="985d492d"/>
|
||||
</game>
|
||||
<game name="timcrus">
|
||||
<description>Time Cruise</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="time cruise (usa).pce" size="524288" crc="02c39660"/>
|
||||
</game>
|
||||
<game name="timeball">
|
||||
<description>Timeball</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="timeball (usa).pce" size="131072" crc="5d395019"/>
|
||||
</game>
|
||||
<game name="tricky">
|
||||
<description>Tricky Kick</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="tricky kick (usa).pce" size="262144" crc="48e6fd34"/>
|
||||
</game>
|
||||
<game name="turrican">
|
||||
<description>Turrican</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>Ballistic</manufacturer>
|
||||
<rom name="turrican (usa).pce" size="262144" crc="eb045edf"/>
|
||||
</game>
|
||||
<game name="tvbasket">
|
||||
<description>TV Sports Basketball</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="tv sports basketball (usa).pce" size="524288" crc="ea54d653"/>
|
||||
</game>
|
||||
<game name="tvfootbl">
|
||||
<description>TV Sports Football</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="tv sports football (usa).pce" size="393216" crc="5e25b557"/>
|
||||
</game>
|
||||
<game name="tvhockey">
|
||||
<description>TV Sports Hockey</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="tv sports hockey (usa).pce" size="393216" crc="97fe5bcf"/>
|
||||
</game>
|
||||
<game name="veigues">
|
||||
<description>Veigues - Tactical Gladiator</description>
|
||||
<year>1990</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="veigues - tactical gladiator (usa).pce" size="393216" crc="99d14fb7"/>
|
||||
</game>
|
||||
<game name="victoryr">
|
||||
<description>Victory Run</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="victory run (usa).pce" size="262144" crc="85cbd045"/>
|
||||
</game>
|
||||
<game name="vigilant">
|
||||
<description>Vigilante</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="vigilante (usa).pce" size="393216" crc="79d49a0d"/>
|
||||
</game>
|
||||
<game name="wcbasebl">
|
||||
<description>World Class Baseball</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="world class baseball (usa).pce" size="262144" crc="4186d0c0"/>
|
||||
</game>
|
||||
<game name="wctennis">
|
||||
<description>World Court Tennis</description>
|
||||
<year>1989</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="world court tennis (usa).pce" size="262144" crc="a4457df0"/>
|
||||
</game>
|
||||
<game name="wscomp">
|
||||
<description>World Sports Competition</description>
|
||||
<year>1992</year>
|
||||
<manufacturer>TTI</manufacturer>
|
||||
<rom name="world sports competition (usa).pce" size="524288" crc="4b93f0ac"/>
|
||||
</game>
|
||||
<game name="yobro">
|
||||
<description>Yo, Bro</description>
|
||||
<year>1991</year>
|
||||
<manufacturer>NEC</manufacturer>
|
||||
<rom name="yo, bro (usa).pce" size="524288" crc="3ca7db48"/>
|
||||
</game>
|
||||
</datafile>
|
||||
+11419
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,35 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
ROOT_DIR := $(LOCAL_PATH)/..
|
||||
MAIN_FBA_DIR := $(ROOT_DIR)/src
|
||||
|
||||
INCLUDE_CPLUSPLUS11_FILES := 0
|
||||
INCLUDE_7Z_SUPPORT := 1
|
||||
EXTERNAL_ZLIB := 0
|
||||
BUILD_X64_EXE := 0
|
||||
WANT_NEOGEOCD := 0
|
||||
HAVE_NEON := 0
|
||||
|
||||
CFLAGS :=
|
||||
CXXFLAGS :=
|
||||
LDFLAGS :=
|
||||
SOURCES_C :=
|
||||
SOURCES_CXX :=
|
||||
FBA_DEFINES :=
|
||||
|
||||
include $(LIBRETRO_DIR)/Makefile.common
|
||||
|
||||
COMMON_FLAGS := -DUSE_SPEEDHACKS -D__LIBRETRO__ -DANDROID -DFRONTEND_SUPPORTS_RGB565 -Wno-write-strings -DLSB_FIRST $(FBA_DEFINES)
|
||||
|
||||
# Build shared library including static C module
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := retro
|
||||
LOCAL_SRC_FILES := $(SOURCES_C) $(SOURCES_S) $(SOURCES_CXX)
|
||||
LOCAL_C_INCLUDES := $(INCLUDE_DIRS)
|
||||
LOCAL_CFLAGS := $(CFLAGS) $(COMMON_FLAGS)
|
||||
LOCAL_CPPFLAGS := $(CXXFLAGS) $(COMMON_FLAGS)
|
||||
LOCAL_LDFLAGS := -Wl,-version-script=$(MAIN_FBA_DIR)/burner/libretro/link.T
|
||||
LOCAL_LDLIBS := $(LDFLAGS)
|
||||
LOCAL_CPP_FEATURES := exceptions rtti
|
||||
LOCAL_DISABLE_FORMAT_STRING_CHECKS := true
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,2 @@
|
||||
APP_ABI := all
|
||||
APP_STL := gnustl_static
|
||||
@@ -1,98 +0,0 @@
|
||||
# Main Makefile for FB Alpha, execute an appropriate system-specific makefile
|
||||
|
||||
export
|
||||
|
||||
#
|
||||
# Declare variables
|
||||
#
|
||||
|
||||
# Make a special build, pass the quoted text as comment (use FORCE_UPDATE declaration below to force recompilation of resources)
|
||||
# SPECIALBUILD = "This text will appear in the property sheet of the .exe file"
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Flags. Uncomment any of these declarations to enable their function.
|
||||
#
|
||||
|
||||
# Include Unicode support
|
||||
UNICODE = 1
|
||||
|
||||
# Use Segoe Fonts (installed by default on Windows Vista and newer)
|
||||
USE_SEGOE = 1
|
||||
|
||||
# Build A68K ASM 68000 core
|
||||
#BUILD_A68K = 1
|
||||
|
||||
# Include x86 Assembly routines
|
||||
BUILD_X86_ASM = 1
|
||||
|
||||
# Build for x64 targets (MinGW64 and MSVC only, this will undefine BUILD_A68K and BUILD_X86_ASM)
|
||||
#BUILD_X64_EXE = 1
|
||||
|
||||
# Build for Windows XP target (for use with Visual Studio 2012-15)
|
||||
#BUILD_VS_XP_TARGET = 1
|
||||
|
||||
# Include 7-zip support
|
||||
INCLUDE_7Z_SUPPORT = 1
|
||||
|
||||
# Include AVI recording support (uses Video For Windows)
|
||||
INCLUDE_AVI_RECORDING = 1
|
||||
|
||||
# Include Files that require C++11 (Killer Instinct, Midway Mortal Kombat style drivers, and associated files) - requires C++11 support
|
||||
INCLUDE_CPLUSPLUS11_FILES = 1
|
||||
|
||||
# Include symbols and other debug information in the executable
|
||||
#SYMBOL = 1
|
||||
|
||||
# Include features for debugging drivers
|
||||
DEBUG = 1
|
||||
|
||||
# Include rom set verifying features (comment this for release builds)
|
||||
#ROM_VERIFY = 1
|
||||
|
||||
# Force recompilation of files that need it (i.e. use __TIME__, __DATE__, SPECIALBUILD).
|
||||
FORCE_UPDATE = 1
|
||||
|
||||
# Use the __fastcall calling convention when interfacing with A68K/Musashi/Doze
|
||||
FASTCALL = 1
|
||||
|
||||
# Compress executable with upx (the DEBUG option ignores this)
|
||||
# COMPRESS = 1
|
||||
|
||||
# Perl is available
|
||||
PERL = 1
|
||||
|
||||
# Endianness
|
||||
LSB_FIRST = 1
|
||||
|
||||
# Include png.h from burner.h
|
||||
INCLUDE_LIB_PNGH = 1
|
||||
|
||||
|
||||
#
|
||||
# execute an appropriate system-specific makefile
|
||||
#
|
||||
|
||||
mingw345: FORCE
|
||||
@$(MAKE) -s -f makefile.mingw GCC345=1
|
||||
|
||||
mingw452: FORCE
|
||||
@$(MAKE) -s -f makefile.mingw GCC452=1
|
||||
|
||||
mingw471: FORCE
|
||||
@$(MAKE) -s -f makefile.mingw GCC471=1
|
||||
|
||||
mingw510: FORCE
|
||||
@$(MAKE) -s -f makefile.mingw GCC510=1
|
||||
|
||||
mamemingw: FORCE
|
||||
@$(MAKE) -s -f makefile.mamemingw
|
||||
|
||||
sdl: FORCE
|
||||
@$(MAKE) -s -f makefile.sdl
|
||||
|
||||
vc: FORCE
|
||||
@$(MAKE) -s -f makefile.vc
|
||||
|
||||
FORCE:
|
||||
@@ -1,167 +0,0 @@
|
||||
alldir = burn burn/devices burn/snd burn/drv burn/drv/capcom burn/drv/cave burn/drv/coleco burn/drv/cps3 burn/drv/dataeast \
|
||||
burn/drv/galaxian burn/drv/irem burn/drv/konami burn/drv/megadrive burn/drv/midway burn/drv/pce burn/drv/pst90s burn/drv/pre90s \
|
||||
burn/drv/neogeo burn/drv/pgm burn/drv/psikyo burn/drv/sega burn/drv/sg1000 burn/drv/sms burn/drv/msx burn/drv/snes burn/drv/spectrum \
|
||||
burn/drv/taito burn/drv/toaplan cpu cpu/a68k cpu/arm cpu/arm7 cpu/h6280 cpu/hd6309 cpu/i8039 cpu/i8x41 cpu/i8051 cpu/konami cpu/m68k cpu/m6502 cpu/m6800 \
|
||||
cpu/m6805 cpu/m6809 cpu/nec cpu/pic16c5x cpu/s2650 cpu/tlcs90 cpu/sh2 cpu/tms32010 cpu/upd7725 cpu/upd7810 cpu/v60 cpu/z80 cpu/z180
|
||||
|
||||
drvsrc = d_dodonpachi.o d_donpachi.o d_esprade.o d_feversos.o d_gaia.o d_guwange.o d_hotdogst.o d_korokoro.o d_mazinger.o \
|
||||
d_metmqstr.o d_pwrinst2.o d_sailormn.o d_tjumpman.o d_uopoko.o \
|
||||
\
|
||||
d_cps1.o \
|
||||
\
|
||||
d_cps2.o \
|
||||
\
|
||||
d_cps3.o \
|
||||
\
|
||||
d_actfancr.o d_backfire.o d_boogwing.o d_bwing.o d_cbuster.o d_chanbara.o d_cninja.o d_darkseal.o d_dassault.o d_dblewing.o d_dec0.o d_decocass.o \
|
||||
d_deco156.o d_deco32.o d_decomlc.o d_dec8.o d_dietgogo.o d_dreambal.o d_funkyjet.o d_karnov.o d_kchamp.o d_lemmings.o d_metlclsh.o d_pktgaldx.o d_progolf.o d_rohga.o \
|
||||
d_shootout.o d_sidepckt.o d_simpl156.o d_stadhero.o d_supbtime.o d_tumblep.o d_vaportra.o \
|
||||
\
|
||||
d_galaxian.o \
|
||||
\
|
||||
d_m52.o d_m57.o d_m58.o d_m62.o d_m63.o d_m72.o d_m90.o d_m92.o d_m107.o d_vigilant.o \
|
||||
\
|
||||
d_88games.o d_ajax.o d_aliens.o d_asterix.o d_battlex.o d_battlnts.o d_bishi.o d_bladestl.o d_blockhl.o d_bottom9.o d_chqflag.o d_circusc.o d_combatsc.o d_contra.o \
|
||||
d_crimfght.o d_dbz.o d_ddribble.o d_divebomb.o d_fastlane.o d_finalzr.o d_flkatck.o d_gberet.o d_gijoe.o d_gbusters.o d_gradius3.o d_gyruss.o d_hcastle.o d_hexion.o d_hyperspt.o \
|
||||
d_ironhors.o d_jackal.o d_jailbrek.o d_junofrst.o d_kontest.o d_labyrunr.o d_lethal.o d_mainevt.o d_megazone.o d_mikie.o d_mogura.o d_moo.o \
|
||||
d_mystwarr.o d_nemesis.o d_pandoras.o d_parodius.o d_pingpong.o d_pooyan.o d_rocnrope.o d_rockrage.o d_rollerg.o d_sbasketb.o d_scotrsht.o d_shaolins.o \
|
||||
d_simpsons.o d_spy.o d_surpratk.o d_thunderx.o d_timeplt.o d_tmnt.o d_tp84.o d_trackfld.o d_tutankhm.o d_twin16.o d_ultraman.o d_vendetta.o \
|
||||
d_xexex.o d_xmen.o d_yiear.o \
|
||||
\
|
||||
d_neogeo.o \
|
||||
\
|
||||
d_pgm.o \
|
||||
\
|
||||
d_psikyo.o d_psikyo4.o d_psikyosh.o \
|
||||
\
|
||||
d_angelkds.o d_appoooh.o d_bankp.o d_dotrikun.o d_hangon.o d_outrun.o d_segae.o d_segag80v.o d_suprloco.o d_sys1.o d_sys16a.o d_sys16b.o d_sys18.o d_turbo.o \
|
||||
d_xbrd.o d_ybrd.o d_zaxxon.o \
|
||||
\
|
||||
d_arkanoid.o d_ashnojoe.o d_asuka.o d_bublbobl.o d_chaknpop.o d_crbaloon.o d_darius2.o d_darkmist.o d_exzisus.o d_flstory.o d_jollyjgr.o d_ksayakyu.o d_lkage.o \
|
||||
d_minivdr.o d_msisaac.o d_othunder.o d_retofinv.o d_rollrace.o d_slapshot.o d_ssrj.o d_superchs.o d_supridr.o d_taitob.o d_taitoh.o d_taitof2.o d_taitof3.o \
|
||||
d_taitol.o d_taitomisc.o d_taitosj.o d_taitox.o d_taitoz.o d_tnzs.o d_wyvernf0.o \
|
||||
\
|
||||
d_batrider.o d_batsugun.o d_battleg.o d_bbakraid.o d_dogyuun.o d_enmadaio.o d_fixeight.o d_ghox.o d_kbash.o d_kbash2.o d_mahoudai.o d_pipibibs.o d_shippumd.o d_slapfght.o \
|
||||
d_snowbro2.o d_tekipaki.o d_toaplan1.o d_truxton2.o d_vfive.o d_wardner.o \
|
||||
\
|
||||
d_4enraya.o d_1942.o d_1943.o d_aeroboto.o d_alinvade.o d_alpha68k.o d_alpha68k1.o d_alpha68k2.o d_ambush.o d_amspdwy.o d_arabian.o d_armedf.o d_asteroids.o d_atetris.o d_aztarac.o d_bagman.o \
|
||||
d_baraduke.o d_battlane.o d_bbusters.o d_beaminv.o d_bionicc.o d_blktiger.o d_blockade.o d_blockout.o d_blueprnt.o d_bogeyman.o d_bombjack.o d_btime.o d_brkthru.o d_bwidow.o d_bzone.o d_cabal.o \
|
||||
d_calorie.o d_canyon.o d_capbowl.o d_carjmbre.o d_ccastles.o d_cclimber.o d_cheekyms.o d_chinagat.o d_citycon.o d_cloak.o d_cloud9.o d_clshroad.o d_commando.o d_cop01.o d_copsnrob.o d_cybertnk.o \
|
||||
d_dacholer.o d_dday.o d_ddayjlc.o d_ddragon.o d_djboy.o d_dkong.o d_docastle.o d_dogfgt.o d_dorachan.o d_dribling.o d_drmicro.o d_dynduke.o d_efdt.o d_epos.o d_espial.o d_ettrivia.o d_exedexes.o d_fantland.o \
|
||||
d_fastfred.o d_firetrap.o d_flipjack.o d_flower.o d_foodf.o d_freekick.o d_funkybee.o d_galaga.o d_galivan.o d_gaplus.o d_gauntlet.o d_ginganin.o d_gng.o d_goindol.o d_gunsmoke.o \
|
||||
d_headonb.o d_higemaru.o d_himesiki.o d_holeland.o d_hvyunit.o d_invaders.o d_jack.o d_jedi.o d_jrpacman.o d_kangaroo.o d_kncljoe.o d_kyugo.o d_ladybug.o d_lasso.o d_lastduel.o d_lwings.o d_mainsnk.o \
|
||||
d_mappy.o d_marineb.o d_mario.o d_madmotor.o d_markham.o d_mastboyo.o d_matmania.o d_megasys1.o d_meijinsn.o d_metlfrzr.o d_mhavoc.o d_millipede.o d_mirax.o d_mitchell.o d_mole.o d_momoko.o d_mmagic.o \
|
||||
d_mouser.o d_mrdo.o d_mrflea.o d_mrjong.o d_munchmo.o d_mustache.o d_mystston.o d_namcos1.o d_namcos86.o d_ninjakd2.o d_nitedrvr.o d_naughtyb.o d_olibochu.o d_omegrace.o d_oneshot.o d_pacland.o d_pacman.o d_pbaction.o \
|
||||
d_pac2650.o d_pengadvb.o d_phoenix.o d_pitnrun.o d_pkunwar.o d_popeye.o d_popper.o d_prehisle.o d_psychic5.o d_pturn.o d_punchout.o d_qbert.o d_quizo.o d_rallyx.o d_renegade.o \
|
||||
d_quantum.o d_route16.o d_rpunch.o d_safarir.o d_sauro.o d_scregg.o d_seicross.o d_sf.o d_shisen.o d_sidearms.o d_skyarmy.o d_skyfox.o d_skykid.o d_snk.o d_snk6502.o \
|
||||
d_snk68.o d_solomon.o d_sonson.o d_spacefb.o d_speedbal.o d_sprcros2.o d_srumbler.o d_ssozumo.o d_sstrangr.o d_starwars.o d_stfight.o d_sub.o d_suna8.o d_tagteam.o d_tankbust.o d_tail2nose.o d_tbowl.o \
|
||||
d_tceptor.o d_tecmo.o d_tempest.o d_terracre.o d_thedeep.o d_thepit.o d_tigeroad.o d_timelimt.o d_toki.o d_toypop.o d_travrusa.o d_tsamurai.o d_twincobr.o d_usgames.o d_vastar.o d_vball.o d_vicdual.o d_vulgus.o \
|
||||
d_wallc.o d_warpwarp.o d_warpsped.o d_wc90.o d_wc90b.o d_williams.o d_wiping.o d_wiz.o d_wrally.o d_wwfsstar.o d_xain.o d_xxmissio.o d_xyonix.o d_zodiack.o \
|
||||
\
|
||||
d_3x3puzzl.o d_1945kiii.o d_20pacgal.o d_aerofgt.o d_airbustr.o d_aquarium.o d_bestleag.o d_bigstrkb.o d_blackt96.o d_blmbycar.o d_bloodbro.o d_crospang.o d_crshrace.o d_cultures.o \
|
||||
d_dcon.o d_ddragon3.o d_deniam.o d_diverboy.o d_dooyong.o d_dreamwld.o d_drgnmst.o d_drtomy.o d_egghunt.o d_esd16.o d_f1gp.o d_funybubl.o d_fuukifg2.o \
|
||||
d_fuukifg3.o d_gaelco.o d_gaelco2.o d_gaiden.o d_galpanic.o d_galspnbl.o d_glass.o d_go2000.o d_gotcha.o d_gumbo.o d_hyperpac.o d_jchan.o d_kaneko16.o d_lordgun.o \
|
||||
d_macrossp.o d_mcatadv.o d_metro.o d_midas.o d_mirage.o d_missb2.o d_mosaic.o d_mugsmash.o d_mwarr.o d_namcos2.o d_news.o d_nmg5.o d_nmk16.o d_ohmygod.o d_onetwo.o d_pass.o d_patapata.o \
|
||||
d_pipedrm.o d_pirates.o d_pkscram.o d_playmark.o d_powerins.o d_ppmast93.o d_pushman.o d_raiden.o d_raiden2.o d_sandscrp.o d_seta.o d_seta2.o d_shadfrce.o d_silkroad.o d_silvmil.o \
|
||||
d_speedspn.o d_ssv.o d_suna16.o d_supduck.o d_suprnova.o d_taotaido.o d_targeth.o d_tecmo16.o d_tecmosys.o d_tetrisp2.o d_thoop2.o d_tumbleb.o d_unico.o d_vmetal.o d_welltris.o d_wwfwfest.o \
|
||||
d_xorworld.o d_yunsun16.o d_yunsung8.o d_zerozone.o \
|
||||
\
|
||||
d_parent.o \
|
||||
\
|
||||
d_megadrive.o \
|
||||
\
|
||||
d_pce.o \
|
||||
\
|
||||
d_sms.o \
|
||||
\
|
||||
d_msx.o \
|
||||
\
|
||||
d_snes.o \
|
||||
\
|
||||
d_coleco.o \
|
||||
\
|
||||
d_sg1000.o \
|
||||
\
|
||||
d_spectrum.o
|
||||
|
||||
ifdef INCLUDE_CPLUSPLUS11_FILES
|
||||
drvsrc += d_kinst.o d_wunit.o
|
||||
endif
|
||||
|
||||
depobj = burn.o burn_bitmap.o burn_gun.o burn_led.o burn_shift.o burn_memory.o burn_pal.o burn_sound.o burn_sound_c.o cheat.o debug_track.o hiscore.o load.o \
|
||||
tilemap_generic.o tiles_generic.o timer.o vector.o \
|
||||
\
|
||||
6821pia.o 8255ppi.o 8257dma.o c169.o avgdvg.o bsmt2000.o decobsmt.o earom.o eeprom.o gaelco_crypt.o joyprocess.o nb1414m4.o nb1414m4_8bit.o nmk004.o nmk112.o kaneko_tmap.o mathbox.o mb87078.o \
|
||||
mermaid.o namco_c45.o namcoio.o pandora.o resnet.o seibusnd.o sknsspr.o slapstic.o st0020.o t5182.o timekpr.o tms34061.o v3021.o vdc.o tms9928a.o \
|
||||
watchdog.o x2212.o \
|
||||
\
|
||||
asteroids.o ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o burn_md2612.o \
|
||||
burn_ym3526.o burn_ym3812.o burn_ymf278b.o bzone.o c6280.o dac.o es5506.o es8712.o flower.o flt_rc.o fm.o fmopl.o ym2612.o gaelco.o hc55516.o ics2115.o iremga20.o \
|
||||
k005289.o k007232.o k051649.o k053260.o k054539.o llander.o msm5205.o msm5232.o msm6295.o namco_snd.o c140.o nes_apu.o tms5110.o tms5220.o tms36xx.o phoenixsound.o \
|
||||
pleiadssound.o pokey.o redbaron.o rf5c68.o saa1099.o samples.o segapcm.o sn76477.o sn76496.o upd7759.o vlm5030.o wiping.o x1010.o ym2151.o ym2413.o \
|
||||
ymdeltat.o ymf278b.o ymz280b.o snk6502_sound.o sp0250.o sp0256.o \
|
||||
\
|
||||
arm7_intf.o arm_intf.o h6280_intf.o hd6309_intf.o konami_intf.o m6502_intf.o m6800_intf.o m6805_intf.o m6809_intf.o \
|
||||
m68000_intf.o nec_intf.o pic16c5x_intf.o s2650_intf.o tlcs90_intf.o z80_intf.o z180_intf.o \
|
||||
\
|
||||
arm.o arm7.o h6280.o hd6309.o i8039.o i8x41.o mcs51.o konami.o m6502.o m6800.o m6805.o m6809.o nec.o pic16c5x.o s2650.o sh2.o tms32010.o tlcs90.o \
|
||||
upd7725.o upd7810.o v25.o v60.o z80.o z80daisy.o z180.o \
|
||||
\
|
||||
cave.o cave_palette.o cave_sprite.o cave_tile.o \
|
||||
\
|
||||
cps2_crpt.o cps.o cps_config.o cps_draw.o cps_mem.o cps_obj.o cps_pal.o cps_run.o cps_rw.o cps_scr.o cpsr.o cpsrd.o \
|
||||
cpst.o ctv.o fcrash_snd.o kabuki.o ps.o ps_m.o ps_z.o qs.o qs_c.o qs_z.o sf2mdt_snd.o \
|
||||
\
|
||||
cps3run.o cps3snd.o \
|
||||
\
|
||||
deco16ic.o deco146.o decobac06.o \
|
||||
\
|
||||
gal_gfx.o gal_run.o gal_sound.o gal_stars.o \
|
||||
\
|
||||
irem_cpu.o irem_sound.o \
|
||||
\
|
||||
k007121.o k007342_k007420.o k051316.o k051733.o k051960.o k052109.o k053245.o k053247.o k053250.o k053251.o k053936.o k054000.o \
|
||||
k054338.o k055555.o k056832.o konamigx.o konamiic.o timeplt_snd.o \
|
||||
\
|
||||
neo_decrypt.o neo_palette.o neo_run.o neo_sprite.o neo_text.o neo_upd4990a.o neogeo.o \
|
||||
\
|
||||
pgm_crypt.o pgm_draw.o pgm_run.o pgm_asic3.o pgm_asic27a_type1.o pgm_asic27a_type2.o pgm_asic27a_type3.o pgm_asic25.o \
|
||||
\
|
||||
psikyo_palette.o psikyo_sprite.o psikyo_tile.o psikyosh_render.o \
|
||||
\
|
||||
fd1089.o fd1094.o genesis_vid.o mc8123.o sega_315_5195.o sys16_fd1094.o sys16_gfx.o sys16_run.o usb_snd.o \
|
||||
\
|
||||
cchip.o pc080sn.o pc090oj.o taito.o taito_ic.o taitof3_snd.o taitof3_video.o taito_m68705.o tc0100scn.o tc0110pcr.o tc0140syt.o tc0150rod.o \
|
||||
tc0180vcu.o tc0220ioc.o tc0280grd.o tc0360pri.o tc0480scp.o tc0510nio.o tc0640fio.o tnzs_prot.o \
|
||||
\
|
||||
toa_bcu2.o toa_extratext.o toa_gp9001.o toa_palette.o toaplan1.o toaplan.o \
|
||||
\
|
||||
megadrive.o stm95.o \
|
||||
\
|
||||
pce.o \
|
||||
\
|
||||
sms.o smspio.o smssystem.o smsvdp.o smsfmintf.o smsrender.o smssound.o smstms.o \
|
||||
\
|
||||
snes_65816.o snes_io.o snes_main.o snes_ppu.o snes_spc700.o \
|
||||
\
|
||||
spectrum_states.o
|
||||
|
||||
|
||||
ifdef DEBUG
|
||||
depobj += m68kdasm.o
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
autobj += burn_sound_a.o
|
||||
endif
|
||||
|
||||
|
||||
ifdef INCLUDE_CPLUSPLUS11_FILES
|
||||
alldir += cpu/mips3 cpu/tms34010 cpu/adsp2100
|
||||
depobj += ide.o cop0.o cop1.o mips3.o mips3_intf.o dcs2k.o midwayic.o midwunit.o tms34010.o tms34010_optable.o tms34010_intf.o \
|
||||
adsp2100.o adsp2100_intf.o
|
||||
ifdef BUILD_X64_EXE
|
||||
alldir += cpu/mips3/x64
|
||||
depobj += mips3_x64.o
|
||||
endif
|
||||
endif
|
||||
@@ -1,43 +0,0 @@
|
||||
alldir += burner burner/win32 dep/kaillera/client dep/libs/libpng dep/libs/lib7z dep/libs/zlib intf intf/video \
|
||||
intf/video/scalers intf/video/win32 intf/audio intf/audio/win32 intf/input intf/input/win32 intf/cd intf/cd/win32 \
|
||||
intf/perfcount intf/perfcount/win32 dep/generated
|
||||
|
||||
depobj += about.o bzip.o choose_monitor.o cona.o debugger.o drv.o d3dkmt_sync.o dynhuff.o fba_kaillera.o gameinfo.o image_win32.o \
|
||||
inpc.o inpcheat.o inpd.o inpdipsw.o inps.o ips_manager.o localise.o localise_download.o localise_gamelist.o main.o \
|
||||
media.o memcard.o menu.o misc_win32.o neocdlist.o neocdsel.o numdial.o paletteviewer.o placeholder.o popup_win32.o \
|
||||
progress.o replay.o res.o roms.o run.o scrn.o sel.o sfactd.o splash.o stated.o support_paths.o systeminfo.o wave.o \
|
||||
\
|
||||
conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \
|
||||
\
|
||||
adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o gzwrite.o infback.o inffast.o inflate.o inftrees.o \
|
||||
trees.o uncompr.o zutil.o \
|
||||
\
|
||||
png.o pngerror.o pngget.o pngmem.o pngpread.o pngread.o pngrio.o pngrtran.o pngrutil.o pngset.o pngtrans.o pngwio.o \
|
||||
pngwrite.o pngwtran.o pngwutil.o \
|
||||
\
|
||||
net.o \
|
||||
\
|
||||
aud_dsp.o aud_interface.o cd_interface.o inp_interface.o interface.o lowpass2.o prf_interface.o vid_interface.o \
|
||||
vid_softfx.o vid_support.o \
|
||||
\
|
||||
2xpm.o 2xsai.o ddt3x.o epx.o hq2xs.o hq2xs_16.o xbr.o \
|
||||
\
|
||||
aud_dsound3.o aud_xaudio2.o cd_isowav.o cdsound.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
|
||||
inp_dinput.o prf_performance_counter.o vid_d3d.o vid_ddraw.o vid_ddrawfx.o vid_directx9.o vid_directx_support.o
|
||||
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
depobj += un7z.o \
|
||||
\
|
||||
7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o 7zFile.o 7zStream.o Bcj2.o Bra.o Bra86.o BraIA64.o CpuArch.o \
|
||||
Delta.o LzmaDec.o Lzma2Dec.o Ppmd7.o Ppmd7Dec.o Sha256.o Xz.o XzCrc64.o XzCrc64Opt.o XzDec.o
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_AVI_RECORDING
|
||||
depobj += avi.o
|
||||
endif
|
||||
|
||||
autobj += $(depobj)
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
autobj += eagle_fm.o 2xsaimmx.o hq2x32.o hq3x32.o hq4x32.o superscale.o
|
||||
endif
|
||||
@@ -1,391 +0,0 @@
|
||||
DEBUG = 0
|
||||
LIBRETRO_OPTIMIZATIONS = 1
|
||||
FRONTEND_SUPPORTS_RGB565 = 1
|
||||
HAVE_GRIFFIN = 0
|
||||
|
||||
ifeq ($(platform),)
|
||||
platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
platform = win
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
platform = osx
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
platform = win
|
||||
endif
|
||||
endif
|
||||
|
||||
# system platform
|
||||
system_platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
system_platform = win
|
||||
EXE_EXT=.exe
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
system_platform = osx
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
system_platform = win
|
||||
endif
|
||||
|
||||
|
||||
MAIN_FBA_DIR := src
|
||||
FBA_BURN_DIR := $(MAIN_FBA_DIR)/burn
|
||||
FBA_BURN_DRIVERS_DIR := $(MAIN_FBA_DIR)/burn/drv
|
||||
FBA_BURNER_DIR := $(MAIN_FBA_DIR)/burner
|
||||
LIBRETRO_DIR := $(FBA_BURNER_DIR)/libretro
|
||||
FBA_CPU_DIR := $(MAIN_FBA_DIR)/cpu
|
||||
FBA_LIB_DIR := $(MAIN_FBA_DIR)/dep/libs
|
||||
FBA_INTERFACE_DIR := $(MAIN_FBA_DIR)/intf
|
||||
FBA_GENERATED_DIR = $(MAIN_FBA_DIR)/dep/generated
|
||||
FBA_SCRIPTS_DIR = $(MAIN_FBA_DIR)/dep/scripts
|
||||
GRIFFIN_DIR = griffin-libretro
|
||||
|
||||
EXTERNAL_ZLIB = 0
|
||||
|
||||
ifeq ($(platform), unix)
|
||||
TARGET := libretro.so
|
||||
fpic := -fPIC
|
||||
SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(LIBRETRO_DIR)/link.T
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
else ifeq ($(platform), osx)
|
||||
TARGET := libretro.dylib
|
||||
fpic := -fPIC
|
||||
SHARED := -dynamiclib
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
else ifeq ($(platform), ps3)
|
||||
TARGET := libretro_ps3.a
|
||||
CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
|
||||
CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe
|
||||
AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES += -D__CELLOS_LV2__
|
||||
EXTERNAL_ZLIB = 1
|
||||
else ifeq ($(platform), sncps3)
|
||||
TARGET := libretro_ps3.a
|
||||
CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
|
||||
CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
|
||||
AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES += -D__CELLOS_LV2__ -DSN_TARGET_PS3
|
||||
EXTERNAL_ZLIB = 1
|
||||
else ifeq ($(platform), psl1ght)
|
||||
TARGET := libretro_psl1ght.a
|
||||
CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
|
||||
CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT)
|
||||
AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES += -D__CELLOS_LV2__
|
||||
EXTERNAL_ZLIB = 1
|
||||
else ifeq ($(platform), xenon)
|
||||
TARGET := libretro_xenon360.a
|
||||
CC = xenon-gcc$(EXE_EXT)
|
||||
CXX = xenon-g++$(EXE_EXT)
|
||||
AR = xenon-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES := -D__LIBXENON__ -m32 -D__ppc__
|
||||
else ifeq ($(platform), ngc)
|
||||
TARGET := libretro_ngc.a
|
||||
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
|
||||
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES := -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float
|
||||
EXTERNAL_ZLIB = 1
|
||||
else ifeq ($(platform), wii)
|
||||
TARGET := libretro_wii.a
|
||||
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
|
||||
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
|
||||
ENDIANNESS_DEFINES = -DWORDS_BIGENDIAN
|
||||
PLATFORM_DEFINES := -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float
|
||||
EXTERNAL_ZLIB = 1
|
||||
else
|
||||
TARGET := retro.dll
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
SHARED := -shared -Wl,-no-undefined -Wl,--version-script=$(LIBRETRO_DIR)/link.T
|
||||
LDFLAGS += -static-libgcc -static-libstdc++
|
||||
ENDIANNESS_DEFINES := -DLSB_FIRST
|
||||
endif
|
||||
|
||||
CC_SYSTEM = gcc
|
||||
CXX_SYSTEM = g++
|
||||
|
||||
.PHONY: clean generate-files generate-files-clean clean-objs
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
BURN_BLACKLIST := $(FBA_BURNER_DIR)/un7z.cpp \
|
||||
$(FBA_CPU_DIR)/arm7/arm7exec.c \
|
||||
$(FBA_CPU_DIR)/arm7/arm7core.c \
|
||||
$(FBA_CPU_DIR)/hd6309/6309tbl.c \
|
||||
$(FBA_CPU_DIR)/hd6309/6309ops.c \
|
||||
$(FBA_CPU_DIR)/konami/konamtbl.c \
|
||||
$(FBA_CPU_DIR)/konami/konamops.c \
|
||||
$(FBA_CPU_DIR)/m68k/m68k_in.c \
|
||||
$(FBA_CPU_DIR)/m6800/6800ops.c \
|
||||
$(FBA_CPU_DIR)/m6800/6800tbl.c \
|
||||
$(FBA_CPU_DIR)/m6805/6805ops.c \
|
||||
$(FBA_CPU_DIR)/m6809/6809ops.c \
|
||||
$(FBA_CPU_DIR)/m6809/6809tbl.c \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2.cpp \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2-x86.cpp \
|
||||
$(FBA_CPU_DIR)/m68k/m68kmake.c \
|
||||
$(FBA_BURNER_DIR)/wave_writer.cpp \
|
||||
$(FBA_CPU_DIR)/m68k/m68kdasm.c \
|
||||
$(FBA_LIBRETRO_DIR)/menu.cpp \
|
||||
$(FBA_CPU_DIR)/sh2/mksh2.cpp \
|
||||
$(FBA_BURNER_DIR)/sshot.cpp \
|
||||
$(FBA_BURNER_DIR)/conc.cpp \
|
||||
$(FBA_BURNER_DIR)/dat.cpp \
|
||||
$(FBA_BURNER_DIR)/cong.cpp \
|
||||
$(FBA_BURNER_DIR)/image.cpp \
|
||||
$(FBA_BURNER_DIR)/misc.cpp \
|
||||
$(FBA_CPU_DIR)/h6280/tblh6280.c \
|
||||
$(FBA_CPU_DIR)/m6502/t65sc02.c \
|
||||
$(FBA_CPU_DIR)/m6502/t65c02.c \
|
||||
$(FBA_CPU_DIR)/m6502/tdeco16.c \
|
||||
$(FBA_CPU_DIR)/m6502/tn2a03.c \
|
||||
$(FBA_CPU_DIR)/m6502/t6502.c \
|
||||
$(FBA_CPU_DIR)/nec/v25sfr.c \
|
||||
$(FBA_CPU_DIR)/nec/v25instr.c \
|
||||
$(FBA_CPU_DIR)/nec/necinstr.c \
|
||||
$(FBA_BURN_DIR)/drv/capcom/ctv_make.cpp
|
||||
|
||||
#ifeq ($(LIBRETRO_OPTIMIZATIONS), 1)
|
||||
#BURN_BLACKLIST += $(FBA_BURN_DIR)/drv/capcom/ctv.cpp
|
||||
#endif
|
||||
|
||||
ifeq ($(EXTERNAL_ZLIB), 1)
|
||||
BURN_BLACKLIST += $(FBA_BURNER_DIR)/unzip.c \
|
||||
$(FBA_BURNER_DIR)/ioapi.c
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GRIFFIN), 1)
|
||||
GRIFFIN_CXXSRCFILES := $(GRIFFIN_DIR)/cps12.cpp $(GRIFFIN_DIR)/cps3.cpp $(GRIFFIN_DIR)/neogeo.cpp $(GRIFFIN_DIR)/pgm.cpp $(GRIFFIN_DIR)/snes.cpp $(GRIFFIN_DIR)/galaxian.cpp $(GRIFFIN_DIR)/cpu-m68k.cpp
|
||||
BURN_BLACKLIST += $(FBA_CPU_DIR)/m68000_intf.cpp
|
||||
else
|
||||
CPS2_DIR := $(FBA_BURN_DRIVERS_DIR)/capcom
|
||||
CPS3_DIR := $(FBA_BURN_DRIVERS_DIR)/cps3
|
||||
GALAXIAN_DIR := $(FBA_BURN_DRIVERS_DIR)/galaxian
|
||||
NEOGEO_DIR := $(FBA_BURN_DRIVERS_DIR)/neogeo
|
||||
PGM_DIR := $(FBA_BURN_DRIVERS_DIR)/pgm
|
||||
SNES_DIR := $(FBA_BURN_DRIVERS_DIR)/snes
|
||||
M68K_DIR := $(FBA_CPU_DIR)/m68k
|
||||
endif
|
||||
|
||||
FBA_BURN_DIRS := $(FBA_BURN_DIR) \
|
||||
$(FBA_BURN_DIR)/devices \
|
||||
$(FBA_BURN_DIR)/snd \
|
||||
$(CPS2_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/cave \
|
||||
$(CPS3_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/dataeast \
|
||||
$(GALAXIAN_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/irem \
|
||||
$(FBA_BURN_DRIVERS_DIR)/konami \
|
||||
$(FBA_BURN_DRIVERS_DIR)/megadrive \
|
||||
$(NEOGEO_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/pce \
|
||||
$(PGM_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/pre90s \
|
||||
$(FBA_BURN_DRIVERS_DIR)/psikyo \
|
||||
$(FBA_BURN_DRIVERS_DIR)/pst90s \
|
||||
$(FBA_BURN_DRIVERS_DIR)/sega \
|
||||
$(SNES_DIR) \
|
||||
$(FBA_BURN_DRIVERS_DIR)/taito \
|
||||
$(FBA_BURN_DRIVERS_DIR)/toaplan
|
||||
|
||||
FBA_CPU_DIRS := $(FBA_CPU_DIR) \
|
||||
$(FBA_CPU_DIR)/arm \
|
||||
$(FBA_CPU_DIR)/arm7 \
|
||||
$(FBA_CPU_DIR)/h6280 \
|
||||
$(FBA_CPU_DIR)/hd6309 \
|
||||
$(FBA_CPU_DIR)/i8039 \
|
||||
$(FBA_CPU_DIR)/konami \
|
||||
$(M68K_DIR) \
|
||||
$(FBA_CPU_DIR)/m6502 \
|
||||
$(FBA_CPU_DIR)/m6800 \
|
||||
$(FBA_CPU_DIR)/m6805 \
|
||||
$(FBA_CPU_DIR)/m6809 \
|
||||
$(FBA_CPU_DIR)/nec \
|
||||
$(FBA_CPU_DIR)/s2650 \
|
||||
$(FBA_CPU_DIR)/sh2 \
|
||||
$(FBA_CPU_DIR)/z80
|
||||
|
||||
FBA_LIB_DIRS := $(FBA_LIB_DIR)/zlib
|
||||
|
||||
FBA_SRC_DIRS := $(FBA_BURNER_DIR) $(FBA_BURN_DIRS) $(FBA_CPU_DIRS) $(FBA_BURNER_DIRS)
|
||||
|
||||
|
||||
ifeq ($(EXTERNAL_ZLIB), 1)
|
||||
FBA_DEFINES += -DEXTERNAL_ZLIB
|
||||
else
|
||||
FBA_SRC_DIRS += $(FBA_LIB_DIRS)
|
||||
endif
|
||||
|
||||
FBA_CXXSRCS := $(GRIFFIN_CXXSRCFILES) $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.cpp)))
|
||||
FBA_CXXSRCS += $(LIBRETRO_DIR)/libretro.cpp $(LIBRETRO_DIR)/neocdlist.cpp
|
||||
FBA_CXXOBJ := $(FBA_CXXSRCS:.cpp=.o)
|
||||
FBA_CSRCS := $(filter-out $(BURN_BLACKLIST),$(foreach dir,$(FBA_SRC_DIRS),$(wildcard $(dir)/*.c)))
|
||||
FBA_COBJ := $(FBA_CSRCS:.c=.o)
|
||||
|
||||
OBJS := $(FBA_COBJ) $(FBA_CXXOBJ)
|
||||
|
||||
FBA_DEFINES := -DUSE_SPEEDHACKS -D__LIBRETRO__ \
|
||||
-D__LIBRETRO_OPTIMIZATIONS__ \
|
||||
$(ENDIANNESS_DEFINES) \
|
||||
$(PLATFORM_DEFINES) \
|
||||
-DINLINE="static inline" \
|
||||
-DSH2_INLINE="static inline"
|
||||
|
||||
INCDIRS := -I$(FBA_BURNER_DIR)/win32 \
|
||||
-I$(LIBRETRO_DIR) \
|
||||
-I$(LIBRETRO_DIR)/tchar \
|
||||
-I$(FBA_BURN_DIR) \
|
||||
-I$(MAIN_FBA_DIR)/cpu \
|
||||
-I$(FBA_BURN_DIR)/snd \
|
||||
-I$(FBA_BURN_DIR)/devices \
|
||||
-I$(FBA_INTERFACE_DIR) \
|
||||
-I$(FBA_INTERFACE_DIR)/input \
|
||||
-I$(FBA_INTERFACE_DIR)/cd \
|
||||
-I$(FBA_BURNER_DIR) \
|
||||
-I$(FBA_CPU_DIR) \
|
||||
-I$(FBA_CPU_DIR)/i8039 \
|
||||
-I$(FBA_LIB_DIR)/zlib \
|
||||
-I$(FBA_BURN_DIR)/drv/capcom \
|
||||
-I$(FBA_BURN_DIR)/drv/dataeast \
|
||||
-I$(FBA_BURN_DIR)/drv/cave \
|
||||
-I$(FBA_BURN_DIR)/drv/neogeo \
|
||||
-I$(FBA_BURN_DIR)/drv/psikyo \
|
||||
-I$(FBA_BURN_DIR)/drv/sega \
|
||||
-I$(FBA_BURN_DIR)/drv/toaplan \
|
||||
-I$(FBA_BURN_DIR)/drv/taito \
|
||||
-I$(FBA_GENERATED_DIR) \
|
||||
-I$(FBA_LIB_DIR)
|
||||
|
||||
ifeq ($(LIBRETRO_OPTIMIZATIONS), 1)
|
||||
FBA_DEFINES += -D__LIBRETRO_OPTIMIZATIONS__
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
CXXFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3 -DNDEBUG
|
||||
CXXFLAGS += -O3 -DNDEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(platform), sncps3)
|
||||
WARNINGS_DEFINES =
|
||||
else
|
||||
WARNINGS_DEFINES = -Wno-write-strings
|
||||
C_STD_DEFINES = -std=gnu99
|
||||
endif
|
||||
|
||||
CFLAGS += $(C_STD_DEFINES) $(fpic) $(WARNINGS_DEFINES) $(FBA_DEFINES)
|
||||
CXXFLAGS += $(fpic) $(WARNINGS_DEFINES) $(FBA_DEFINES)
|
||||
LDFLAGS += $(fpic)
|
||||
|
||||
ifeq ($(FRONTEND_SUPPORTS_RGB565), 1)
|
||||
CFLAGS += -DFRONTEND_SUPPORTS_RGB565
|
||||
CXXFLAGS += -DFRONTEND_SUPPORTS_RGB565
|
||||
endif
|
||||
|
||||
ifeq ($(ZLIB_INTERNAL), 0)
|
||||
INCDIRS += -I$(FBA_LIB_DIR)
|
||||
endif
|
||||
|
||||
ifeq ($(LIBRETRO_OPTIMIZATIONS), 1)
|
||||
GENERATE_OPTS := -D__LIBRETRO_OPTIMIZATIONS__
|
||||
else
|
||||
GENERATE_OPTS :=
|
||||
endif
|
||||
|
||||
PERL = perl$(EXE_EXT)
|
||||
M68KMAKE_EXE = m68kmake$(EXE_EXT)
|
||||
CTVMAKE_EXE = ctvmake$(EXE_EXT)
|
||||
PGM_SPRITE_CREATE_EXE = pgmspritecreate$(EXE_EXT)
|
||||
EXE_PREFIX = ./
|
||||
|
||||
generate-files-clean:
|
||||
rm -rf $(FBA_GENERATED_DIR)/
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kopac.c
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kopdm.c
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kopnz.c
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kops.c
|
||||
rm -rf $(FBA_CPU_DIR)/m68k/m68kops.h
|
||||
|
||||
generate-files:
|
||||
@mkdir -p $(FBA_GENERATED_DIR) 2>/dev/null || /bin/true
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/driverlist.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/gamelist.pl -o $(FBA_GENERATED_DIR)/driverlist.h -l gamelist.txt $(FBA_BURN_DRIVERS_DIR)/capcom $(FBA_BURN_DRIVERS_DIR)/cave $(FBA_BURN_DRIVERS_DIR)/cps3 $(FBA_BURN_DRIVERS_DIR)/dataeast $(FBA_BURN_DRIVERS_DIR)/galaxian $(FBA_BURN_DRIVERS_DIR)/irem $(FBA_BURN_DRIVERS_DIR)/konami $(FBA_BURN_DRIVERS_DIR)/megadrive $(FBA_BURN_DRIVERS_DIR)/neogeo $(FBA_BURN_DRIVERS_DIR)/pce $(FBA_BURN_DRIVERS_DIR)/pgm $(FBA_BURN_DRIVERS_DIR)/pre90s $(FBA_BURN_DRIVERS_DIR)/psikyo $(FBA_BURN_DRIVERS_DIR)/pst90s $(FBA_BURN_DRIVERS_DIR)/sega $(FBA_BURN_DRIVERS_DIR)/snes $(FBA_BURN_DRIVERS_DIR)/taito $(FBA_BURN_DRIVERS_DIR)/toaplan
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/neo_sprite_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/neo_sprite_func_table.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/neo_sprite_func.pl -o $(FBA_GENERATED_DIR)/neo_sprite_func.h $(LIBRETRO_OPTIMIZATIONS)
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/psikyo_tile_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/psikyo_tile_func_table.h..."
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/psikyo_tile_func.pl -o $(FBA_GENERATED_DIR)/psikyo_tile_func.h
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/cave_sprite_func.h..."
|
||||
@echo ""
|
||||
@echo "Generating[ $(FBA_GENERATED_DIR)/cave_tile_func_table.h"
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/cave_sprite_func.pl -o $(FBA_GENERATED_DIR)/cave_sprite_func.h
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/cave_tile_func.pl -o $(FBA_GENERATED_DIR)/cave_tile_func.h
|
||||
@echo ""
|
||||
@echo "Generate $(FBA_GENERATED_DIR)/toa_gp9001_func_table.h"
|
||||
@echo ""
|
||||
$(PERL) $(FBA_SCRIPTS_DIR)/toa_gp9001_func.pl -o $(FBA_GENERATED_DIR)/toa_gp9001_func.h
|
||||
$(CXX_SYSTEM) $(GENERATE_OPTS) -o $(PGM_SPRITE_CREATE_EXE) $(FBA_BURN_DRIVERS_DIR)/pgm/pgm_sprite_create.cpp
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/pgm_sprite.h..."
|
||||
@echo ""
|
||||
$(EXE_PREFIX)$(PGM_SPRITE_CREATE_EXE) > $(FBA_GENERATED_DIR)/pgm_sprite.h
|
||||
$(CC_SYSTEM) $(GENERATE_OPTS) -o $(M68KMAKE_EXE) $(FBA_CPU_DIR)/m68k/m68kmake.c
|
||||
$(EXE_PREFIX)$(M68KMAKE_EXE) $(FBA_CPU_DIR)/m68k/ $(FBA_CPU_DIR)/m68k/m68k_in.c
|
||||
$(CXX_SYSTEM) $(GENERATE_OPTS) -o $(CTVMAKE_EXE) $(FBA_BURN_DRIVERS_DIR)/capcom/ctv_make.cpp
|
||||
@echo ""
|
||||
@echo "Generating $(FBA_GENERATED_DIR)/ctv.h..."
|
||||
@echo ""
|
||||
$(EXE_PREFIX)$(CTVMAKE_EXE) > $(FBA_GENERATED_DIR)/ctv.h
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@echo "LD $@"
|
||||
ifeq ($(platform), ps3)
|
||||
@$(AR) rcs $@ $(OBJS)
|
||||
else ifeq ($(platform), sncps3)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
else ifeq ($(platform), psl1ght)
|
||||
$(AR) rcs $@ $(OBJS)
|
||||
else ifeq ($(platform), xenon)
|
||||
@$(AR) rcs $@ $(OBJS)
|
||||
else ifeq ($(platform), ngc)
|
||||
@$(AR) rcs $@ $(OBJS)
|
||||
else ifeq ($(platform), wii)
|
||||
@$(AR) rcs $@ $(OBJS)
|
||||
else
|
||||
@$(CXX) -o $@ $(SHARED) $(OBJS) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
%.o: %.cpp
|
||||
@echo "CXX $<"
|
||||
@$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS)
|
||||
|
||||
%.o: %.c
|
||||
@echo "CC $<"
|
||||
@$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS)
|
||||
|
||||
clean-objs:
|
||||
rm -f $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
rm -f $(OBJS)
|
||||
rm -f $(M68KMAKE_EXE)
|
||||
rm -f $(PGM_SPRITE_CREATE_EXE)
|
||||
rm -f $(CTVMAKE_EXE)
|
||||
@@ -1,673 +0,0 @@
|
||||
# Makefile for FBA, for use with GNU make & GCC (MinGW)
|
||||
#
|
||||
# The first pass makes sure all intermediary targets are present. The second pass updates
|
||||
# any targets, if necessary. (Intermediary) targets which have their own unique rules
|
||||
# are generated as required.
|
||||
|
||||
unexport
|
||||
|
||||
#
|
||||
# Flags. Uncomment any of these declarations to enable their function.
|
||||
#
|
||||
|
||||
# Check for changes in header files
|
||||
DEPEND = 1
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Declare variables
|
||||
#
|
||||
|
||||
# Specify the name of the executable file, without ".exe"
|
||||
NAME = fba
|
||||
COMPILENAME = 3
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
ifdef BUILD_A68K
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
ifdef BUILD_X86_ASM
|
||||
undefine BUILD_X86_ASM
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
|
||||
ifndef CPUTYPE
|
||||
CPUTYPE = i686
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
MMX = 1
|
||||
else
|
||||
MMX = 0
|
||||
endif
|
||||
|
||||
ifndef BUILD_X86_ASM
|
||||
NAME := $(NAME)x
|
||||
COMPILENAME := $(COMPILENAME)x
|
||||
endif
|
||||
ifdef BUILD_X64_EXE
|
||||
NAME = fba64
|
||||
COMPILENAME = 6
|
||||
endif
|
||||
ifdef DEBUG
|
||||
NAME := $(NAME)d
|
||||
COMPILENAME := $(COMPILENAME)d
|
||||
endif
|
||||
ifdef SYMBOL
|
||||
NAME := $(NAME)s
|
||||
COMPILENAME := $(COMPILENAME)s
|
||||
endif
|
||||
ifndef UNICODE
|
||||
NAME := $(NAME)a
|
||||
COMPILENAME := $(COMPILENAME)a
|
||||
endif
|
||||
|
||||
ifeq ($(CPUTYPE),i686)
|
||||
ppro = ppro
|
||||
else
|
||||
NAME := $(NAME)$(CPUTYPE)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Specify paths/files
|
||||
#
|
||||
|
||||
|
||||
objdir = obj/$(COMPILENAME)/
|
||||
|
||||
|
||||
srcdir = src/
|
||||
|
||||
include makefile.burn_rules
|
||||
include makefile.burner_win32_rules
|
||||
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/mingw/include -I$(srcdir)dep/mingw/include/directx9 -I$(srcdir)dep/mingw/include/xaudio2
|
||||
|
||||
|
||||
ifdef UNICODE
|
||||
# lib = -lunicows
|
||||
endif
|
||||
|
||||
lib += -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lshell32 -lwinmm -lshlwapi -ladvapi32 -lsetupapi -lole32 -luuid -lwininet
|
||||
|
||||
|
||||
depobj += resource.o \
|
||||
|
||||
autdep = $(depobj:.o=.d)
|
||||
drvdep = $(drvsrc:.o=.d)
|
||||
|
||||
ifdef BUILD_A68K
|
||||
a68k.o = $(objdir)cpu/a68k/a68k.o
|
||||
endif
|
||||
|
||||
app_gnuc.rc = $(srcdir)dep/generated/app_gnuc.rc
|
||||
license.rtf = $(srcdir)dep/generated/license.rtf
|
||||
driverlist.h = $(srcdir)dep/generated/driverlist.h
|
||||
ctv.h = $(srcdir)dep/generated/ctv.h
|
||||
toa_gp9001_func.h = $(srcdir)dep/generated/toa_gp9001_func.h
|
||||
neo_sprite_func.h = $(srcdir)dep/generated/neo_sprite_func.h
|
||||
cave_tile_func.h = $(srcdir)dep/generated/cave_tile_func.h
|
||||
cave_sprite_func.h = $(srcdir)dep/generated/cave_sprite_func.h
|
||||
psikyo_tile_func.h = $(srcdir)dep/generated/psikyo_tile_func.h
|
||||
pgm_sprite.h = $(srcdir)dep/generated/pgm_sprite.h
|
||||
build_details.h = $(srcdir)dep/generated/build_details.h
|
||||
|
||||
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kops.o \
|
||||
$(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.asm), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
ifdef BUILD_A68K
|
||||
allobj += $(a68k.o)
|
||||
endif
|
||||
|
||||
alldep = $(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.d,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
autdrv := $(drvsrc:.cpp=.o)
|
||||
|
||||
#
|
||||
#
|
||||
# Specify compiler/linker/assembler
|
||||
#
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
LD = $(CXX)
|
||||
AS = nasm
|
||||
|
||||
LDFLAGS = -static
|
||||
|
||||
CFLAGS = -pipe \
|
||||
-std=gnu99 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
-Wno-sequence-point \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
CXXFLAGS = -pipe \
|
||||
-std=gnu++11 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations -fcheck-new \
|
||||
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
|
||||
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
|
||||
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
|
||||
-Wno-unused-but-set-variable -Wno-sequence-point -Wno-narrowing -Wno-extra \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
CFLAGS += -m64
|
||||
CXXFLAGS += -m64
|
||||
LDFLAGS += -m64
|
||||
else
|
||||
CFLAGS += -m32
|
||||
CXXFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
endif
|
||||
|
||||
ASFLAGS = -O1 -f coff -w-orphan-labels
|
||||
|
||||
# D3DUtils & D3DMath need these
|
||||
# DEF = -Dsinf=\(float\)sin -Dcosf=\(float\)cos -Dasinf=\(float\)asin -Dacosf=\(float\)acos -Dsqrtf=\(float\)sqrt
|
||||
|
||||
DEF := -DBUILD_WIN32 -DUSE_SPEEDHACKS -DFILENAME=$(NAME) -DMMX=$(MMX)
|
||||
|
||||
ifdef UNICODE
|
||||
DEF := $(DEF) -D_UNICODE
|
||||
endif
|
||||
|
||||
ifdef SPECIALBUILD
|
||||
DEF := $(DEF) -DSPECIALBUILD=$(SPECIALBUILD)
|
||||
endif
|
||||
|
||||
ifdef FASTCALL
|
||||
DEF := $(DEF) -DFASTCALL
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
DEF := $(DEF) -DFBA_DEBUG
|
||||
endif
|
||||
|
||||
ifdef ROM_VERIFY
|
||||
DEF := $(DEF) -DROM_VERIFY
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) -DINCLUDE_7Z_SUPPORT
|
||||
endif
|
||||
|
||||
ifdef LSB_FIRST
|
||||
DEF := $(DEF) -DLSB_FIRST
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_LIB_PNGH
|
||||
DEF := $(DEF) -DINCLUDE_LIB_PNGH
|
||||
endif
|
||||
|
||||
ifdef BUILD_A68K
|
||||
DEF := $(DEF) -DBUILD_A68K
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
DEF := $(DEF) -DBUILD_X86_ASM
|
||||
endif
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
DEF := $(DEF) -DBUILD_X64_EXE
|
||||
ifdef INCLUDE_CPLUSPLUS11_FILES
|
||||
DEF := $(DEF) -DXBYAK_NO_OP_NAMES -DMIPS3_X64_DRC
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef USE_SEGOE
|
||||
DEF := $(DEF) -DUSE_SEGOE
|
||||
endif
|
||||
|
||||
ifdef SYMBOL
|
||||
|
||||
CFLAGS += -ggdb3
|
||||
ASFLAGS += -g
|
||||
DEF := $(DEF) -D_DEBUG
|
||||
|
||||
ifdef PROFILE
|
||||
CFLAGS += -pg
|
||||
CXXFLAGS += -pg
|
||||
else
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
CXXFLAGS += -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
else
|
||||
LDFLAGS += -s
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
CFLAGS += -mmmx
|
||||
CXXFLAGS += -mmmx
|
||||
endif
|
||||
|
||||
# For zlib
|
||||
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=32
|
||||
|
||||
# For lib7z
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) -D_7ZIP_PPMD_SUPPPORT
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Specify paths
|
||||
#
|
||||
#
|
||||
|
||||
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
|
||||
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
vpath %.d $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
|
||||
#
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
#
|
||||
|
||||
.PHONY: all init cleandep touch clean
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef DEPEND
|
||||
|
||||
all: init $(drvdep) $(autdep) $(autobj) $(autdrv)
|
||||
@$(MAKE) -f makefile.mamemingw -s GCC471=1
|
||||
|
||||
else
|
||||
|
||||
all: init $(autobj) $(autdrv)
|
||||
|
||||
@$(MAKE) -f makefile.mamemingw -s GCC471=1
|
||||
|
||||
|
||||
endif
|
||||
else
|
||||
|
||||
all: $(NAME).exe
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Rule for linking the executable
|
||||
#
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
|
||||
$(objdir)/drivers.o: $(autdrv)
|
||||
@echo Linking drivers...
|
||||
ifdef BUILD_X64_EXE
|
||||
@$(LD) -m64 -r -nostdlib -o $@ $^
|
||||
else
|
||||
@$(LD) -m32 -r -nostdlib -o $@ $^
|
||||
endif
|
||||
|
||||
$(NAME).exe: $(allobj) $(objdir)/drivers.o
|
||||
@echo
|
||||
@echo Linking executable... $(NAME).exe
|
||||
@$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
|
||||
|
||||
ifdef DEBUG
|
||||
|
||||
# Don't compress when making a debug build
|
||||
|
||||
else
|
||||
ifdef COMPRESS
|
||||
@upx --best $@
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef FORCE_UPDATE
|
||||
$(build_details.h): FORCE
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate the gamelist
|
||||
#
|
||||
|
||||
burn.o burn.d: driverlist.h
|
||||
|
||||
$(driverlist.h): $(drvsrc) $(srcdir)dep/scripts/gamelist.pl
|
||||
ifdef PERL
|
||||
@$(srcdir)dep/scripts/gamelist.pl -o $@ -l gamelist.txt \
|
||||
$(filter %.cpp,$(foreach file,$(drvsrc:.o=.cpp),$(foreach dir,$(alldir), \
|
||||
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Verify if driverlist.h needs to be updated
|
||||
#
|
||||
|
||||
#ifeq ($(MAKELEVEL),1)
|
||||
#ifdef FORCE_UPDATE
|
||||
#$(driverlist.h): FORCE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#
|
||||
# Fix the .rc file
|
||||
#
|
||||
|
||||
resource.o resource.d: $(app_gnuc.rc) string.rc version.rc version.h $(build_details.h)
|
||||
|
||||
$(license.rtf): $(srcdir)license.txt $(srcdir)dep/scripts/license2rtf.pl
|
||||
|
||||
ifdef PERL
|
||||
ifdef USE_SEGOE
|
||||
@$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf) -f 'Segoe UI'
|
||||
else
|
||||
@$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf)
|
||||
endif
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
$(app_gnuc.rc): app.rc $(license.rc) $(license.rtf) $(srcdir)dep/scripts/fixrc.pl $(srcdir)burner/resource/fba.ico $(srcdir)burner/resource/about.bmp $(srcdir)burner/resource/splash.bmp $(srcdir)burner/resource/misc.bmp
|
||||
|
||||
ifdef PERL
|
||||
@$(srcdir)dep/scripts/fixrc.pl $< -o $@
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate some info on the build details
|
||||
#
|
||||
|
||||
about.o about.d: $(build_details.h)
|
||||
|
||||
$(build_details.h): $(srcdir)dep/scripts/build_details.cpp
|
||||
$(CXX) -mconsole $(CXXFLAGS) $(LDFLAGS) $< -o $(objdir)/dep/generated/build_details.exe
|
||||
obj\\$(COMPILENAME)\\dep\\generated\\build_details.exe >$@
|
||||
|
||||
#
|
||||
# Compile 68000 cores
|
||||
#
|
||||
|
||||
# A68K
|
||||
|
||||
ifdef BUILD_A68K
|
||||
$(a68k.o): fba_make68k.c
|
||||
@echo Compiling A68K MC68000 core...
|
||||
@$(CC) -mconsole $(CFLAGS) $(LDFLAGS) -DWIN32 -Wno-unused -Wno-conversion -Wno-missing-prototypes \
|
||||
-s $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe)
|
||||
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) \
|
||||
$(@D)/a68k_tab.asm 00 $(ppro)
|
||||
@echo Assembling A68K MC68000 core...
|
||||
@$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
|
||||
endif
|
||||
|
||||
# Musashi
|
||||
|
||||
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)dep/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kcpu.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(srcdir)cpu/m68k/m68kcpu.c -o $(objdir)cpu/m68k/m68kcpu.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kops.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopac.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopac.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kopac.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kopac.c -o $(objdir)cpu/m68k/m68kopac.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopdm.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopdm.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kopdm.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kopdm.c -o $(objdir)cpu/m68k/m68kopdm.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopnz.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopnz.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kopnz.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kopnz.c -o $(objdir)cpu/m68k/m68kopnz.o
|
||||
|
||||
$(objdir)dep/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake.exe $(srcdir)cpu/m68k/m68k_in.c
|
||||
$(objdir)/cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
|
||||
|
||||
$(objdir)cpu/m68k/m68kmake.exe: $(srcdir)cpu/m68k/m68kmake.c
|
||||
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...
|
||||
@$(CC) $(CFLAGS) $(srcdir)cpu/m68k/m68kmake.c -o $(objdir)cpu/m68k/m68kmake.exe
|
||||
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cvt.h, needed by ctv.cpp
|
||||
#
|
||||
|
||||
ctv.d ctv.o: $(ctv.h)
|
||||
|
||||
$(ctv.h): ctv_make.cpp
|
||||
echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
$(CC) -mconsole $(CXXFLAGS) $(LDFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe)
|
||||
obj\\$(COMPILENAME)\\burn\\drv\\capcom\\ctv_make.exe >$@
|
||||
|
||||
#
|
||||
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
|
||||
#
|
||||
|
||||
toa_bcu2.d toa_bcu2.o toa_gp9001.d toa_gp9001.o: $(toa_gp9001_func.h)
|
||||
|
||||
$(toa_gp9001_func.h): $(srcdir)dep/scripts/toa_gp9001_func.pl
|
||||
@$(srcdir)dep/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
|
||||
#
|
||||
|
||||
neo_sprite.d neo_sprite.o: $(neo_sprite_func.h)
|
||||
|
||||
$(neo_sprite_func.h): $(srcdir)dep/scripts/neo_sprite_func.pl
|
||||
@$(srcdir)dep/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
|
||||
#
|
||||
|
||||
cave_tile.d cave_tile.o: $(cave_tile_func.h)
|
||||
|
||||
$(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
|
||||
@$(srcdir)dep/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
|
||||
#
|
||||
|
||||
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
|
||||
|
||||
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
|
||||
@$(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
|
||||
#
|
||||
|
||||
psikyo_tile.d psikyo_tile.o psikyosprite.d psikyo_sprite.o: $(psikyo_tile_func.h)
|
||||
|
||||
$(psikyo_tile_func.h): $(srcdir)dep/scripts/psikyo_tile_func.pl
|
||||
$(srcdir)dep/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file pgm_sprite.h, needed by pgm_draw.cpp
|
||||
#
|
||||
|
||||
pgm_draw.d pgm_draw.o: $(pgm_sprite.h)
|
||||
|
||||
$(pgm_sprite.h): pgm_sprite_create.cpp
|
||||
echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
$(CC) -mconsole $(CXXFLAGS) $(LDFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe)
|
||||
obj\\$(COMPILENAME)\\burn\\drv\\pgm\\pgm_sprite_create.exe >$@
|
||||
|
||||
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
ifdef DEPEND
|
||||
|
||||
include $(alldep)
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generic rule for resource files
|
||||
#
|
||||
|
||||
%.o: %.rc
|
||||
@echo Compiling resource file $(<F)...
|
||||
ifdef BUILD_X64_EXE
|
||||
@windres -F pe-x86-64 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
else
|
||||
@windres -F pe-i386 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Generic rules for C/C++ files
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
|
||||
%.o: %.cpp
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
else
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $@
|
||||
|
||||
%.o:
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate dependencies for C/C++ files
|
||||
#
|
||||
|
||||
ifdef DEPEND
|
||||
|
||||
%.d: %.c
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.cpp
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.rc
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Phony targets
|
||||
#
|
||||
|
||||
init:
|
||||
|
||||
ifdef DEBUG
|
||||
echo Making debug build...
|
||||
else
|
||||
@echo Making normal build...
|
||||
endif
|
||||
@echo
|
||||
@mingw-mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
|
||||
@mingw-mkdir -p $(srcdir)dep/generated
|
||||
|
||||
cleandep:
|
||||
@echo Removing depend files from $(objdir)...
|
||||
-@for dir in $(alldir); do rm -f $(objdir)$$dir/*.d; done
|
||||
|
||||
touch:
|
||||
@echo Marking all targets for $(NAME) as uptodate...
|
||||
-@touch $(NAME).exe
|
||||
-@touch -c -r $(NAME).exe $(srcdir)/dep/generated/*
|
||||
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
|
||||
|
||||
clean:
|
||||
@echo Removing all files from $(objdir)...
|
||||
-@rm -f -r $(objdir)
|
||||
-@rm -f -r $(ctv.h)
|
||||
|
||||
ifdef PERL
|
||||
@echo Removing all files generated with perl scripts...
|
||||
-@rm -f -r $(app_gnuc.rc) $(driverlist)
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Rule to force recompilation of any target that depends on it
|
||||
#
|
||||
|
||||
FORCE:
|
||||
-807
@@ -1,807 +0,0 @@
|
||||
# Makefile for FBA, for use with GNU make & GCC (MinGW)
|
||||
#
|
||||
# The first pass makes sure all intermediary targets are present. The second pass updates
|
||||
# any targets, if necessary. (Intermediary) targets which have their own unique rules
|
||||
# are generated as required.
|
||||
|
||||
unexport
|
||||
|
||||
#
|
||||
# Flags. Uncomment any of these declarations to enable their function.
|
||||
#
|
||||
|
||||
# Check for changes in header files
|
||||
DEPEND = 1
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Declare variables
|
||||
#
|
||||
|
||||
# Specify the name of the executable file, without ".exe"
|
||||
NAME = fba
|
||||
COMPILENAME = 3
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
ifdef BUILD_A68K
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
ifdef BUILD_X86_ASM
|
||||
undefine BUILD_X86_ASM
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
|
||||
ifndef CPUTYPE
|
||||
CPUTYPE = i686
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
MMX = 1
|
||||
else
|
||||
MMX = 0
|
||||
endif
|
||||
|
||||
ifndef BUILD_X86_ASM
|
||||
NAME := $(NAME)x
|
||||
COMPILENAME := $(COMPILENAME)x
|
||||
endif
|
||||
ifdef BUILD_X64_EXE
|
||||
NAME = fba64
|
||||
COMPILENAME = 6
|
||||
endif
|
||||
ifdef DEBUG
|
||||
NAME := $(NAME)d
|
||||
COMPILENAME := $(COMPILENAME)d
|
||||
endif
|
||||
ifdef SYMBOL
|
||||
NAME := $(NAME)s
|
||||
COMPILENAME := $(COMPILENAME)s
|
||||
endif
|
||||
ifndef UNICODE
|
||||
NAME := $(NAME)a
|
||||
COMPILENAME := $(COMPILENAME)a
|
||||
endif
|
||||
|
||||
ifeq ($(CPUTYPE),i686)
|
||||
ppro = ppro
|
||||
else
|
||||
NAME := $(NAME)$(CPUTYPE)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Specify paths/files
|
||||
#
|
||||
|
||||
ifdef GCC345
|
||||
objdir = obj/34/$(COMPILENAME)/
|
||||
endif
|
||||
ifdef GCC452
|
||||
objdir = obj/45/$(COMPILENAME)/
|
||||
endif
|
||||
ifdef GCC471
|
||||
objdir = obj/47/$(COMPILENAME)/
|
||||
endif
|
||||
ifdef GCC510
|
||||
objdir = obj/51/$(COMPILENAME)/
|
||||
endif
|
||||
|
||||
srcdir = src/
|
||||
|
||||
include makefile.burn_rules
|
||||
include makefile.burner_win32_rules
|
||||
|
||||
ifdef GCC345
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/mingw/include -I- -I$(srcdir)dep/mingw/include/directx9 -I$(srcdir)dep/mingw/include/xaudio2
|
||||
endif
|
||||
ifdef GCC452
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/mingw/include -I$(srcdir)dep/mingw/include/directx9 -I$(srcdir)dep/mingw/include/xaudio2
|
||||
endif
|
||||
ifdef GCC471
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/mingw/include -I$(srcdir)dep/mingw/include/directx9 -I$(srcdir)dep/mingw/include/xaudio2
|
||||
endif
|
||||
ifdef GCC510
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/mingw/include -I$(srcdir)dep/mingw/include/directx9 -I$(srcdir)dep/mingw/include/xaudio2
|
||||
endif
|
||||
|
||||
ifdef UNICODE
|
||||
# lib = -lunicows
|
||||
endif
|
||||
|
||||
lib += -luser32 -lgdi32 -lcomdlg32 -lcomctl32 -lshell32 -lwinmm -lshlwapi -ladvapi32 -lsetupapi -lole32 -luuid -lwininet
|
||||
|
||||
ifdef INCLUDE_AVI_RECORDING
|
||||
lib += -lvfw32
|
||||
endif
|
||||
|
||||
|
||||
depobj += resource.o \
|
||||
|
||||
autdep = $(depobj:.o=.d)
|
||||
drvdep = $(drvsrc:.o=.d)
|
||||
|
||||
ifdef BUILD_A68K
|
||||
a68k.o = $(objdir)cpu/a68k/a68k.o
|
||||
endif
|
||||
|
||||
app_gnuc.rc = $(srcdir)dep/generated/app_gnuc.rc
|
||||
license.rtf = $(srcdir)dep/generated/license.rtf
|
||||
driverlist.h = $(srcdir)dep/generated/driverlist.h
|
||||
ctv.h = $(srcdir)dep/generated/ctv.h
|
||||
toa_gp9001_func.h = $(srcdir)dep/generated/toa_gp9001_func.h
|
||||
neo_sprite_func.h = $(srcdir)dep/generated/neo_sprite_func.h
|
||||
cave_tile_func.h = $(srcdir)dep/generated/cave_tile_func.h
|
||||
cave_sprite_func.h = $(srcdir)dep/generated/cave_sprite_func.h
|
||||
psikyo_tile_func.h = $(srcdir)dep/generated/psikyo_tile_func.h
|
||||
pgm_sprite.h = $(srcdir)dep/generated/pgm_sprite.h
|
||||
build_details.h = $(srcdir)dep/generated/build_details.h
|
||||
|
||||
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kops.o \
|
||||
$(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.asm), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
ifdef BUILD_A68K
|
||||
allobj += $(a68k.o)
|
||||
endif
|
||||
|
||||
alldep = $(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.d,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
autdrv := $(drvsrc:.cpp=.o)
|
||||
|
||||
#
|
||||
#
|
||||
# Specify compiler/linker/assembler
|
||||
#
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
LD = $(CXX)
|
||||
AS = nasm
|
||||
|
||||
LDFLAGS = -static
|
||||
|
||||
ifdef GCC345
|
||||
CFLAGS = -pipe \
|
||||
-std=gnu99 -march=$(CPUTYPE) -O1 \
|
||||
-mno-cygwin -mwindows \
|
||||
-fforce-mem -fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-freduce-all-givs -fmove-all-movables -fexpensive-optimizations \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
CXXFLAGS = -pipe \
|
||||
-march=$(CPUTYPE) -O1 \
|
||||
-mno-cygwin -mwindows \
|
||||
-fforce-mem -fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-freduce-all-givs -fmove-all-movables -fexpensive-optimizations \
|
||||
-fcheck-new \
|
||||
-Wall -W -pedantic -Wno-long-long \
|
||||
-Wunknown-pragmas -Wundef -Wconversion -Wno-missing-braces \
|
||||
-Wuninitialized -Wpointer-arith -Winline -Wno-multichar \
|
||||
$(DEF) $(incdir)
|
||||
endif
|
||||
ifdef GCC452
|
||||
CFLAGS = -pipe \
|
||||
-std=gnu99 -march=$(CPUTYPE) -O1 \
|
||||
-mno-cygwin -mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
-Wno-sequence-point \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
CXXFLAGS = -pipe \
|
||||
-march=$(CPUTYPE) -O1 \
|
||||
-mno-cygwin -mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations -fcheck-new \
|
||||
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
|
||||
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
|
||||
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
|
||||
-Wno-sequence-point \
|
||||
$(DEF) $(incdir)
|
||||
endif
|
||||
ifdef GCC471
|
||||
CFLAGS = -pipe \
|
||||
-std=gnu99 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
-Wno-sequence-point \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
CXXFLAGS = -pipe \
|
||||
-std=gnu++11 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations -fcheck-new \
|
||||
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
|
||||
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
|
||||
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
|
||||
-Wno-unused-but-set-variable -Wno-sequence-point -Wno-narrowing -Wno-extra \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
CFLAGS += -m64
|
||||
CXXFLAGS += -m64
|
||||
LDFLAGS += -m64
|
||||
else
|
||||
CFLAGS += -m32
|
||||
CXXFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef GCC510
|
||||
CFLAGS = -pipe \
|
||||
-std=gnu99 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations \
|
||||
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
|
||||
-Wno-sequence-point -Wno-pedantic \
|
||||
$(DEF) $(incdir)
|
||||
|
||||
CXXFLAGS = -pipe \
|
||||
-std=gnu++11 -O1 \
|
||||
-mwindows \
|
||||
-fforce-addr -finline-limit=1200 -fthread-jumps \
|
||||
-fexpensive-optimizations -fcheck-new \
|
||||
-Wall -W -pedantic -Wshadow -Wno-long-long -Wno-write-strings \
|
||||
-Wunknown-pragmas -Wundef -Wno-conversion -Wno-missing-braces -Wno-multichar \
|
||||
-Wuninitialized -Wpointer-arith -Wno-inline -Wno-address -Wno-unused-value \
|
||||
-Wno-unused-but-set-variable -Wno-sequence-point -Wno-narrowing -Wno-extra \
|
||||
-Wno-pedantic \
|
||||
$(DEF) $(incdir)
|
||||
ifdef BUILD_X64_EXE
|
||||
CFLAGS += -m64
|
||||
CXXFLAGS += -m64
|
||||
LDFLAGS += -m64
|
||||
|
||||
# allow nasty C code in i8051.cpp
|
||||
CXXFLAGS += -fpermissive
|
||||
else
|
||||
CFLAGS += -m32
|
||||
CXXFLAGS += -m32
|
||||
LDFLAGS += -m32
|
||||
endif
|
||||
endif
|
||||
|
||||
ASFLAGS = -O1 -f coff -w-orphan-labels
|
||||
|
||||
# D3DUtils & D3DMath need these
|
||||
# DEF = -Dsinf=\(float\)sin -Dcosf=\(float\)cos -Dasinf=\(float\)asin -Dacosf=\(float\)acos -Dsqrtf=\(float\)sqrt
|
||||
|
||||
DEF := -DBUILD_WIN32 -DUSE_SPEEDHACKS -DFILENAME=$(NAME) -DMMX=$(MMX)
|
||||
|
||||
ifdef UNICODE
|
||||
DEF := $(DEF) -D_UNICODE
|
||||
endif
|
||||
|
||||
ifdef SPECIALBUILD
|
||||
DEF := $(DEF) -DSPECIALBUILD=$(SPECIALBUILD)
|
||||
endif
|
||||
|
||||
ifdef FASTCALL
|
||||
DEF := $(DEF) -DFASTCALL
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
ifdef GCC345
|
||||
CFLAGS += -mconsole
|
||||
endif
|
||||
ifdef GCC452
|
||||
CFLAGS += -mconsole
|
||||
endif
|
||||
DEF := $(DEF) -DFBA_DEBUG
|
||||
endif
|
||||
|
||||
ifdef ROM_VERIFY
|
||||
DEF := $(DEF) -DROM_VERIFY
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) -DINCLUDE_7Z_SUPPORT
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_AVI_RECORDING
|
||||
DEF := $(DEF) -DINCLUDE_AVI_RECORDING
|
||||
endif
|
||||
|
||||
ifdef LSB_FIRST
|
||||
DEF := $(DEF) -DLSB_FIRST
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_LIB_PNGH
|
||||
DEF := $(DEF) -DINCLUDE_LIB_PNGH
|
||||
endif
|
||||
|
||||
ifdef BUILD_A68K
|
||||
DEF := $(DEF) -DBUILD_A68K
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
DEF := $(DEF) -DBUILD_X86_ASM
|
||||
endif
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
DEF := $(DEF) -DBUILD_X64_EXE
|
||||
ifdef INCLUDE_CPLUSPLUS11_FILES
|
||||
DEF := $(DEF) -DXBYAK_NO_OP_NAMES -DMIPS3_X64_DRC
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef USE_SEGOE
|
||||
DEF := $(DEF) -DUSE_SEGOE
|
||||
endif
|
||||
|
||||
ifdef SYMBOL
|
||||
|
||||
CFLAGS += -ggdb3
|
||||
ASFLAGS += -g
|
||||
DEF := $(DEF) -D_DEBUG
|
||||
|
||||
ifdef PROFILE
|
||||
CFLAGS += -pg
|
||||
CXXFLAGS += -pg
|
||||
else
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
CXXFLAGS += -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
else
|
||||
LDFLAGS += -s
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
CFLAGS += -mmmx
|
||||
CXXFLAGS += -mmmx
|
||||
endif
|
||||
|
||||
# For zlib
|
||||
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=32
|
||||
|
||||
# For lib7z
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) -D_7ZIP_PPMD_SUPPPORT
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Specify paths
|
||||
#
|
||||
#
|
||||
|
||||
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
|
||||
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
vpath %.d $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
|
||||
#
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
#
|
||||
|
||||
.PHONY: all init cleandep touch clean
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef DEPEND
|
||||
|
||||
all: init $(drvdep) $(autdep) $(autobj) $(autdrv)
|
||||
ifdef GCC345
|
||||
@$(MAKE) -f makefile.mingw -s GCC345=1
|
||||
endif
|
||||
ifdef GCC452
|
||||
@$(MAKE) -f makefile.mingw -s GCC452=1
|
||||
endif
|
||||
ifdef GCC471
|
||||
@$(MAKE) -f makefile.mingw -s GCC471=1
|
||||
endif
|
||||
ifdef GCC510
|
||||
@$(MAKE) -f makefile.mingw -s GCC510=1
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
all: init $(autobj) $(autdrv)
|
||||
ifdef GCC345
|
||||
@$(MAKE) -f makefile.mingw -s GCC345=1
|
||||
endif
|
||||
ifdef GCC452
|
||||
@$(MAKE) -f makefile.mingw -s GCC452=1
|
||||
endif
|
||||
ifdef GCC471
|
||||
@$(MAKE) -f makefile.mingw -s GCC471=1
|
||||
endif
|
||||
ifdef GCC510
|
||||
@$(MAKE) -f makefile.mingw -s GCC510=1
|
||||
endif
|
||||
|
||||
endif
|
||||
else
|
||||
|
||||
all: $(NAME).exe
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Rule for linking the executable
|
||||
#
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
|
||||
$(objdir)/drivers.o: $(autdrv)
|
||||
@echo Linking drivers...
|
||||
ifdef BUILD_X64_EXE
|
||||
@$(LD) -m64 -r -nostdlib -o $@ $^
|
||||
else
|
||||
@$(LD) -m32 -r -nostdlib -o $@ $^
|
||||
endif
|
||||
|
||||
$(NAME).exe: $(allobj) $(objdir)/drivers.o
|
||||
@echo
|
||||
@echo Linking executable... $(NAME).exe
|
||||
@$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
|
||||
|
||||
ifdef DEBUG
|
||||
|
||||
# Don't compress when making a debug build
|
||||
|
||||
else
|
||||
ifdef COMPRESS
|
||||
@upx --best $@
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef FORCE_UPDATE
|
||||
$(build_details.h): FORCE
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate the gamelist
|
||||
#
|
||||
|
||||
burn.o burn.d: driverlist.h
|
||||
|
||||
$(driverlist.h): $(drvsrc) $(srcdir)dep/scripts/gamelist.pl
|
||||
ifdef PERL
|
||||
@$(srcdir)dep/scripts/gamelist.pl -o $@ -l gamelist.txt \
|
||||
$(filter %.cpp,$(foreach file,$(drvsrc:.o=.cpp),$(foreach dir,$(alldir), \
|
||||
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Verify if driverlist.h needs to be updated
|
||||
#
|
||||
|
||||
#ifeq ($(MAKELEVEL),1)
|
||||
#ifdef FORCE_UPDATE
|
||||
#$(driverlist.h): FORCE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#
|
||||
# Fix the .rc file
|
||||
#
|
||||
|
||||
resource.o resource.d: $(app_gnuc.rc) string.rc version.rc version.h $(build_details.h)
|
||||
|
||||
$(license.rtf): $(srcdir)license.txt $(srcdir)dep/scripts/license2rtf.pl
|
||||
|
||||
ifdef PERL
|
||||
ifdef USE_SEGOE
|
||||
@$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf) -f 'Segoe UI'
|
||||
else
|
||||
@$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf)
|
||||
endif
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
$(app_gnuc.rc): app.rc $(license.rc) $(license.rtf) $(srcdir)dep/scripts/fixrc.pl $(srcdir)burner/resource/fba.ico $(srcdir)burner/resource/about.bmp $(srcdir)burner/resource/splash.bmp $(srcdir)burner/resource/misc.bmp
|
||||
|
||||
ifdef PERL
|
||||
@$(srcdir)dep/scripts/fixrc.pl $< -o $@
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate some info on the build details
|
||||
#
|
||||
|
||||
about.o about.d: $(build_details.h)
|
||||
|
||||
$(build_details.h): $(srcdir)dep/scripts/build_details.cpp
|
||||
@$(CXX) -mconsole $(CXXFLAGS) $(LDFLAGS) $< -o $(objdir)dep/generated/build_details.exe
|
||||
@$(objdir)dep/generated/build_details.exe >$@
|
||||
|
||||
#
|
||||
# Compile 68000 cores
|
||||
#
|
||||
|
||||
# A68K
|
||||
|
||||
ifdef BUILD_A68K
|
||||
$(a68k.o): fba_make68k.c
|
||||
@echo Compiling A68K MC68000 core...
|
||||
@$(CC) -mconsole $(CFLAGS) $(LDFLAGS) -DWIN32 -Wno-unused -Wno-conversion -Wno-missing-prototypes \
|
||||
-s $< -o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe)
|
||||
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) \
|
||||
$(@D)/a68k_tab.asm 00 $(ppro)
|
||||
@echo Assembling A68K MC68000 core...
|
||||
@$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
|
||||
endif
|
||||
|
||||
# Musashi
|
||||
|
||||
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)dep/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kcpu.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(srcdir)cpu/m68k/m68kcpu.c -o $(objdir)cpu/m68k/m68kcpu.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kops.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
|
||||
|
||||
$(objdir)dep/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake.exe $(srcdir)cpu/m68k/m68k_in.c
|
||||
$(objdir)/cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
|
||||
|
||||
$(objdir)cpu/m68k/m68kmake.exe: $(srcdir)cpu/m68k/m68kmake.c
|
||||
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...
|
||||
@$(CC) $(CFLAGS) $(srcdir)cpu/m68k/m68kmake.c -o $(objdir)cpu/m68k/m68kmake.exe
|
||||
|
||||
|
||||
#
|
||||
# Extra rules for generated header file ctv.h, needed by ctv.cpp
|
||||
#
|
||||
|
||||
ctv.d ctv.o: $(ctv.h)
|
||||
|
||||
$(ctv.h): ctv_make.cpp
|
||||
@echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
@$(CC) -mconsole $(CXXFLAGS) $(LDFLAGS) $< \
|
||||
-o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe)
|
||||
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
|
||||
|
||||
#
|
||||
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
|
||||
#
|
||||
|
||||
toa_bcu2.d toa_bcu2.o toa_gp9001.d toa_gp9001.o: $(toa_gp9001_func.h)
|
||||
|
||||
$(toa_gp9001_func.h): $(srcdir)dep/scripts/toa_gp9001_func.pl
|
||||
@$(srcdir)dep/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
|
||||
#
|
||||
|
||||
neo_sprite.d neo_sprite.o: $(neo_sprite_func.h)
|
||||
|
||||
$(neo_sprite_func.h): $(srcdir)dep/scripts/neo_sprite_func.pl
|
||||
@$(srcdir)dep/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
|
||||
#
|
||||
|
||||
cave_tile.d cave_tile.o: $(cave_tile_func.h)
|
||||
|
||||
$(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
|
||||
@$(srcdir)dep/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
|
||||
#
|
||||
|
||||
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
|
||||
|
||||
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
|
||||
@$(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
|
||||
#
|
||||
|
||||
psikyo_tile.d psikyo_tile.o psikyosprite.d psikyo_sprite.o: $(psikyo_tile_func.h)
|
||||
|
||||
$(psikyo_tile_func.h): $(srcdir)dep/scripts/psikyo_tile_func.pl
|
||||
$(srcdir)dep/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file pgm_sprite.h, needed by pgm_draw.cpp
|
||||
#
|
||||
|
||||
pgm_draw.d pgm_draw.o: $(pgm_sprite.h)
|
||||
|
||||
$(pgm_sprite.h): pgm_sprite_create.cpp
|
||||
@echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
@$(CC) -mconsole $(CXXFLAGS) $(LDFLAGS) $< \
|
||||
-o $(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe)
|
||||
@$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
|
||||
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
ifdef DEPEND
|
||||
|
||||
include $(alldep)
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generic rule for resource files
|
||||
#
|
||||
|
||||
%.o: %.rc
|
||||
@echo Compiling resource file $(<F)...
|
||||
ifdef GCC345
|
||||
@windres $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
endif
|
||||
ifdef GCC452
|
||||
@windres $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
endif
|
||||
ifdef GCC471
|
||||
ifdef BUILD_X64_EXE
|
||||
@windres -F pe-x86-64 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
else
|
||||
@windres -F pe-i386 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
endif
|
||||
endif
|
||||
ifdef GCC510
|
||||
ifdef BUILD_X64_EXE
|
||||
@windres -F pe-x86-64 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
else
|
||||
@windres -F pe-i386 $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generic rules for C/C++ files
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
|
||||
%.o: %.cpp
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
else
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $@
|
||||
|
||||
%.o:
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate dependencies for C/C++ files
|
||||
#
|
||||
|
||||
ifdef DEPEND
|
||||
|
||||
%.d: %.c
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.cpp
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.rc
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Phony targets
|
||||
#
|
||||
|
||||
init:
|
||||
|
||||
ifdef DEBUG
|
||||
@echo Making debug build...
|
||||
else
|
||||
@echo Making normal build...
|
||||
endif
|
||||
@echo
|
||||
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
|
||||
@mkdir -p $(srcdir)dep/generated
|
||||
|
||||
cleandep:
|
||||
@echo Removing depend files from $(objdir)...
|
||||
-@for dir in $(alldir); do rm -f $(objdir)$$dir/*.d; done
|
||||
|
||||
touch:
|
||||
@echo Marking all targets for $(NAME) as uptodate...
|
||||
-@touch $(NAME).exe
|
||||
-@touch -c -r $(NAME).exe $(srcdir)/dep/generated/*
|
||||
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
|
||||
|
||||
clean:
|
||||
@echo Removing all files from $(objdir)...
|
||||
-@rm -f -r $(objdir)
|
||||
-@rm -f -r $(ctv.h)
|
||||
|
||||
ifdef PERL
|
||||
@echo Removing all files generated with perl scripts...
|
||||
-@rm -f -r $(app_gnuc.rc) $(driverlist)
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Rule to force recompilation of any target that depends on it
|
||||
#
|
||||
|
||||
FORCE:
|
||||
-716
@@ -1,716 +0,0 @@
|
||||
# Makefile for FBA, for use with GNU make (Cygwin/MinGW)
|
||||
#
|
||||
# The first pass makes sure all intermediary targets are present. The second pass updates
|
||||
# any targets, if necessary. (Intermediary) targets which have their own unique rules
|
||||
# are generated as required.
|
||||
|
||||
#
|
||||
# Flags. Uncomment any of these declarations to enable their function.
|
||||
#
|
||||
|
||||
# Specify the name of the executable file, without ".exe"
|
||||
NAME = fbasdl
|
||||
EXE = $(NAME)
|
||||
INSTALLDIR = /usr/local/games/fba/
|
||||
ROMDIR = /usr/local/share/roms/
|
||||
BINDIR = /usr/local/bin/
|
||||
FILES = fbasdl.ini gamelist.txt fb.png
|
||||
|
||||
# Check for changes in header files
|
||||
DEPEND = 1
|
||||
|
||||
#
|
||||
# Declare variables
|
||||
#
|
||||
|
||||
ifndef CPUTYPE
|
||||
CPUTYPE = i686
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
MMX = 1
|
||||
else
|
||||
MMX = 0
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
NAME := $(NAME)d
|
||||
else
|
||||
NAME := $(NAME)
|
||||
endif
|
||||
|
||||
ifeq ($(CPUTYPE),i686)
|
||||
ppro = ppro
|
||||
|
||||
endif
|
||||
|
||||
ifneq ($(CPUTYPE),i686)
|
||||
NAME := $(NAME)$(CPUTYPE)
|
||||
endif
|
||||
|
||||
#
|
||||
# Specify paths/files
|
||||
#
|
||||
|
||||
objdir = obj/GNU_SDL/$(NAME)/
|
||||
srcdir = src/
|
||||
|
||||
alldir = burn \
|
||||
burn/devices \
|
||||
burn/drv \
|
||||
burn/drv/capcom \
|
||||
burn/drv/cave \
|
||||
burn/drv/coleco \
|
||||
burn/drv/cps3 \
|
||||
burn/drv/dataeast \
|
||||
burn/drv/galaxian \
|
||||
burn/drv/irem \
|
||||
burn/drv/konami \
|
||||
burn/drv/megadrive \
|
||||
burn/drv/midway \
|
||||
burn/drv/pce \
|
||||
burn/drv/neogeo \
|
||||
burn/drv/pce \
|
||||
burn/drv/pgm \
|
||||
burn/drv/pre90s \
|
||||
burn/drv/psikyo \
|
||||
burn/drv/pst90s \
|
||||
burn/drv/sega \
|
||||
burn/drv/sg1000 \
|
||||
burn/drv/sms \
|
||||
burn/drv/snes \
|
||||
burn/drv/taito \
|
||||
burn/drv/toaplan \
|
||||
burn/snd \
|
||||
burner \
|
||||
burner/sdl \
|
||||
intf \
|
||||
intf/audio \
|
||||
intf/audio/sdl \
|
||||
intf/cd \
|
||||
intf/cd/sdl \
|
||||
intf/input \
|
||||
intf/input/sdl \
|
||||
intf/video \
|
||||
intf/video/sdl \
|
||||
intf/video/scalers \
|
||||
cpu \
|
||||
cpu/a68k \
|
||||
cpu/arm \
|
||||
cpu/arm7 \
|
||||
cpu/c68k \
|
||||
cpu/cz80 \
|
||||
cpu/h6280 \
|
||||
cpu/hd6309 \
|
||||
cpu/i8039 \
|
||||
cpu/konami \
|
||||
cpu/m68k \
|
||||
cpu/m6502 \
|
||||
cpu/m6800 \
|
||||
cpu/m6805 \
|
||||
cpu/m6809 \
|
||||
cpu/nec \
|
||||
cpu/pic16c5x \
|
||||
cpu/s2650 \
|
||||
cpu/sh2 \
|
||||
cpu/tlcs90 \
|
||||
cpu/z80 \
|
||||
dep/kaillera/client \
|
||||
dep/libs/lib7z \
|
||||
dep/libs/libpng \
|
||||
dep/libs/zlib \
|
||||
dep/mingw/include \
|
||||
dep/scripts \
|
||||
dep/vc/include \
|
||||
dep/generated
|
||||
|
||||
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I/local/include -I/include/SDL
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
lib = -static -lstdc++ -lpng -lmingw32 -Wl,-Bdynamic -lSDL -lz -lopengl32 -lglu32
|
||||
else
|
||||
lib = -lstdc++ -lSDL -lGL -lGLU -lz
|
||||
endif
|
||||
|
||||
|
||||
drvobj += \
|
||||
d_dodonpachi.o d_donpachi.o d_esprade.o d_feversos.o d_gaia.o d_guwange.o d_hotdogst.o d_korokoro.o d_mazinger.o \
|
||||
d_metmqstr.o d_pwrinst2.o d_sailormn.o d_tjumpman.o d_uopoko.o \
|
||||
\
|
||||
d_cps1.o \
|
||||
\
|
||||
d_cps2.o \
|
||||
\
|
||||
d_cps3.o \
|
||||
\
|
||||
d_actfancr.o d_backfire.o d_boogwing.o d_cbuster.o d_cninja.o d_darkseal.o d_dassault.o d_dec0.o d_dec8.o \
|
||||
d_dietgogo.o d_funkyjet.o d_karnov.o d_lemmings.o d_pktgaldx.o d_rohga.o d_sidepckt.o d_simpl156.o d_supbtime.o \
|
||||
d_tumblep.o d_vaportra.o \
|
||||
\
|
||||
d_galaxian.o \
|
||||
\
|
||||
d_m62.o d_m63.o d_m72.o d_m90.o d_m92.o d_m107.o d_vigilant.o \
|
||||
\
|
||||
d_88games.o d_ajax.o d_aliens.o d_asterix.o d_battlnts.o d_bishi.o d_bladestl.o d_blockhl.o d_bottom9.o d_circusc.o d_contra.o \
|
||||
d_crimfght.o d_dbz.o d_finalzr.o d_gberet.o d_gijoe.o d_gbusters.o d_gradius3.o d_gyruss.o d_hcastle.o d_hexion.o d_ironhors.o \
|
||||
d_jailbrek.o d_kontest.o d_labyrunr.o d_lethal.o d_mainevt.o d_megazone.o d_mikie.o d_mogura.o d_moo.o d_mystwarr.o d_nemesis.o \
|
||||
d_pandoras.o d_parodius.o d_pooyan.o d_rocnrope.o d_rockrage.o d_rollerg.o d_scotrsht.o d_shaolins.o d_simpsons.o d_spy.o \
|
||||
d_surpratk.o d_thunderx.o d_timeplt.o d_tmnt.o d_tp84.o d_tutankhm.o d_twin16.o d_ultraman.o d_vendetta.o d_xexex.o d_xmen.o \
|
||||
d_yiear.o \
|
||||
\
|
||||
d_neogeo.o \
|
||||
\
|
||||
d_pgm.o \
|
||||
\
|
||||
d_psikyo.o d_psikyo4.o d_psikyosh.o \
|
||||
\
|
||||
d_angelkds.o d_bankp.o d_dotrikun.o d_hangon.o d_outrun.o d_suprloco.o d_suprnova.o d_sys1.o d_sys16a.o d_sys16b.o d_sys18.o \
|
||||
d_xbrd.o d_ybrd.o d_zaxxon.o \
|
||||
\
|
||||
d_arkanoid.o d_ashnojoe.o d_asuka.o d_bublbobl.o d_chaknpop.o d_darius2.o d_darkmist.o d_exzisus.o d_flstory.o d_lkage.o \
|
||||
d_minivdr.o d_othunder.o d_retofinv.o d_slapshot.o d_superchs.o d_taitob.o d_taitof2.o d_taitomisc.o d_taitox.o d_taitoz.o \
|
||||
d_tnzs.o d_wyvernf0.o \
|
||||
\
|
||||
d_batrider.o d_batsugun.o d_battleg.o d_bbakraid.o d_demonwld.o d_dogyuun.o d_fixeight.o d_ghox.o d_hellfire.o \
|
||||
d_kbash.o d_kbash2.o d_mahoudai.o d_outzone.o d_pipibibs.o d_rallybik.o d_samesame.o d_shippumd.o d_slapfght.o \
|
||||
d_snowbro2.o d_tekipaki.o d_truxton.o d_truxton2.o d_vfive.o d_vimana.o d_zerowing.o \
|
||||
\
|
||||
d_4enraya.o d_1942.o d_1943.o d_alinvade.o d_alpha68k.o d_ambush.o d_arabian.o d_armedf.o d_atetris.o d_aztarac.o d_baraduke.o \
|
||||
d_bionicc.o d_blktiger.o d_blockout.o d_blueprnt.o d_bombjack.o d_capbowl.o d_commando.o d_cybertnk.o d_ddragon.o d_djboy.o d_dkong.o \
|
||||
d_dynduke.o d_epos.o d_exedexes.o d_funkybee.o d_galaga.o d_gauntlet.o d_ginganin.o d_gng.o d_gunsmoke.o d_higemaru.o \
|
||||
d_ikki.o d_invaders.o d_jack.o d_kangaroo.o d_kncljoe.o d_kyugo.o d_ladybug.o d_lwings.o d_lastduel.o d_mario.o d_markham.o \
|
||||
d_marineb.o d_megasys1.o d_meijinsn.o d_mitchell.o d_mole.o d_momoko.o d_mrdo.o d_mrflea.o d_mustache.o d_mystston.o d_ninjakd2.o \
|
||||
d_pacland.o d_pacman.o d_pac2650.o d_pkunwar.o d_prehisle.o d_punchout.o d_psychic5.o d_quizo.o d_rallyx.o d_renegade.o d_rpunch.o \
|
||||
d_route16.o d_scregg.o d_sf.o d_sidearms.o d_skyarmy.o d_skyfox.o d_skykid.o d_snk68.o d_solomon.o d_sonson.o d_srumbler.o d_suna8.o d_tail2nose.o \
|
||||
d_tbowl.o d_tecmo.o d_terracre.o d_tigeroad.o d_timelimt.o d_toki.o d_tsamurai.o d_vulgus.o d_wallc.o d_wc90.o d_wc90b.o d_wwfsstar.o \
|
||||
d_xain.o \
|
||||
\
|
||||
d_1945kiii.o d_aerofgt.o d_airbustr.o d_aquarium.o d_blmbycar.o d_bloodbro.o d_crospang.o d_crshrace.o d_dcon.o d_deniam.o \
|
||||
d_ddragon3.o d_diverboy.o d_dooyong.o d_drgnmst.o d_drtomy.o d_egghunt.o d_esd16.o d_f1gp.o d_funybubl.o \
|
||||
d_fuukifg3.o d_gaelco.o d_gaiden.o d_galpanic.o d_galspnbl.o d_gotcha.o d_gumbo.o d_hyperpac.o d_jchan.o d_kaneko16.o \
|
||||
d_lordgun.o d_mcatadv.o d_midas.o d_mugsmash.o d_mwarr.o d_news.o d_nmg5.o d_nmk16.o d_ohmygod.o d_pass.o d_pirates.o \
|
||||
d_playmark.o d_powerins.o d_pushman.o d_raiden.o d_raiden2.o d_sandscrp.o d_seta.o d_seta2.o d_shadfrce.o d_silkroad.o \
|
||||
d_silvmil.o d_speedspn.o d_suna16.o d_taotaido.o d_tecmo16.o d_tecmosys.o d_tetrisp2.o d_tumbleb.o d_unico.o d_vmetal.o \
|
||||
d_welltris.o d_wwfwfest.o d_xorworld.o d_xxmissio.o d_yunsun16.o d_zerozone.o \
|
||||
\
|
||||
d_parent.o \
|
||||
\
|
||||
d_megadrive.o \
|
||||
\
|
||||
d_pce.o \
|
||||
\
|
||||
d_sms.o \
|
||||
\
|
||||
d_snes.o \
|
||||
\
|
||||
d_coleco.o \
|
||||
\
|
||||
d_sg1000.o
|
||||
|
||||
depobj += \
|
||||
bzip.o config.o drv.o inpdipsw.o main.o media.o run.o stated.o \
|
||||
stringset.o ips_manager.o support_paths.o scrn.o \
|
||||
\
|
||||
ioapi.o unzip.o conc.o cong.o dat.o gamc.o gami.o image.o \
|
||||
misc.o sshot.o state.o statec.o zipfn.o \
|
||||
\
|
||||
aud_sdl.o inp_sdl.o vid_sdlfx.o vid_sdlopengl.o \
|
||||
\
|
||||
aud_dsp.o aud_interface.o inp_interface.o interface.o \
|
||||
lowpass2.o vid_interface.o vid_softfx.o vid_support.o \
|
||||
\
|
||||
cd_interface.o cd_isowav.o cdsound.o neocdlist.o \
|
||||
\
|
||||
2xpm.o 2xsai.o ddt3x.o epx.o hq2xs.o hq2xs_16.o xbr.o \
|
||||
\
|
||||
adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o gzwrite.o infback.o \
|
||||
inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o \
|
||||
\
|
||||
png.o pngerror.o pngget.o pngmem.o pngpread.o pngread.o pngrio.o pngrtran.o pngrutil.o \
|
||||
pngset.o pngtrans.o pngwio.o pngwrite.o pngwtran.o pngwutil.o \
|
||||
\
|
||||
$(drvobj) \
|
||||
\
|
||||
burn.o burn_gun.o burn_led.o burn_memory.o burn_sound.o burn_sound_c.o cheat.o debug_track.o hiscore.o load.o \
|
||||
tiles_generic.o timer.o vector.o \
|
||||
\
|
||||
8255ppi.o 8257dma.o eeprom.o nmk004.o kaneko_tmap.o pandora.o seibusnd.o sknsspr.o slapstic.o t5182.o timekpr.o tms34061.o \
|
||||
v3021.o vdc.o tms9928a.o \
|
||||
\
|
||||
ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o \
|
||||
burn_ym3526.o burn_ym3812.o burn_ymf278b.o c6280.o dac.o es5506.o es8712.o flt_rc.o fm.o fmopl.o ics2115.o iremga20.o \
|
||||
k005289.o k007232.o k051649.o k053260.o k054539.o msm5205.o msm5232.o msm6295.o namco_snd.o nes_apu.o rf5c68.o saa1099.o \
|
||||
samples.o segapcm.o sn76496.o upd7759.o vlm5030.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf278b.o ymz280b.o \
|
||||
\
|
||||
arm7_intf.o arm_intf.o h6280_intf.o hd6309_intf.o konami_intf.o m6502_intf.o m6800_intf.o m6805_intf.o m6809_intf.o \
|
||||
m68000_intf.o nec_intf.o pic16c5x_intf.o s2650_intf.o tlcs90_intf.o z80_intf.o \
|
||||
\
|
||||
arm.o arm7.o h6280.o hd6309.o i8039.o konami.o m6502.o m6800.o m6805.o m6809.o nec.o pic16c5x.o s2650.o sh2.o tlcs90.o \
|
||||
v25.o z80.o z80daisy.o \
|
||||
\
|
||||
cave.o cave_palette.o cave_sprite.o cave_tile.o \
|
||||
\
|
||||
cps2_crpt.o cps.o cps_config.o cps_draw.o cps_mem.o cps_obj.o cps_pal.o cps_run.o cps_rw.o cps_scr.o cpsr.o cpsrd.o \
|
||||
cpst.o ctv.o fcrash_snd.o kabuki.o ps.o ps_m.o ps_z.o qs.o qs_c.o qs_z.o sf2mdt_snd.o \
|
||||
\
|
||||
cps3run.o cps3snd.o \
|
||||
\
|
||||
deco16ic.o \
|
||||
\
|
||||
gal_gfx.o gal_run.o gal_sound.o gal_stars.o \
|
||||
\
|
||||
irem_cpu.o \
|
||||
\
|
||||
k007342_k007420.o k051316.o k051733.o k051960.o k052109.o k053245.o k053247.o k053250.o k053251.o k053936.o k054000.o \
|
||||
k054338.o k055555.o k056832.o konamigx.o konamiic.o timeplt_snd.o \
|
||||
\
|
||||
neo_decrypt.o neo_palette.o neo_run.o neo_sprite.o neo_text.o neo_upd4990a.o neogeo.o \
|
||||
\
|
||||
pgm_crypt.o pgm_draw.o pgm_run.o pgm_asic3.o pgm_asic27a_type1.o pgm_asic27a_type2.o pgm_asic27a_type3.o pgm_asic25.o \
|
||||
\
|
||||
psikyo_palette.o psikyo_sprite.o psikyo_tile.o psikyosh_render.o \
|
||||
\
|
||||
fd1089.o fd1094.o genesis_vid.o mc8123.o sys16_fd1094.o sys16_gfx.o sys16_run.o \
|
||||
\
|
||||
cchip.o pc080sn.o pc090oj.o taito.o taito_ic.o taito_m68705.o tc0100scn.o tc0110pcr.o tc0140syt.o tc0150rod.o \
|
||||
tc0180vcu.o tc0220ioc.o tc0280grd.o tc0360pri.o tc0480scp.o tc0510nio.o tc0640fio.o tnzs_prot.o \
|
||||
\
|
||||
toa_bcu2.o toa_extratext.o toa_gp9001.o toa_palette.o toaplan1.o toaplan.o \
|
||||
\
|
||||
megadrive.o \
|
||||
\
|
||||
pce.o \
|
||||
\
|
||||
sms.o smspio.o smssystem.o smsvdp.o smsfmintf.o smsrender.o smssound.o smstms.o \
|
||||
\
|
||||
snes_65816.o snes_io.o snes_main.o snes_ppu.o snes_spc700.o
|
||||
|
||||
autobj += $(depobj)
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
autobj += burn_sound_a.o eagle_fm.o 2xsaimmx.o hq2x32.o hq3x32.o hq4x32.o superscale.o
|
||||
endif
|
||||
|
||||
autdep = $(depobj:.o=.d)
|
||||
|
||||
#app_windres.rc = $(srcdir)dep/generated/app_windres.rc
|
||||
#license.rc = $(srcdir)dep/generated/license.rc
|
||||
driverlist.h = $(srcdir)dep/generated/driverlist.h
|
||||
ctv.h = $(srcdir)dep/generated/ctv.h
|
||||
toa_gp9001_func.h = $(srcdir)dep/generated/toa_gp9001_func.h
|
||||
neo_sprite_func.h = $(srcdir)dep/generated/neo_sprite_func.h
|
||||
cave_tile_func.h = $(srcdir)dep/generated/cave_tile_func.h
|
||||
cave_sprite_func.h = $(srcdir)dep/generated/cave_sprite_func.h
|
||||
psikyo_tile_func.h = $(srcdir)dep/generated/psikyo_tile_func.h
|
||||
pgm_sprite.h = $(srcdir)dep/generated/pgm_sprite.h
|
||||
build_details.h = $(srcdir)dep/generated/build_details.h
|
||||
|
||||
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kops.o \
|
||||
$(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.asm), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
alldep = $(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.d,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.rc), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .rc,.d,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
#
|
||||
#
|
||||
# Specify compiler/linker/assembler
|
||||
#
|
||||
#
|
||||
|
||||
HOSTCC = gcc
|
||||
HOSTCXX = g++
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
LD = $(CXX)
|
||||
AS = nasm
|
||||
|
||||
HOSTCFLAGS = $(incdir)
|
||||
CFLAGS = -O2 -fomit-frame-pointer -Wno-write-strings -DLSB_FIRST -DFASTCALL -DBUILD_M68K -DINCLUDE_LIB_PNGH
|
||||
CXXFLAGS = -O2 -fomit-frame-pointer -Wno-write-strings -DLSB_FIRST -DFASTCALL -DBUILD_M68K -DINCLUDE_LIB_PNGH
|
||||
DEF := -DCPUTYPE=$(CPUTYPE) -DUSE_SPEEDHACKS -DBUILD_SDL
|
||||
|
||||
CFLAGS += -U__cdecl -U__fastcall -D__cdecl="" -D__fastcall=""
|
||||
CXXFLAGS += -U__cdecl -U__fastcall -D__cdecl="" -D__fastcall=""
|
||||
|
||||
ifdef SPECIALBUILD
|
||||
DEF := $(DEF) -DSPECIALBUILD=$(SPECIALBUILD)
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
DEF := $(DEF) -D_DEBUG
|
||||
CFLAGS += -g
|
||||
CXXFLAGS += -g
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
DEF := $(DEF) -DBUILD_X86_ASM
|
||||
endif
|
||||
|
||||
ifdef MMX
|
||||
DEF += -DMMX
|
||||
endif
|
||||
|
||||
DEF := $(DEF) -DFILENAME=$(NAME)
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
CFLAGS += -mmmx
|
||||
CXXFLAGS += -mmmx
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF) $(incdir)
|
||||
CXXFLAGS += $(DEF) $(incdir)
|
||||
ifndef DEBUG
|
||||
LDFLAGS += -s
|
||||
endif
|
||||
ASFLAGS = -O1
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CFLAGS_CONSOLE = -mno-cygwin -mconsole -pipe -Wall -W $(DEF) $(incdir)
|
||||
ASFLAGS += -f coff
|
||||
else
|
||||
ASFLAGS += -f elf
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Specify paths
|
||||
#
|
||||
#
|
||||
|
||||
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
|
||||
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
vpath %.d $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
|
||||
#
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
#
|
||||
|
||||
.PHONY: all init cleandep touch clean
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef DEPEND
|
||||
|
||||
all: init $(autdep) $(autobj)
|
||||
@$(MAKE) -f makefile.sdl
|
||||
else
|
||||
|
||||
all: init $(autobj)
|
||||
@$(MAKE) -f makefile.sdl
|
||||
endif
|
||||
else
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Rule for linking the executable
|
||||
#
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
|
||||
$(NAME): $(allobj)
|
||||
@echo
|
||||
@echo Linking executable $(NAME)...
|
||||
@$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
|
||||
|
||||
ifdef DEBUG
|
||||
|
||||
# Don't compress when making a debug build
|
||||
|
||||
else
|
||||
ifdef COMPRESS
|
||||
@upx --best $@
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate the gamelist
|
||||
#
|
||||
|
||||
burn.o burn.d: driverlist.h
|
||||
|
||||
$(driverlist.h): $(drvobj) $(srcdir)dep/scripts/gamelist.pl
|
||||
ifdef PERL
|
||||
@perl $(srcdir)dep/scripts/gamelist.pl -o $@ -l gamelist.txt \
|
||||
$(filter %.cpp,$(foreach file,$(drvobj:.o=.cpp),$(foreach dir,$(alldir), \
|
||||
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Fix the .rc file
|
||||
#
|
||||
|
||||
resource.o resource.d: $(app_windres.rc) version.rc version.h
|
||||
|
||||
$(license.rc): $(srcdir)license.txt $(srcdir)dep/scripts/license2rtf.pl $(srcdir)dep/scripts/license2rc.pl
|
||||
|
||||
ifdef PERL
|
||||
@perl $(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf)
|
||||
@perl $(srcdir)dep/scripts/license2rc.pl $(srcdir)dep/generated/$(@F:.rc=.rtf) -o $@
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
$(app_windres.rc): app.rc $(license.rc) $(srcdir)dep/scripts/fixrc.pl $(srcdir)burner/resource/fba.ico $(srcdir)burner/resource/about.bmp $(srcdir)burner/resource/preview.bmp $(srcdir)burner/resource/misc.bmp
|
||||
|
||||
ifdef PERL
|
||||
@perl $(srcdir)dep/scripts/fixrc.pl $< -o $@
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Compile Musashi 68000 cores
|
||||
#
|
||||
|
||||
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)dep/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kcpu.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(srcdir)cpu/m68k/m68kcpu.c -o $(objdir)cpu/m68k/m68kcpu.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo Compiling Musashi MC680x0 core \(m68kops.c\)...
|
||||
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
|
||||
|
||||
$(objdir)dep/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake $(srcdir)cpu/m68k/m68k_in.c
|
||||
$(objdir)/cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
|
||||
|
||||
$(objdir)cpu/m68k/m68kmake: $(srcdir)cpu/m68k/m68kmake.c
|
||||
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...
|
||||
@$(HOSTCC) $(HOSTCFLAGS) $(srcdir)cpu/m68k/m68kmake.c -o $(objdir)cpu/m68k/m68kmake
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cvt.h, needed by ctv.cpp
|
||||
#
|
||||
|
||||
ctv.d ctv.o: $(ctv.h)
|
||||
|
||||
$(ctv.h): ctv_make.cpp
|
||||
@echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
@$(HOSTCXX) $(LDFLAGS) $< -o $(objdir)dep/generated/ctv_make
|
||||
@$(objdir)dep/generated/ctv_make >$@
|
||||
|
||||
#
|
||||
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
|
||||
#
|
||||
|
||||
toa_bcu2.d toa_bcu2.o toa_gp9001.d toa_gp9001.o: $(toa_gp9001_func.h)
|
||||
|
||||
$(toa_gp9001_func.h): $(srcdir)dep/scripts/toa_gp9001_func.pl
|
||||
@$(srcdir)dep/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
|
||||
#
|
||||
|
||||
neo_sprite.d neo_sprite.o: $(neo_sprite_func.h)
|
||||
|
||||
$(neo_sprite_func.h): $(srcdir)dep/scripts/neo_sprite_func.pl
|
||||
@$(srcdir)dep/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
|
||||
#
|
||||
|
||||
cave_tile.d cave_tile.o: $(cave_tile_func.h)
|
||||
|
||||
$(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
|
||||
@perl $(srcdir)dep/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
|
||||
#
|
||||
|
||||
cave_sprite.d cave_sprite.o: $(cave_sprite_func.h)
|
||||
|
||||
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
|
||||
@perl $(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
|
||||
#
|
||||
|
||||
psikyo_tile.d psikyo_tile.o psikyosprite.d psikyo_sprite.o: $(psikyo_tile_func.h)
|
||||
|
||||
$(psikyo_tile_func.h): $(srcdir)dep/scripts/psikyo_tile_func.pl
|
||||
@perl $(srcdir)dep/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file pgm_sprite.h, needed by pgm_draw.cpp
|
||||
#
|
||||
|
||||
pgm_draw.d pgm_draw.o: $(pgm_sprite.h)
|
||||
|
||||
$(pgm_sprite.h): pgm_sprite_create.cpp
|
||||
@echo Generating $(srcdir)dep/generated/$(@F)...
|
||||
@$(HOSTCXX) $(LDFLAGS) $< -o $(objdir)dep/generated/pgm_sprite_create
|
||||
@$(objdir)dep/generated/pgm_sprite_create >$@
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
ifdef DEPEND
|
||||
|
||||
include $(alldep)
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generic rule for resource files
|
||||
#
|
||||
|
||||
%.o: %.rc
|
||||
@echo Compiling resource file $(<F)...
|
||||
@windres $(DEF) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(foreach dir,$(alldir),--include-dir $(srcdir)$(dir))
|
||||
|
||||
#
|
||||
# Generic rules for C/C++ files
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
|
||||
ifdef FORCE_UPDATE
|
||||
resource.o: FORCE
|
||||
about.o: FORCE
|
||||
endif
|
||||
|
||||
%.o: %.cpp
|
||||
@echo Compiling $<...
|
||||
@$(CXX) $(CXXFLAGS) -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -Wno-unused -Wno-conversion -Wno-missing-prototypes -c $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
else
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) -Wno-unused -Wno-conversion -Wno-missing-prototypes -c $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $@
|
||||
|
||||
%.o:
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate dependencies for C/C++ files
|
||||
#
|
||||
|
||||
ifdef DEPEND
|
||||
|
||||
%.d: %.c
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.cpp
|
||||
@echo Generating depend file for $<...
|
||||
@$(CXX) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CXXFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.d: %.rc
|
||||
@echo Generating depend file for $<...
|
||||
@$(CC) -MM -MT "$(subst $(srcdir),$(objdir),$(<D))/$(*F).o $(subst $(srcdir),$(objdir),$(<D))/$(@F)" -x c++ $(CFLAGS) $< >$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Phony targets
|
||||
#
|
||||
|
||||
init:
|
||||
|
||||
ifdef DEBUG
|
||||
@echo Making debug build...
|
||||
else
|
||||
@echo Making normal build...
|
||||
endif
|
||||
@echo
|
||||
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
|
||||
@mkdir -p $(srcdir)dep/generated
|
||||
|
||||
cleandep:
|
||||
@echo Removing depend files from $(objdir)...
|
||||
@for dir in $(alldir); do rm -f $(objdir)$$dir/*.d; done
|
||||
|
||||
touch:
|
||||
@echo Marking all targets for $(NAME) as uptodate...
|
||||
@for dir in $(alldir); do touch -c $(objdir)$$dir/*; done
|
||||
@do touch -c $(srcdir)/generated/*
|
||||
@touch $(NAME).exe
|
||||
install:
|
||||
mkdir -p $(INSTALLDIR)
|
||||
mkdir -p $(ROMDIR)
|
||||
cp $(EXE) $(INSTALLDIR)
|
||||
cp $(FILES) $(INSTALLDIR)
|
||||
ln -fs $(INSTALLDIR)$(EXE) $(BINDIR)$(EXE)
|
||||
|
||||
clean:
|
||||
@echo Removing all files from $(objdir)...
|
||||
@rm -f -r $(objdir)
|
||||
@rm -f -r $(ctv.h)
|
||||
|
||||
ifdef PERL
|
||||
@echo Removing all files generated with perl scripts...
|
||||
@rm -f -r $(app_windres.rc) $(driverlist)
|
||||
endif
|
||||
@echo Removing executable file...
|
||||
@rm -f $(EXE)
|
||||
|
||||
#
|
||||
# Rule to force recompilation of any target that depends on it
|
||||
#
|
||||
|
||||
FORCE:
|
||||
@@ -1,138 +0,0 @@
|
||||
alldir = burn burn/devices burn/sound burn/drivers burn/drivers/capcom burn/drivers/cave burn/drivers/cps3 \
|
||||
burn/drivers/dataeast burn/drivers/galaxian burn/drivers/irem burn/drivers/konami burn/drivers/megadrive \
|
||||
burn/drivers/misc_post90s burn/drivers/misc_pre90s burn/drivers/neogeo burn/drivers/pgm burn/drivers/psikyo \
|
||||
burn/drivers/sega burn/drivers/snes burn/drivers/taito burn/drivers/toaplan burner burner/platform/sdl cpu cpu/a68k \
|
||||
cpu/arm cpu/arm7 cpu/h6280 cpu/hd6309 cpu/i8039 cpu/konami cpu/m68k cpu/m6502 cpu/m6800 cpu/m6805 cpu/m6809 cpu/nec \
|
||||
cpu/s2650 cpu/sh2 cpu/z80 depend/kaillera/client depend/libs/libpng depend/libs/zlib interface interface/video \
|
||||
interface/video/scalers interface/video/sdl interface/audio interface/audio/sdl interface/input \
|
||||
interface/input/sdl interface/cd interface/cd/sdl interface/perfcount \
|
||||
depend/generated
|
||||
|
||||
drvobj = d_dodonpachi.o d_donpachi.o d_esprade.o d_feversos.o d_gaia.o d_guwange.o d_hotdogst.o d_korokoro.o d_mazinger.o \
|
||||
d_metmqstr.o d_pwrinst2.o d_sailormn.o d_tjumpman.o d_uopoko.o \
|
||||
\
|
||||
d_cps1.o \
|
||||
\
|
||||
d_cps2.o \
|
||||
\
|
||||
d_cps3.o \
|
||||
\
|
||||
d_actfancr.o d_backfire.o d_boogwing.o d_cbuster.o d_cninja.o d_darkseal.o d_dassault.o d_dec0.o d_dec8.o \
|
||||
d_dietgogo.o d_funkyjet.o d_karnov.o d_lemmings.o d_rohga.o d_sidepckt.o d_simpl156.o d_supbtime.o d_tumblep.o \
|
||||
d_vaportra.o \
|
||||
\
|
||||
d_galaxian.o \
|
||||
\
|
||||
d_m62.o d_m63.o d_m72.o d_m90.o d_m92.o d_vigilant.o \
|
||||
\
|
||||
d_88games.o d_ajax.o d_aliens.o d_blockhl.o d_bottom9.o d_contra.o d_crimfght.o d_gberet.o d_gbusters.o d_gradius3.o \
|
||||
d_gyruss.o d_hcastle.o d_hexion.o d_kontest.o d_mainevt.o d_mogura.o d_parodius.o d_pooyan.o d_rollerg.o d_scotrsht.o \
|
||||
d_simpsons.o d_spy.o d_surpratk.o d_thunderx.o d_tmnt.o d_twin16.o d_ultraman.o d_vendetta.o d_xmen.o \
|
||||
\
|
||||
d_neogeo.o \
|
||||
\
|
||||
d_pgm.o \
|
||||
\
|
||||
d_psikyo.o d_psikyo4.o d_psikyosh.o \
|
||||
\
|
||||
d_angelkds.o d_bankp.o d_dotrikun.o d_hangon.o d_outrun.o d_suprloco.o d_sys1.o d_sys16a.o d_sys16b.o d_sys18.o \
|
||||
d_xbrd.o d_ybrd.o \
|
||||
\
|
||||
d_arkanoid.o d_ashnojoe.o d_asuka.o d_bublbobl.o d_chaknpop.o d_darius2.o d_flstory.o d_lkage.o d_minivdr.o \
|
||||
d_othunder.o d_retofinv.o d_slapshot.o d_superchs.o d_taitob.o d_taitof2.o d_taitomisc.o d_taitox.o d_taitoz.o \
|
||||
d_tnzs.o \
|
||||
\
|
||||
d_batrider.o d_batsugun.o d_battleg.o d_bbakraid.o d_demonwld.o d_dogyuun.o d_fixeight.o d_ghox.o d_hellfire.o \
|
||||
d_kbash.o d_kbash2.o d_mahoudai.o d_outzone.o d_pipibibs.o d_rallybik.o d_samesame.o d_shippumd.o d_snowbro2.o \
|
||||
d_tekipaki.o d_tigerheli.o d_truxton.o d_truxton2.o d_vfive.o d_vimana.o d_zerowing.o \
|
||||
\
|
||||
d_4enraya.o d_1942.o d_1943.o d_ambush.o d_arabian.o d_armedf.o d_atetris.o d_aztarac.o d_baraduke.o d_bionicc.o \
|
||||
d_blktiger.o d_blockout.o d_blueprnt.o d_bombjack.o d_commando.o d_cybertnk.o d_ddragon.o d_dkong.o d_dynduke.o d_epos.o \
|
||||
d_exedexes.o d_funkybee.o d_galaga.o d_gauntlet.o d_ginganin.o d_gng.o d_gunsmoke.o d_higemaru.o d_ikki.o d_jack.o \
|
||||
d_kangaroo.o d_kyugo.o d_ladybug.o d_lwings.o d_madgear.o d_markham.o d_marineb.o d_meijinsn.o d_mitchell.o d_mole.o \
|
||||
d_momoko.o d_mrdo.o d_mrflea.o d_mystston.o d_pacland.o d_pacman.o d_pac2650.o d_pkunwar.o d_prehisle.o d_quizo.o \
|
||||
d_rallyx.o d_renegade.o d_rpunch.o d_route16.o d_scregg.o d_sf.o d_skyfox.o d_skykid.o d_snk68.o d_solomon.o \
|
||||
d_sonson.o d_srumbler.o d_tecmo.o d_terracre.o d_tigeroad.o d_toki.o d_vulgus.o d_wallc.o d_wc90.o d_wc90b.o \
|
||||
d_wwfsstar.o \
|
||||
\
|
||||
d_1945kiii.o d_aerofgt.o d_airbustr.o d_aquarium.o d_blmbycar.o d_bloodbro.o d_crospang.o d_crshrace.o d_dcon.o \
|
||||
d_deniam.o d_ddragon3.o d_diverboy.o d_drtomy.o d_egghunt.o d_esd16.o d_f1gp.o d_fstarfrc.o d_funybubl.o d_fuukifg3.o \
|
||||
d_gaelco.o d_gaiden.o d_galpanic.o d_galspnbl.o d_gotcha.o d_gumbo.o d_hyperpac.o d_jchan.o d_kaneko16.o d_lordgun.o \
|
||||
d_mcatadv.o d_midas.o d_mugsmash.o d_news.o d_nmg5.o d_nmk16.o d_ohmygod.o d_pass.o d_pirates.o d_pktgaldx.o \
|
||||
d_powerins.o d_pushman.o d_raiden.o d_seta.o d_seta2.o d_shadfrce.o d_silkroad.o d_silvmin.o d_speedspn.o d_suna16.o \
|
||||
d_taotaido.o d_tecmosys.o d_tumbleb.o d_unico.o d_vmetal.o d_welltris.o d_wwfwfest.o d_xorworld.o d_yunsun16.o \
|
||||
d_zerozone.o \
|
||||
\
|
||||
d_parent.o \
|
||||
\
|
||||
d_megadrive.o \
|
||||
\
|
||||
d_snes.o
|
||||
|
||||
depobj := main.o drv.o load.o misc.o \
|
||||
vid_sdlfx.o vid_softfx.o vid_interface.o vid_support.o config.o \
|
||||
state.o stated.o statec.o run.o inpdipsw.o gami.o gamc.o \
|
||||
cheat.o vid_sdlopengl.o \
|
||||
inp_interface.o inp_sdl.o\
|
||||
bzip.o unzip.o zipfn.o cong.o conc.o\
|
||||
interface.o sshot.o dat.o aud_sdl.o aud_interface.o aud_dsp.o \
|
||||
lowpass2.o \
|
||||
\
|
||||
$(drvobj) \
|
||||
\
|
||||
burn.o burn_gun.o burn_led.o burn_memory.o burn_sound.o burn_sound_c.o cheat.o debug_track.o hiscore.o load.o \
|
||||
tiles_generic.o timer.o vector.o \
|
||||
\
|
||||
8255ppi.o eeprom.o pandora.o seibusnd.o slapstic.o timekpr.o v3021.o \
|
||||
\
|
||||
ay8910.o burn_y8950.o burn_ym2151.o burn_ym2203.o burn_ym2413.o burn_ym2608.o burn_ym2610.o burn_ym2612.o \
|
||||
burn_ym3526.o burn_ym3812.o burn_ymf278b.o dac.o es5506.o es8712.o fm.o fmopl.o ics2115.o iremga20.o k007232.o \
|
||||
k051649.o k053260.o k054539.o msm5205.o msm6295.o namco_snd.o rf5c68.o saa1099.o samples.o segapcm.o sn76496.o \
|
||||
upd7759.o x1010.o ym2151.o ym2413.o ymdeltat.o ymf278b.o ymz280b.o \
|
||||
\
|
||||
arm7_intf.o arm_intf.o h6280_intf.o hd6309_intf.o konami_intf.o m6502_intf.o m6800_intf.o m6805_intf.o m6809_intf.o \
|
||||
m68000_intf.o nec_intf.o s2650_intf.o z80_intf.o \
|
||||
\
|
||||
arm.o arm7.o h6280.o hd6309.o i8039.o konami.o m6502.o m6800.o m6805.o m6809.o nec.o s2650.o sh2.o v25.o z80.o \
|
||||
z80daisy.o \
|
||||
\
|
||||
2xpm.o 2xsai.o epx.o hq2xs.o hq2xs_16.o \
|
||||
\
|
||||
cave.o cave_palette.o cave_sprite.o cave_tile.o \
|
||||
\
|
||||
cps2_crpt.o cps.o cps_config.o cps_draw.o cps_mem.o cps_obj.o cps_pal.o cps_run.o cps_rw.o cps_scr.o cpsr.o cpsrd.o \
|
||||
cpst.o ctv.o kabuki.o ps.o ps_m.o ps_z.o qs.o qs_c.o qs_z.o \
|
||||
\
|
||||
cps3run.o cps3snd.o \
|
||||
\
|
||||
deco16ic.o \
|
||||
\
|
||||
gal_gfx.o gal_run.o gal_sound.o gal_stars.o \
|
||||
\
|
||||
irem_cpu.o \
|
||||
\
|
||||
k051316.o k051733.o k051960.o k052109.o k053245.o k053247.o k053251.o k053936.o k054000.o konamiic.o \
|
||||
\
|
||||
neo_decrypt.o neo_palette.o neo_run.o neo_sprite.o neo_text.o neo_upd4990a.o neogeo.o \
|
||||
\
|
||||
pgm_crypt.o pgm_draw.o pgm_prot.o pgm_run.o \
|
||||
\
|
||||
psikyo_palette.o psikyo_sprite.o psikyo_tile.o psikyosh_render.o \
|
||||
\
|
||||
fd1089.o fd1094.o genesis_vid.o mc8123.o sys16_fd1094.o sys16_gfx.o sys16_run.o \
|
||||
\
|
||||
cchip.o pc080sn.o pc090oj.o taito.o taito_ic.o taito_m68705.o tc0100scn.o tc0110pcr.o tc0140syt.o tc0150rod.o \
|
||||
tc0180vcu.o tc0220ioc.o tc0280grd.o tc0360pri.o tc0480scp.o tc0510nio.o tc0640fio.o tnzs_prot.o \
|
||||
\
|
||||
toa_bcu2.o toa_extratext.o toa_gp9001.o toa_palette.o toaplan1.o toaplan.o \
|
||||
\
|
||||
nmk004.o \
|
||||
\
|
||||
megadrive.o \
|
||||
\
|
||||
snes_65816.o snes_io.o snes_main.o snes_mem.o snes_ppu.o snes_spc700.o
|
||||
|
||||
|
||||
|
||||
autobj += $(depobj)
|
||||
|
||||
-623
@@ -1,623 +0,0 @@
|
||||
# Makefile for FBA, for use with GNU make & Microsoft Visual C++ 2012
|
||||
#
|
||||
# The first pass makes sure all intermediary targets are present. The second pass updates
|
||||
# any targets, if necessary. (Intermediary) targets which have their own unique rules
|
||||
# are generated as required.
|
||||
|
||||
MAKEOS = cygwin
|
||||
ifeq ($(MAKEOS),)
|
||||
MAKEOS = $(OSTYPE)
|
||||
endif
|
||||
|
||||
unexport
|
||||
|
||||
#
|
||||
# Declare variables
|
||||
#
|
||||
|
||||
# Specify the name of the executable file, without ".exe"
|
||||
NAME = fba
|
||||
COMPILENAME = 3
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
ifdef BUILD_A68K
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
ifdef BUILD_X86_ASM
|
||||
undefine BUILD_X86_ASM
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
undefine BUILD_A68K
|
||||
endif
|
||||
|
||||
ifndef CPUTYPE
|
||||
CPUTYPE = i686
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
MMX = 1
|
||||
else
|
||||
MMX = 0
|
||||
endif
|
||||
|
||||
ifndef BUILD_X86_ASM
|
||||
NAME := $(NAME)x
|
||||
COMPILENAME := $(COMPILENAME)x
|
||||
endif
|
||||
ifdef BUILD_X64_EXE
|
||||
NAME = fba64
|
||||
COMPILENAME = 6
|
||||
endif
|
||||
ifdef DEBUG
|
||||
NAME := $(NAME)d
|
||||
COMPILENAME := $(COMPILENAME)d
|
||||
endif
|
||||
ifdef SYMBOL
|
||||
NAME := $(NAME)s
|
||||
COMPILENAME := $(COMPILENAME)s
|
||||
endif
|
||||
ifndef UNICODE
|
||||
NAME := $(NAME)a
|
||||
COMPILENAME := $(COMPILENAME)a
|
||||
endif
|
||||
ifdef BUILD_VS_XP_TARGET
|
||||
NAME := $(NAME)xp
|
||||
endif
|
||||
|
||||
cpulevel = 6
|
||||
ifeq ($(CPUTYPE),i586)
|
||||
cpulevel = 5
|
||||
endif
|
||||
ifeq ($(CPUTYPE),pentium)
|
||||
cpulevel = 5
|
||||
endif
|
||||
ifeq ($(CPUTYPE),k6)
|
||||
cpulevel = 5
|
||||
endif
|
||||
ifeq ($(CPUTYPE),i786)
|
||||
cpulevel = 7
|
||||
endif
|
||||
ifeq ($(CPUTYPE),pentium4)
|
||||
cpulevel = 7
|
||||
endif
|
||||
ifeq ($(CPUTYPE),athlon)
|
||||
cpulevel = 7
|
||||
endif
|
||||
|
||||
ifeq ($(cpulevel),6)
|
||||
ppro = ppro
|
||||
else
|
||||
NAME := $(NAME)$(CPUTYPE)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Specify paths/files
|
||||
#
|
||||
|
||||
objdir = obj/VC/$(COMPILENAME)/
|
||||
srcdir = src/
|
||||
|
||||
include makefile.burn_rules
|
||||
include makefile.burner_win32_rules
|
||||
|
||||
incdir = $(foreach dir,$(alldir),/I$(srcdir)$(dir)) /I$(objdir)dep/generated
|
||||
|
||||
ifdef UNICODE
|
||||
# lib = unicows.lib
|
||||
endif
|
||||
|
||||
lib += user32.lib gdi32.lib comdlg32.lib comctl32.lib shell32.lib winmm.lib ole32.lib shlwapi.lib advapi32.lib setupapi.lib wininet.lib
|
||||
|
||||
ifdef INCLUDE_AVI_RECORDING
|
||||
lib += vfw32.lib
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
autobj += hq3xs.o hq_shared32.o
|
||||
endif
|
||||
|
||||
ifdef BUILD_A68K
|
||||
a68k.o = $(objdir)cpu/a68k/a68k.o
|
||||
endif
|
||||
|
||||
license.rtf = $(srcdir)dep/generated/license.rtf
|
||||
driverlist.h = $(srcdir)dep/generated/driverlist.h
|
||||
ctv.h = $(srcdir)dep/generated/ctv.h
|
||||
toa_gp9001_func.h = $(srcdir)dep/generated/toa_gp9001_func.h
|
||||
neo_sprite_func.h = $(srcdir)dep/generated/neo_sprite_func.h
|
||||
cave_tile_func.h = $(srcdir)dep/generated/cave_tile_func.h
|
||||
cave_sprite_func.h = $(srcdir)dep/generated/cave_sprite_func.h
|
||||
psikyo_tile_func.h = $(srcdir)dep/generated/psikyo_tile_func.h
|
||||
pgm_sprite.h = $(srcdir)dep/generated/pgm_sprite.h
|
||||
build_details.h = $(srcdir)dep/generated/build_details.h
|
||||
|
||||
allobj = $(objdir)cpu/m68k/m68kcpu.o $(objdir)cpu/m68k/m68kops.o $(objdir)burner/win32/resource.res \
|
||||
$(foreach file,$(autobj:.o=.c), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .c,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.cpp), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .cpp,.o,$(wildcard $(srcdir)$(dir)/$(file))))))) \
|
||||
$(foreach file,$(autobj:.o=.asm), \
|
||||
$(foreach dir,$(alldir),$(subst $(srcdir),$(objdir), \
|
||||
$(firstword $(subst .asm,.o,$(wildcard $(srcdir)$(dir)/$(file)))))))
|
||||
|
||||
ifdef BUILD_A68K
|
||||
allobj += $(a68k.o)
|
||||
endif
|
||||
|
||||
autdrv := $(drvsrc:.cpp=.o)
|
||||
|
||||
#
|
||||
#
|
||||
# Specify compiler/linker/assembler
|
||||
#
|
||||
#
|
||||
|
||||
CC = cl
|
||||
CXX = cl
|
||||
LD = link
|
||||
AS = nasm
|
||||
|
||||
incdir += /Isrc\dep\VC\include
|
||||
|
||||
ifndef BUILD_X64_EXE
|
||||
LDFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:X86 /LIBPATH:src\VC\lib /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcd.lib # /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcp.lib /NODEFAULTLIB:libcpd.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcpmtd.lib
|
||||
else
|
||||
LDFLAGS = /NOLOGO /INCREMENTAL:NO /MACHINE:X64 /LIBPATH:src\VC\lib /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcd.lib # /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:libcp.lib /NODEFAULTLIB:libcpd.lib /NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcpmtd.lib
|
||||
endif
|
||||
|
||||
ASFLAGS = -O1 -f coff -w-orphan-labels
|
||||
|
||||
DEF = /DBUILD_WIN32 /DUSE_SPEEDHACKS /DFILENAME=$(NAME) /DMMX=$(MMX) /DZLIB_WINAPI /DDECL_SPEC=__cdecl
|
||||
|
||||
# For lib7z
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) /D_7ZIP_PPMD_SUPPPORT
|
||||
endif
|
||||
|
||||
ifdef UNICODE
|
||||
DEF := $(DEF) /D_UNICODE
|
||||
endif
|
||||
|
||||
ifdef SPECIALBUILD
|
||||
DEF := $(DEF) /DSPECIALBUILD=$(SPECIALBUILD)
|
||||
endif
|
||||
|
||||
ifdef FASTCALL
|
||||
DEF := $(DEF) /DFASTCALL
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
DEF := $(DEF) /DFBA_DEBUG
|
||||
endif
|
||||
|
||||
ifdef ROM_VERIFY
|
||||
DEF := $(DEF) /DROM_VERIFY
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
DEF := $(DEF) /DINCLUDE_7Z_SUPPORT
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_AVI_RECORDING
|
||||
DEF := $(DEF) /DINCLUDE_AVI_RECORDING
|
||||
endif
|
||||
|
||||
ifdef LSB_FIRST
|
||||
DEF := $(DEF) /DLSB_FIRST
|
||||
endif
|
||||
|
||||
ifdef INCLUDE_LIB_PNGH
|
||||
DEF := $(DEF) /DINCLUDE_LIB_PNGH
|
||||
endif
|
||||
|
||||
ifdef BUILD_A68K
|
||||
DEF := $(DEF) /DBUILD_A68K
|
||||
endif
|
||||
|
||||
ifdef BUILD_X86_ASM
|
||||
DEF := $(DEF) /DBUILD_X86_ASM
|
||||
endif
|
||||
|
||||
ifdef BUILD_X64_EXE
|
||||
DEF := $(DEF) /DBUILD_X64_EXE
|
||||
ifdef INCLUDE_CPLUSPLUS11_FILES
|
||||
DEF := $(DEF) /DXBYAK_NO_OP_NAMES /DMIPS3_X64_DRC
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef BUILD_VS_XP_TARGET
|
||||
DEF := $(DEF) /DBUILD_VS_XP_TARGET
|
||||
endif
|
||||
|
||||
ifdef USE_SEGOE
|
||||
DEF := $(DEF) /DUSE_SEGOE
|
||||
endif
|
||||
|
||||
ifdef SYMBOL
|
||||
CFLAGS = /nologo /Od /GF /GS /RTC1 /Zi /Zc:forScope /MTd /EHsc /Fp$(objdir)/dep/generated/ # /Wall
|
||||
ASFLAGS += -g
|
||||
LDFLAGS += /DEBUG
|
||||
DEF := $(DEF) /D_DEBUG
|
||||
|
||||
ifdef PROFILE
|
||||
CFLAGS += /Oy
|
||||
else
|
||||
CFLAGS += /Oy-
|
||||
endif
|
||||
|
||||
else
|
||||
CFLAGS = /nologo /w /O2 /Ox /Oi /Ot /Oy /Ob2 /GF /Gs /Gy /GL /Zc:forScope /MT /EHsc
|
||||
LDFLAGS += /LTCG:STATUS
|
||||
endif
|
||||
|
||||
ifdef BUILD_VS_XP_TARGET
|
||||
CFLAGS += /D_USING_V110_SDK71_
|
||||
LDFLAGS += /SUBSYSTEM:WINDOWS,5.01
|
||||
endif
|
||||
|
||||
# Change the priority of some warnings so they are only shown at warning level 4. They are:
|
||||
# lvl4 C4127: conditional expression is constant
|
||||
# lvl4 C4201: nonstandard extension used : nameless struct/union
|
||||
# lvl1 C4244: 'variable' : conversion from 'type' to 'type', possible loss of data
|
||||
# 3 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
||||
# lvl4 C4505: 'function' : unreferenced local function has been removed
|
||||
# lvl4 C4514: 'function' : unreferenced inline function has been removed
|
||||
# lvl4 C4611: interaction between 'function' and C++ object destruction is non-portable
|
||||
# lvl4 C4710: 'function' : function not inlined
|
||||
# lvl1 C4799: No EMMS at end of function 'function'
|
||||
# lvl3 C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
CFLAGS += /w44201 /w44127 /w44244 /w44505 /w44514 /w44611 /w44710 /w44799 /w44800 $(DEF) $(incdir)
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
|
||||
#
|
||||
#
|
||||
# Specify paths
|
||||
#
|
||||
#
|
||||
|
||||
vpath %.asm $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.cpp $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.c $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.h $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
vpath %.rc $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
|
||||
vpath %.o $(foreach dir,$(alldir),$(objdir)$(dir)/ )
|
||||
vpath %.res $(foreach dir,$(alldir),$(srcdir)$(dir)/ )
|
||||
|
||||
#
|
||||
#
|
||||
# Rules
|
||||
#
|
||||
#
|
||||
|
||||
.PHONY: all init cleandep touch clean
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
|
||||
all: init $(autdrv) $(autobj) resource.res
|
||||
$(MAKE) -f makefile.vc
|
||||
|
||||
else
|
||||
|
||||
all: $(NAME).exe
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
#
|
||||
# Rule for linking the executable
|
||||
#
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
|
||||
$(objdir)/drivers.lib: $(autdrv)
|
||||
@echo Linking drivers...
|
||||
ifdef BUILD_X64_EXE
|
||||
@LIB /MACHINE:X64 /LTCG /OUT:$@ $^
|
||||
else
|
||||
@LIB /MACHINE:X86 /LTCG /OUT:$@ $^
|
||||
endif
|
||||
|
||||
$(NAME).exe: $(allobj) $(objdir)/drivers.lib
|
||||
@echo
|
||||
@echo Linking executable $(NAME).exe...
|
||||
$(LD) $(LDFLAGS) /OUT:$@ $^ $(lib)
|
||||
|
||||
ifdef DEBUG
|
||||
|
||||
# Don't compress when making a debug build
|
||||
|
||||
else
|
||||
ifdef COMPRESS
|
||||
@upx --best $@
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
ifdef FORCE_UPDATE
|
||||
$(build_details.h): FORCE
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Generate the gamelist
|
||||
#
|
||||
|
||||
burn.o burn.d: driverlist.h
|
||||
|
||||
$(driverlist.h): $(drvsrc) $(srcdir)dep/scripts/gamelist.pl
|
||||
ifdef PERL
|
||||
@$(srcdir)dep/scripts/gamelist.pl -o $@ -l gamelist.txt \
|
||||
$(filter %.cpp,$(foreach file,$(drvsrc:.o=.cpp),$(foreach dir,$(alldir), \
|
||||
$(firstword $(wildcard $(srcdir)$(dir)/$(file))))))
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Verify if driverlist.h needs to be updated
|
||||
#
|
||||
|
||||
#ifeq ($(MAKELEVEL),1)
|
||||
#ifdef FORCE_UPDATE
|
||||
#$(driverlist.h): FORCE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#
|
||||
# Fix the .rc file
|
||||
#
|
||||
|
||||
resource.res resource.d: app.rc version.rc version.h $(build_details.h) $(license.rtf)
|
||||
|
||||
$(license.rtf): $(srcdir)license.txt $(srcdir)dep/scripts/license2rtf.pl
|
||||
|
||||
ifdef PERL
|
||||
ifdef USE_SEGOE
|
||||
$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf) -f 'Segoe UI'
|
||||
else
|
||||
$(srcdir)dep/scripts/license2rtf.pl $< -o $(srcdir)dep/generated/$(@F:.rc=.rtf)
|
||||
endif
|
||||
else
|
||||
ifeq ($(MAKELEVEL),2)
|
||||
@echo
|
||||
@echo Warning: Perl is not available on this system.
|
||||
@echo $@ cannot be updated or created!
|
||||
@echo
|
||||
endif
|
||||
endif
|
||||
|
||||
resource.rc: app.rc $(license.rc) $(srcdir)burner/resource/fba.ico $(srcdir)burner/resource/about.bmp $(srcdir)burner/resource/splash.bmp $(srcdir)burner/resource/misc.bmp
|
||||
|
||||
#
|
||||
# Generate some info on the build details
|
||||
#
|
||||
|
||||
about.o about.d systeminfo.o systeminfo.d: $(build_details.h)
|
||||
|
||||
$(build_details.h): $(srcdir)dep/scripts/build_details.cpp
|
||||
$(CC) $(CFLAGS) $< /Fo$(objdir)dep/generated/ /Fe$(objdir)dep/generated/build_details.exe
|
||||
$(objdir)dep/generated/build_details.exe >$@
|
||||
|
||||
#
|
||||
# Compile 68000 cores
|
||||
#
|
||||
|
||||
# A68K
|
||||
|
||||
ifdef BUILD_A68K
|
||||
$(a68k.o): fba_make68k.c
|
||||
echo "Compiling A68K MC68000 core... "
|
||||
$(CC) $(CFLAGS) -DWIN32 $< /Fo$(subst $(srcdir),$(objdir),$(<D))/ /Fe$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
|
||||
$(subst $(srcdir),$(objdir),$(<D))/$(<F:.c=.exe) $(@:.o=.asm) $(@D)/a68k_tab.asm 00 $(ppro)
|
||||
@echo Assembling A68K MC68000 core...
|
||||
$(AS) $(ASFLAGS) $(@:.o=.asm) -o $@
|
||||
endif
|
||||
|
||||
# Musashi
|
||||
|
||||
$(objdir)cpu/m68k/m68kcpu.o: $(srcdir)cpu/m68k/m68kcpu.c $(objdir)dep/generated/m68kops.h $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(srcdir)cpu/m68k/m68kcpu.c /Fo$(objdir)cpu/m68k/m68kcpu.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)dep/generated/m68kops.c /Fo$(objdir)cpu/m68k/m68kops.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopac.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopac.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)dep/generated/m68kopac.c /Fo$(objdir)cpu/m68k/m68kopac.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopdm.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopdm.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)dep/generated/m68kopdm.c /Fo$(objdir)cpu/m68k/m68kopdm.o
|
||||
|
||||
$(objdir)cpu/m68k/m68kopnz.o: $(objdir)cpu/m68k/m68kmake.exe $(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kopnz.c $(srcdir)cpu/m68k/m68k.h $(srcdir)cpu/m68k/m68kconf.h
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" /c $(objdir)dep/generated/m68kopnz.c /Fo$(objdir)cpu/m68k/m68kopnz.o
|
||||
|
||||
$(objdir)dep/generated/m68kops.h: $(objdir)cpu/m68k/m68kmake.exe $(srcdir)cpu/m68k/m68k_in.c
|
||||
$(objdir)/cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
|
||||
|
||||
$(objdir)cpu/m68k/m68kmake.exe: $(srcdir)cpu/m68k/m68kmake.c
|
||||
@echo "Compiling Musashi MC680x0 core... "
|
||||
$(CC) $(CFLAGS) /DINLINE="__inline static" $(srcdir)cpu/m68k/m68kmake.c /Fo$(objdir)cpu/m68k/ /Fe$(objdir)cpu/m68k/m68kmake.exe /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
|
||||
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cvt.h, needed by ctv.cpp
|
||||
#
|
||||
|
||||
ctv.o: $(ctv.h)
|
||||
|
||||
$(ctv.h): ctv_make.cpp
|
||||
@echo Generating... $(srcdir)dep/generated/$(@F)
|
||||
$(CC) $(CXXFLAGS) $< /Fo$(subst $(srcdir),$(objdir),$(<D))/ /Fe$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
|
||||
$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
|
||||
|
||||
#
|
||||
# Extra rules for generated header file toa_gp9001_func.h, needed by toa_gp9001.cpp
|
||||
#
|
||||
|
||||
toa_bcu2.o toa_gp9001.o: $(toa_gp9001_func.h)
|
||||
|
||||
$(toa_gp9001_func.h): $(srcdir)dep/scripts/toa_gp9001_func.pl
|
||||
$(srcdir)dep/scripts/toa_gp9001_func.pl -o $(toa_gp9001_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file neo_sprite_func.h, needed by neo_sprite.cpp
|
||||
#
|
||||
|
||||
neo_sprite.o: $(neo_sprite_func.h)
|
||||
|
||||
$(neo_sprite_func.h): $(srcdir)dep/scripts/neo_sprite_func.pl
|
||||
$(srcdir)dep/scripts/neo_sprite_func.pl -o $(neo_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_tile_func.h, needed by cave_tile.cpp
|
||||
#
|
||||
|
||||
cave_tile.o: $(cave_tile_func.h)
|
||||
|
||||
$(cave_tile_func.h): $(srcdir)dep/scripts/cave_tile_func.pl
|
||||
$(srcdir)dep/scripts/cave_tile_func.pl -o $(cave_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file cave_sprite_func.h, needed by cave_sprite.cpp
|
||||
#
|
||||
|
||||
cave_sprite.o: $(cave_sprite_func.h)
|
||||
|
||||
$(cave_sprite_func.h): $(srcdir)dep/scripts/cave_sprite_func.pl
|
||||
$(srcdir)dep/scripts/cave_sprite_func.pl -o $(cave_sprite_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file psikyo_tile_func.h / psikyo_sprite_func.h, needed by psikyo_tile.cpp / psikyo_sprite.cpp
|
||||
#
|
||||
|
||||
psikyo_tile.o psikyo_sprite.o: $(psikyo_tile_func.h)
|
||||
|
||||
$(psikyo_tile_func.h): $(srcdir)dep/scripts/psikyo_tile_func.pl
|
||||
$(srcdir)dep/scripts/psikyo_tile_func.pl -o $(psikyo_tile_func.h)
|
||||
|
||||
#
|
||||
# Extra rules for generated header file pgm_sprite.h, needed by pgm_draw.cpp
|
||||
#
|
||||
|
||||
pgm_draw.d pgm_draw.o: $(pgm_sprite.h)
|
||||
|
||||
$(pgm_sprite.h): pgm_sprite_create.cpp
|
||||
@echo Generating... $(srcdir)dep/generated/$(@F)
|
||||
$(CC) $(CXXFLAGS) $< /Fo$(subst $(srcdir),$(objdir),$(<D))/ /Fe$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) /link $(LDFLAGS) /SUBSYSTEM:CONSOLE
|
||||
$(subst $(srcdir),$(objdir),$(<D))/$(<F:.cpp=.exe) >$@
|
||||
|
||||
#
|
||||
# Generic rule for resource files
|
||||
#
|
||||
|
||||
%.res: %.rc
|
||||
@echo Compiling resource file... $(<F)
|
||||
rc $(DEF) /n /Fo $(subst $(srcdir),$(objdir),$(<D))/$(@F) $(incdir) $<
|
||||
|
||||
#
|
||||
# Generic rules for C/C++ files
|
||||
#
|
||||
|
||||
ifeq ($(MAKELEVEL),1)
|
||||
|
||||
%.o: %.cpp
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) /c $< /Fo$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) /c /Dinline=__inline $< /Fo$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o$(subst $(srcdir),$(objdir),$(<D))/$(@F)
|
||||
|
||||
else
|
||||
|
||||
%.o: %.c
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CFLAGS) /c /Dinline=__inline $< /Fo $@
|
||||
|
||||
%.o: %.asm
|
||||
@echo Assembling $<...
|
||||
@$(AS) $(ASFLAGS) $< -o $@
|
||||
|
||||
%.o:
|
||||
@echo Compiling $<...
|
||||
@$(CC) $(CXXFLAGS) /c $< /Fo $@
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Phony targets
|
||||
#
|
||||
|
||||
init:
|
||||
|
||||
ifdef DEBUG
|
||||
@echo Making debug build...
|
||||
else
|
||||
@echo Making normal build...
|
||||
endif
|
||||
@echo
|
||||
ifeq ($(MAKEOS),cygwin)
|
||||
@mkdir -p $(foreach dir, $(alldir),$(objdir)$(dir))
|
||||
@mkdir -p $(srcdir)dep/generated
|
||||
else
|
||||
@echo nt
|
||||
@mkdir $(foreach dir, $(alldir),$(objdir)$(dir))
|
||||
@mkdir $(srcdir)dep/generated
|
||||
endif
|
||||
|
||||
touch:
|
||||
@echo Marking all targets for $(NAME) as uptodate...
|
||||
-@touch $(NAME).exe
|
||||
-@touch -c -r $(NAME).exe $(srcdir)/dep/generated/*
|
||||
-@for dir in $(alldir); do touch -c -r $(NAME).exe $(objdir)$$dir/*; done
|
||||
|
||||
clean:
|
||||
@echo Removing all files from $(objdir)...
|
||||
ifeq ($(MAKEOS),cygwin)
|
||||
-@rm -f -r $(objdir)
|
||||
-@rm -f -r $(ctv.h)
|
||||
else
|
||||
-@del -f -s $(objdir)
|
||||
-@del -f -s $(ctv.h)
|
||||
endif
|
||||
|
||||
ifdef PERL
|
||||
@echo Removing all files generated with perl scripts...
|
||||
ifeq ($(MAKEOS),cygwin)
|
||||
-@rm -f -r $(driverlist)
|
||||
else
|
||||
-@del -f -s $(driverlist)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Rule to force recompilation of any target that depends on it
|
||||
#
|
||||
|
||||
FORCE:
|
||||
+17892
File diff suppressed because it is too large.
Load diff
@@ -37,14 +37,18 @@ typedef union {
|
||||
/* PlayStation3 */
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <ppu_intrinsics.h>
|
||||
#include <math.h>
|
||||
#define BURN_ENDIAN_SWAP_INT8(x) (x^1)
|
||||
#define BURN_ENDIAN_SWAP_INT16(x) ({uint16_t t; __sthbrx(&t, x); t;})
|
||||
#define BURN_ENDIAN_SWAP_INT32(x) ({uint32_t t; __stwbrx(&t, x); t;})
|
||||
#define BURN_ENDIAN_SWAP_INT16(x) ({uint16_t tt; __sthbrx(&tt, x); tt;})
|
||||
#define BURN_ENDIAN_SWAP_INT32(x) ({uint32_t tt; __stwbrx(&tt, x); tt;})
|
||||
/* Wii */
|
||||
#elif defined(HW_RVL)
|
||||
#define BURN_ENDIAN_SWAP_INT8(x) (x^1)
|
||||
#define BURN_ENDIAN_SWAP_INT16(x) ({uint16_t t; __sthbrx(&t, 0, x); t;})
|
||||
#define BURN_ENDIAN_SWAP_INT32(x) ({uint32_t t; __stwbrx(&t, 0, x); t;})
|
||||
#define BURN_ENDIAN_SWAP_INT16(x) ({uint16_t tt; __sthbrx(&tt, 0, x); tt;})
|
||||
#define BURN_ENDIAN_SWAP_INT32(x) ({uint32_t tt; __stwbrx(&tt, 0, x); tt;})
|
||||
/* Not sure the asm stuff is working properly, so trying something else for debugging (may be slower) */
|
||||
//#define BURN_ENDIAN_SWAP_INT16(x) (((x) >> 8) | (((x) & 0xFF) << 8))
|
||||
//#define BURN_ENDIAN_SWAP_INT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0xFF) << 24))
|
||||
#endif
|
||||
|
||||
#ifdef NO_64BIT_BYTESWAP
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
#ifndef _LIBRETRO_OPTIMIZATIONS_H_
|
||||
#define _LIBRETRO_OPTIMIZATIONS_H_
|
||||
|
||||
#define BurnHighCol LIBRETRO_COLOR_CONVERT
|
||||
#define BurnHighColSwitch LIBRETRO_COLOR_CONVERT_SWITCH
|
||||
|
||||
#ifdef FRONTEND_SUPPORTS_RGB565
|
||||
#define LIBRETRO_COLOR_15BPP_XBGR(color, unused) (((color & 0x001f) << 11) | ((color & 0x03e0) << 1) | ((color & 0x7c00) >> 10))
|
||||
#define LIBRETRO_COLOR_CONVERT(r, g, b, a) (((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001f))
|
||||
#define LIBRETRO_COLOR_CONVERT_SWITCH(r, g, b, a) (nBurnBpp == 2) ? (((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | ((b >> 3) & 0x001f)) : (((r << 16) & 0xff0000) | ((g << 8) & 0x00ff00) | ((b) & 0x0000ff))
|
||||
#else
|
||||
#define LIBRETRO_COLOR_15BPP_XBGR(color, unused) ((((color & 0x1f) << 10) | (((color & 0x3e0) >> 5) << 5) | (((color & 0x7c00) >> 10))) & 0x7fff)
|
||||
#define LIBRETRO_COLOR_CONVERT(r, g, b, a) (((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001f))
|
||||
#define LIBRETRO_COLOR_CONVERT_SWITCH(r, g, b, a) (nBurnBpp == 2) ? (((r << 7) & 0x7c00) | ((g << 2) & 0x03e0) | ((b >> 3) & 0x001f)) : (((r << 16) & 0xff0000) | ((g << 8) & 0x00ff00) | ((b) & 0x0000ff))
|
||||
#endif
|
||||
#include "streams/file_stream_transforms.h"
|
||||
extern int kNetGame;
|
||||
|
||||
#endif
|
||||
@@ -3,16 +3,24 @@
|
||||
|
||||
#include "gameinp.h"
|
||||
#include "input/inp_keys.h"
|
||||
#include "cd_interface.h"
|
||||
|
||||
#include "streams/file_stream_transforms.h"
|
||||
#include "compat/msvc.h"
|
||||
#include "compat/posix_string.h"
|
||||
#undef stricmp
|
||||
#define stricmp strcasecmp
|
||||
|
||||
extern int bDrvOkay;
|
||||
extern int bRunPause;
|
||||
extern bool bAlwaysProcessKeyboardInput;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define ANSIToTCHAR(str, foo, bar) (str)
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH PATH_MAX
|
||||
#endif
|
||||
|
||||
extern char g_rom_dir[MAX_PATH];
|
||||
|
||||
extern void InpDIPSWResetDIPs (void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,791 @@
|
||||
#include "burner.h"
|
||||
#include "cd_emu.h"
|
||||
|
||||
CDEmuStatusValue CDEmuStatus;
|
||||
TCHAR CDEmuImage[MAX_PATH];
|
||||
|
||||
void NeoCDInfo_Exit() {}
|
||||
|
||||
/**
|
||||
* see src/burner/misc.cpp
|
||||
*/
|
||||
TCHAR* ExtractFilename(TCHAR* fullname)
|
||||
{
|
||||
TCHAR* filename = fullname + _tcslen(fullname);
|
||||
|
||||
do {
|
||||
filename--;
|
||||
} while (filename >= fullname && *filename != _T('\\') && *filename != _T('/') && *filename != _T(':'));
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
TCHAR* LabelCheck(TCHAR* s, TCHAR* pszLabel)
|
||||
{
|
||||
INT32 nLen;
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (pszLabel == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
nLen = _tcslen(pszLabel);
|
||||
|
||||
SKIP_WS(s); // Skip whitespace
|
||||
|
||||
if (_tcsncmp(s, pszLabel, nLen)){ // Doesn't match
|
||||
return NULL;
|
||||
}
|
||||
return s + nLen;
|
||||
}
|
||||
|
||||
INT32 QuoteRead(TCHAR** ppszQuote, TCHAR** ppszEnd, TCHAR* pszSrc) // Read a (quoted) string from szSrc and poINT32 to the end
|
||||
{
|
||||
static TCHAR szQuote[QUOTE_MAX];
|
||||
TCHAR* s = pszSrc;
|
||||
TCHAR* e;
|
||||
|
||||
// Skip whitespace
|
||||
SKIP_WS(s);
|
||||
|
||||
e = s;
|
||||
|
||||
if (*s == _T('\"')) { // Quoted string
|
||||
s++;
|
||||
e++;
|
||||
// Find end quote
|
||||
FIND_QT(e);
|
||||
_tcsncpy(szQuote, s, e - s);
|
||||
// Zero-terminate
|
||||
szQuote[e - s] = _T('\0');
|
||||
e++;
|
||||
} else { // Non-quoted string
|
||||
// Find whitespace
|
||||
FIND_WS(e);
|
||||
_tcsncpy(szQuote, s, e - s);
|
||||
// Zero-terminate
|
||||
szQuote[e - s] = _T('\0');
|
||||
}
|
||||
|
||||
if (ppszQuote) {
|
||||
*ppszQuote = szQuote;
|
||||
}
|
||||
if (ppszEnd) {
|
||||
*ppszEnd = e;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <audio/audio_mixer.h>
|
||||
audio_mixer_sound_t *cdsound;
|
||||
audio_mixer_voice_t *cdvoice;
|
||||
|
||||
/**
|
||||
* see src/intf/cd/sdl/cdsound.cpp
|
||||
*/
|
||||
int wav_open(TCHAR* szFile)
|
||||
{
|
||||
wav_exit();
|
||||
|
||||
FILE *fp;
|
||||
void *buffer;
|
||||
int32_t size;
|
||||
|
||||
fp = fopen(szFile, "rb");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
buffer = (void *)malloc(size+1);
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
fread(buffer, size, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
char *ext = strrchr(szFile, '.');
|
||||
if (ext)
|
||||
{
|
||||
if (!strcmp(".wav", ext)) {
|
||||
return 0;
|
||||
// Following code is crashing the core, no idea why
|
||||
//cdsound = audio_mixer_load_wav(buffer, size);
|
||||
}
|
||||
else if (!strcmp(".mp3", ext)) {
|
||||
return 0;
|
||||
//cdsound = audio_mixer_load_mp3(buffer, size);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void wav_stop()
|
||||
{
|
||||
if(!cdvoice) return;
|
||||
audio_mixer_stop(cdvoice);
|
||||
}
|
||||
|
||||
void wav_play()
|
||||
{
|
||||
if(!cdsound) return;
|
||||
cdvoice = audio_mixer_play(cdsound, true, 100, NULL);
|
||||
}
|
||||
|
||||
void wav_exit()
|
||||
{
|
||||
if(!cdsound) return;
|
||||
audio_mixer_destroy(cdsound);
|
||||
}
|
||||
|
||||
/**
|
||||
* see src/intf/cd/sdl/cd_isowav.cpp
|
||||
*/
|
||||
#define MAXIMUM_NUMBER_TRACKS (100)
|
||||
|
||||
#define CD_FRAMES_MINUTE (60 * 75)
|
||||
#define CD_FRAMES_SECOND ( 75)
|
||||
#define CD_FRAMES_PREGAP ( 2 * 75)
|
||||
|
||||
struct isowavTRACK_DATA {
|
||||
char Control;
|
||||
int Mode;
|
||||
char TrackNumber;
|
||||
char Address[4];
|
||||
TCHAR* Filename;
|
||||
};
|
||||
|
||||
struct isowavCDROM_TOC {
|
||||
char FirstTrack;
|
||||
char LastTrack;
|
||||
isowavTRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
|
||||
};
|
||||
|
||||
static isowavCDROM_TOC* isowavTOC;
|
||||
|
||||
static FILE* isowavFile = NULL;
|
||||
static int isowavTrack = 0;
|
||||
static int isowavLBA = 0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static const char* isowavLBAToMSF(const int LBA)
|
||||
{
|
||||
static char address[4];
|
||||
|
||||
address[0] = 0;
|
||||
address[1] = LBA / CD_FRAMES_MINUTE;
|
||||
address[2] = LBA % CD_FRAMES_MINUTE / CD_FRAMES_SECOND;
|
||||
address[3] = LBA % CD_FRAMES_SECOND;
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
static int isowavMSFToLBA(const char* address)
|
||||
{
|
||||
int LBA;
|
||||
|
||||
LBA = address[3];
|
||||
LBA += address[2] * CD_FRAMES_SECOND;
|
||||
LBA += address[1] * CD_FRAMES_MINUTE;
|
||||
|
||||
return LBA;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static int isowavGetTrackSizes()
|
||||
{
|
||||
// determine the lenght of the .iso / .mp3 files to complete the TOC
|
||||
|
||||
FILE* h;
|
||||
|
||||
for (int i = isowavTOC->FirstTrack - 1; i < isowavTOC->LastTrack; i++) {
|
||||
|
||||
const char* address;
|
||||
|
||||
if (isowavTOC->TrackData[i].Control & 4) {
|
||||
|
||||
// data track
|
||||
|
||||
h = _tfopen(isowavTOC->TrackData[i].Filename, _T("rb"));
|
||||
if (h == NULL) return 1;
|
||||
|
||||
if (isowavTOC->TrackData[i].Mode == 2352) {
|
||||
fseek(h, 16, SEEK_END);
|
||||
address = isowavLBAToMSF((ftell(h) + 2335) / 2336 + isowavMSFToLBA(isowavTOC->TrackData[i].Address));
|
||||
} else {
|
||||
fseek(h, 0, SEEK_END);
|
||||
address = isowavLBAToMSF((ftell(h) + 2047) / 2048 + isowavMSFToLBA(isowavTOC->TrackData[i].Address));
|
||||
}
|
||||
|
||||
if(h) fclose(h);
|
||||
|
||||
} else {
|
||||
|
||||
// audio track
|
||||
|
||||
h = _tfopen(isowavTOC->TrackData[i].Filename, _T("rb"));
|
||||
if (h == NULL)return 1;
|
||||
|
||||
fseek(h, 0, SEEK_END);
|
||||
|
||||
address = isowavLBAToMSF(((ftell(h) + 2047) / 2048) + isowavMSFToLBA(isowavTOC->TrackData[i].Address));
|
||||
if(h) fclose(h);
|
||||
}
|
||||
|
||||
isowavTOC->TrackData[i + 1].Address[0] += 0; // always 0 [?]
|
||||
isowavTOC->TrackData[i + 1].Address[1] += address[1]; // M
|
||||
isowavTOC->TrackData[i + 1].Address[2] += address[2]; // S
|
||||
isowavTOC->TrackData[i + 1].Address[3] += address[3]; // F
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isowavTestISO()
|
||||
{
|
||||
TCHAR fullname[MAX_PATH];
|
||||
TCHAR* filename;
|
||||
int length = 0;
|
||||
int offset = 0;
|
||||
int track = 2;
|
||||
FILE* h;
|
||||
|
||||
_tcscpy(fullname, CDEmuImage);
|
||||
length = _tcslen(fullname);
|
||||
|
||||
// assume CD-ROM mode1/2048 format
|
||||
|
||||
if (length <= 4 && (_tcscmp(_T(".iso"), fullname + length - 4) || _tcscmp(_T(".bin"), fullname + length - 4))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// create a TOC with only the data track first
|
||||
|
||||
isowavTOC->FirstTrack = 1;
|
||||
isowavTOC->LastTrack = 1;
|
||||
|
||||
isowavTOC->TrackData[0].TrackNumber = 1;
|
||||
|
||||
isowavTOC->TrackData[0].Address[1] = 0;
|
||||
isowavTOC->TrackData[0].Address[2] = 2;
|
||||
isowavTOC->TrackData[0].Address[3] = 0;
|
||||
|
||||
isowavTOC->TrackData[0].Filename = (TCHAR*)malloc((length + 1) * sizeof(TCHAR));
|
||||
if (isowavTOC->TrackData[0].Filename == NULL) {
|
||||
return 1;
|
||||
}
|
||||
_tcscpy(isowavTOC->TrackData[0].Filename, fullname);
|
||||
|
||||
isowavTOC->TrackData[0].Control = 4;
|
||||
|
||||
// if the filename has a number in it, try to find .mp3 tracks
|
||||
|
||||
filename = ExtractFilename(fullname);
|
||||
offset = (filename - fullname) + length - 6;
|
||||
while (offset >= 0 && fullname[offset] != _T('0') && fullname[offset + 1] != _T('1')) {
|
||||
offset--;
|
||||
}
|
||||
if (offset < 0) {
|
||||
return isowavGetTrackSizes();
|
||||
}
|
||||
|
||||
_stprintf(fullname + length - 4, _T(".wav"));
|
||||
|
||||
while (1) {
|
||||
fullname[offset] = _T('0') + track / 10; fullname[offset + 1] = _T('0') + track % 10;
|
||||
|
||||
if ((h = _tfopen(fullname, _T("rb"))) == NULL) {
|
||||
break;
|
||||
}
|
||||
fclose(h);
|
||||
|
||||
isowavTOC->TrackData[track - 1].TrackNumber = track;
|
||||
|
||||
isowavTOC->TrackData[track - 1].Filename = (TCHAR*)malloc((length + 1) * sizeof(TCHAR));
|
||||
if (isowavTOC->TrackData[track - 1].Filename == NULL) {
|
||||
return 1;
|
||||
}
|
||||
_tcscpy(isowavTOC->TrackData[track - 1].Filename, fullname);
|
||||
|
||||
isowavTOC->LastTrack = track;
|
||||
|
||||
track++;
|
||||
}
|
||||
|
||||
return isowavGetTrackSizes();
|
||||
}
|
||||
|
||||
static int isowavParseCueFile()
|
||||
{
|
||||
TCHAR szLine[1024];
|
||||
TCHAR szFile[1024];
|
||||
TCHAR* s;
|
||||
TCHAR* t;
|
||||
FILE* h;
|
||||
int track = 0;
|
||||
int length;
|
||||
|
||||
isowavTOC->FirstTrack = 1;
|
||||
isowavTOC->LastTrack = 1;
|
||||
|
||||
isowavTOC->TrackData[0].Address[1] = 0;
|
||||
isowavTOC->TrackData[0].Address[2] = 2;
|
||||
isowavTOC->TrackData[0].Address[3] = 0;
|
||||
|
||||
h = _tfopen(CDEmuImage, _T("rt"));
|
||||
if (h == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (_fgetts(szLine, sizeof(szLine), h) == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
length = _tcslen(szLine);
|
||||
// get rid of the linefeed at the end
|
||||
while (length && (szLine[length - 1] == _T('\r') || szLine[length - 1] == _T('\n'))) {
|
||||
szLine[length - 1] = 0;
|
||||
length--;
|
||||
}
|
||||
|
||||
s = szLine;
|
||||
|
||||
// file info
|
||||
if ((t = LabelCheck(s, _T("FILE"))) != 0) {
|
||||
s = t;
|
||||
|
||||
TCHAR* szQuote;
|
||||
|
||||
// read filename
|
||||
QuoteRead(&szQuote, NULL, s);
|
||||
|
||||
sprintf(szFile, "%s/%s", g_rom_dir, szQuote);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// track info
|
||||
if ((t = LabelCheck(s, _T("TRACK"))) != 0) {
|
||||
s = t;
|
||||
|
||||
// track number
|
||||
track = _tcstol(s, &t, 10);
|
||||
|
||||
if (track < 1 || track > MAXIMUM_NUMBER_TRACKS) {
|
||||
fclose(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (track < isowavTOC->FirstTrack) {
|
||||
isowavTOC->FirstTrack = track;
|
||||
}
|
||||
if (track > isowavTOC->LastTrack) {
|
||||
isowavTOC->LastTrack = track;
|
||||
}
|
||||
isowavTOC->TrackData[track - 1].TrackNumber = track;
|
||||
|
||||
isowavTOC->TrackData[track - 1].Filename = (TCHAR*)malloc((_tcslen(szFile) + 1) * sizeof(TCHAR));
|
||||
if (isowavTOC->TrackData[track - 1].Filename == NULL) {
|
||||
fclose(h);
|
||||
return 1;
|
||||
}
|
||||
_tcscpy(isowavTOC->TrackData[track - 1].Filename, szFile);
|
||||
|
||||
s = t;
|
||||
|
||||
// type of track
|
||||
|
||||
if ((t = LabelCheck(s, _T("MODE1/2048"))) != 0) {
|
||||
isowavTOC->TrackData[track - 1].Control = 4;
|
||||
isowavTOC->TrackData[track - 1].Mode = 2048;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ((t = LabelCheck(s, _T("MODE1/2352"))) != 0) {
|
||||
isowavTOC->TrackData[track - 1].Control = 4;
|
||||
isowavTOC->TrackData[track - 1].Mode = 2352;
|
||||
|
||||
continue;
|
||||
}
|
||||
if ((t = LabelCheck(s, _T("AUDIO"))) != 0) {
|
||||
isowavTOC->TrackData[track - 1].Control = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// pregap
|
||||
if ((t = LabelCheck(s, _T("PREGAP"))) != 0) {
|
||||
s = t;
|
||||
|
||||
int M, S, F;
|
||||
|
||||
// pregap M
|
||||
M = _tcstol(s, &t, 10);
|
||||
s = t + 1;
|
||||
// pregap S
|
||||
S = _tcstol(s, &t, 10);
|
||||
s = t + 1;
|
||||
// pregap F
|
||||
F = _tcstol(s, &t, 10);
|
||||
|
||||
if (M < 0 || M > 100 || S < 0 || S > 59 || F < 0 || F > 74) {
|
||||
fclose(h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
isowavTOC->TrackData[track - 1].Address[1] = M;
|
||||
isowavTOC->TrackData[track - 1].Address[2] = S;
|
||||
isowavTOC->TrackData[track - 1].Address[3] = F;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(h);
|
||||
|
||||
return isowavGetTrackSizes();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static int isowavExit()
|
||||
{
|
||||
wav_exit();
|
||||
|
||||
if (isowavFile) {
|
||||
fclose(isowavFile);
|
||||
isowavFile = NULL;
|
||||
}
|
||||
|
||||
isowavTrack = 0;
|
||||
isowavLBA = 0;
|
||||
|
||||
if (isowavTOC) {
|
||||
for (int i = 0; i < MAXIMUM_NUMBER_TRACKS; i++) {
|
||||
free(isowavTOC->TrackData[i].Filename);
|
||||
}
|
||||
|
||||
free(isowavTOC);
|
||||
isowavTOC = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isowavInit()
|
||||
{
|
||||
wav_exit();
|
||||
|
||||
isowavTOC = (isowavCDROM_TOC*)malloc(sizeof(isowavCDROM_TOC));
|
||||
if (isowavTOC == NULL) {
|
||||
return 1;
|
||||
}
|
||||
memset(isowavTOC, 0, sizeof(isowavCDROM_TOC));
|
||||
|
||||
TCHAR* filename = ExtractFilename(CDEmuImage);
|
||||
|
||||
if (_tcslen(filename) < 4) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (_tcscmp(_T(".cue"), filename + _tcslen(filename) - 4) == 0) {
|
||||
if (isowavParseCueFile()) {
|
||||
dprintf(_T("*** Couldn't parse .cue file\n"));
|
||||
isowavExit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (isowavTestISO()) {
|
||||
dprintf(_T("*** Couldn't find .iso / .bin file\n"));
|
||||
isowavExit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf(_T(" CD image TOC read\n"));
|
||||
|
||||
for (int i = isowavTOC->FirstTrack - 1; i < isowavTOC->LastTrack; i++) {
|
||||
dprintf(_T(" track %2i start %02i:%02i:%02i control 0x%02X %s\n"), isowavTOC->TrackData[i].TrackNumber, isowavTOC->TrackData[i].Address[1], isowavTOC->TrackData[i].Address[2], isowavTOC->TrackData[i].Address[3], isowavTOC->TrackData[i].Control, isowavTOC->TrackData[i].Filename);
|
||||
}
|
||||
dprintf(_T(" total running time %02i:%02i:%02i\n"), isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[1], isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[2], isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[3]);
|
||||
|
||||
CDEmuStatus = idle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TCHAR* GetIsoPath()
|
||||
{
|
||||
if(isowavTOC) {
|
||||
return isowavTOC->TrackData[0].Filename;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int isowavStop()
|
||||
{
|
||||
wav_stop();
|
||||
|
||||
if (isowavFile) {
|
||||
fclose(isowavFile);
|
||||
isowavFile = NULL;
|
||||
}
|
||||
CDEmuStatus = idle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isowavPlayLBA(int LBA)
|
||||
{
|
||||
isowavLBA = LBA;
|
||||
|
||||
for (isowavTrack = isowavTOC->FirstTrack - 1; isowavTrack < isowavTOC->LastTrack; isowavTrack++) {
|
||||
if (isowavLBA < isowavMSFToLBA(isowavTOC->TrackData[isowavTrack + 1].Address)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isowavTrack >= isowavTOC->LastTrack) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bprintf(PRINT_IMPORTANT, _T(" playing track %2i - %s\n"), isowavTrack + 1, isowavTOC->TrackData[isowavTrack].Filename);
|
||||
|
||||
isowavFile = _tfopen(isowavTOC->TrackData[isowavTrack].Filename, _T("rb"));
|
||||
if (isowavFile == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( strstr(isowavTOC->TrackData[isowavTrack].Filename, _T(".wav")) || strstr(isowavTOC->TrackData[isowavTrack].Filename, _T(".WAV"))) {
|
||||
// is a wav, no need to keep this file pointer
|
||||
if (isowavFile) {
|
||||
fclose(isowavFile);
|
||||
isowavFile = NULL;
|
||||
}
|
||||
|
||||
if(wav_open(isowavTOC->TrackData[isowavTrack].Filename)) {
|
||||
wav_play();
|
||||
} else {
|
||||
// error creating the WAV stream
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//dprintf(_T("*** WAV: wBitsPerSample: %d \n"), wav->g_pStreamingSound->m_pWaveFile->m_pwfx->wBitsPerSample);
|
||||
//dprintf(_T("*** WAV: nAvgBytesPerSec: %d \n"), wav->g_pStreamingSound->m_pWaveFile->m_pwfx->nAvgBytesPerSec);
|
||||
//dprintf(_T("*** WAV: m_dwSize: %d \n"), wav->g_pStreamingSound->m_pWaveFile->m_dwSize);
|
||||
//dprintf(_T("*** WAV: nBlockAlign: %d \n"), wav->g_pStreamingSound->m_pWaveFile->m_pwfx->nBlockAlign);
|
||||
|
||||
isowavLBA = isowavMSFToLBA(isowavTOC->TrackData[isowavTrack].Address);
|
||||
CDEmuStatus = playing;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isowavPlay(unsigned char M, unsigned char S, unsigned char F)
|
||||
{
|
||||
const char address[] = { 0, M, S, F };
|
||||
|
||||
return isowavPlayLBA(isowavMSFToLBA(address));
|
||||
}
|
||||
|
||||
static int isowavLoadSector(int LBA, char* pBuffer)
|
||||
{
|
||||
LBA += CD_FRAMES_PREGAP;
|
||||
|
||||
if (LBA != isowavLBA) {
|
||||
|
||||
int track;
|
||||
|
||||
for (track = isowavTOC->FirstTrack - 1; track < isowavTOC->LastTrack; track++) {
|
||||
if (LBA < isowavMSFToLBA(isowavTOC->TrackData[track + 1].Address)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isowavFile == NULL || track != isowavTrack) {
|
||||
isowavStop();
|
||||
|
||||
isowavTrack = track;
|
||||
|
||||
bprintf(PRINT_IMPORTANT, _T(" reading track %2i - %s\n"), isowavTrack + 1, isowavTOC->TrackData[isowavTrack].Filename);
|
||||
|
||||
isowavFile = _tfopen(isowavTOC->TrackData[isowavTrack].Filename, _T("rb"));
|
||||
if (isowavFile == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (fseek(isowavFile, (LBA - isowavMSFToLBA(isowavTOC->TrackData[isowavTrack].Address)) * 2048, SEEK_SET)) {
|
||||
dprintf(_T("*** couldn't seek\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
isowavLBA = (ftell(isowavFile) + 2047) / 2048;
|
||||
|
||||
CDEmuStatus = reading;
|
||||
}
|
||||
|
||||
if (fread(pBuffer, 1, 2048, isowavFile) <= 0) {
|
||||
dprintf(_T("*** couldn't read from file\n"));
|
||||
|
||||
isowavStop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
isowavLBA = isowavMSFToLBA(isowavTOC->TrackData[isowavTrack].Address) + (ftell(isowavFile) + 2047) / 2048;
|
||||
|
||||
return isowavLBA - CD_FRAMES_PREGAP;
|
||||
}
|
||||
|
||||
static unsigned char* isowavReadTOC(int track)
|
||||
{
|
||||
static unsigned char TOCEntry[4];
|
||||
|
||||
if (track == -1) {
|
||||
TOCEntry[0] = isowavTOC->FirstTrack - 1;
|
||||
TOCEntry[1] = isowavTOC->LastTrack;
|
||||
TOCEntry[2] = 0;
|
||||
TOCEntry[3] = 0;
|
||||
|
||||
return TOCEntry;
|
||||
}
|
||||
if (track == -2) {
|
||||
TOCEntry[0] = isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[1];
|
||||
TOCEntry[1] = isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[2];
|
||||
TOCEntry[2] = isowavTOC->TrackData[(int)isowavTOC->LastTrack].Address[3];
|
||||
|
||||
TOCEntry[3] = 0;
|
||||
|
||||
return TOCEntry;
|
||||
}
|
||||
|
||||
if (track >= isowavTOC->FirstTrack - 1 && track <= isowavTOC->LastTrack) {
|
||||
TOCEntry[0] = isowavTOC->TrackData[track - 1].Address[1];
|
||||
TOCEntry[1] = isowavTOC->TrackData[track - 1].Address[2];
|
||||
TOCEntry[2] = isowavTOC->TrackData[track - 1].Address[3];
|
||||
TOCEntry[3] = isowavTOC->TrackData[track - 1].Control;
|
||||
}
|
||||
|
||||
return TOCEntry;
|
||||
}
|
||||
|
||||
static unsigned char* isowavReadQChannel()
|
||||
{
|
||||
static unsigned char QChannelData[8];
|
||||
|
||||
switch (CDEmuStatus) {
|
||||
case reading:
|
||||
case playing: {
|
||||
const char* AddressAbs = isowavLBAToMSF(isowavLBA);
|
||||
const char* AddressRel = isowavLBAToMSF(isowavLBA - isowavMSFToLBA(isowavTOC->TrackData[isowavTrack].Address));
|
||||
|
||||
QChannelData[0] = isowavTOC->TrackData[isowavTrack].TrackNumber;
|
||||
|
||||
QChannelData[1] = AddressAbs[1];
|
||||
QChannelData[2] = AddressAbs[2];
|
||||
QChannelData[3] = AddressAbs[3];
|
||||
|
||||
QChannelData[4] = AddressRel[1];
|
||||
QChannelData[5] = AddressRel[2];
|
||||
QChannelData[6] = AddressRel[3];
|
||||
|
||||
QChannelData[7] = isowavTOC->TrackData[isowavTrack].Control;
|
||||
|
||||
break;
|
||||
}
|
||||
case paused: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
memset(QChannelData, 0, sizeof(QChannelData));
|
||||
}
|
||||
}
|
||||
|
||||
return QChannelData;
|
||||
}
|
||||
|
||||
static int isowavGetSoundBuffer(short* /*buffer*/, int /*samples*/)
|
||||
{
|
||||
// ---------------------------------------------------------------------
|
||||
// TODO:
|
||||
// Port the old 'isomp3GetSoundBuffer()' function from 'cd_isomp3.cpp'
|
||||
// to use WAVE stream data, porting that function will fix the
|
||||
// 00:00 progress status on the main NeoGeo CD BIOS menu.
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* see src/intf/cd/cd_interface.cpp
|
||||
*/
|
||||
bool bCDEmuOkay = false;
|
||||
|
||||
INT32 CDEmuInit() {
|
||||
INT32 nRet;
|
||||
CDEmuStatus = idle;
|
||||
if ((nRet = isowavInit()) == 0) {
|
||||
bCDEmuOkay = true;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
INT32 CDEmuExit() {
|
||||
if (!bCDEmuOkay) {
|
||||
return 1;
|
||||
}
|
||||
bCDEmuOkay = false;
|
||||
return isowavExit();
|
||||
}
|
||||
INT32 CDEmuStop() {
|
||||
if (!bCDEmuOkay) {
|
||||
return 1;
|
||||
}
|
||||
return isowavStop();
|
||||
}
|
||||
INT32 CDEmuPlay(UINT8 M, UINT8 S, UINT8 F) {
|
||||
if (!bCDEmuOkay) {
|
||||
return 1;
|
||||
}
|
||||
return isowavPlay(M, S, F);
|
||||
}
|
||||
INT32 CDEmuLoadSector(INT32 LBA, char* pBuffer) {
|
||||
if (!bCDEmuOkay) {
|
||||
return 0;
|
||||
}
|
||||
return isowavLoadSector(LBA, pBuffer);
|
||||
}
|
||||
UINT8* CDEmuReadTOC(INT32 track) {
|
||||
if (!bCDEmuOkay) {
|
||||
return NULL;
|
||||
}
|
||||
return isowavReadTOC(track);
|
||||
}
|
||||
UINT8* CDEmuReadQChannel() {
|
||||
if (!bCDEmuOkay) {
|
||||
return NULL;
|
||||
}
|
||||
return isowavReadQChannel();
|
||||
}
|
||||
INT32 CDEmuGetSoundBuffer(INT16* buffer, INT32 samples) {
|
||||
if (!bCDEmuOkay) {
|
||||
return 1;
|
||||
}
|
||||
return isowavGetSoundBuffer(buffer, samples);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef __RETRO_CD_EMU__
|
||||
#define __RETRO_CD_EMU__
|
||||
|
||||
TCHAR* GetIsoPath();
|
||||
INT32 CDEmuInit();
|
||||
INT32 CDEmuExit();
|
||||
INT32 CDEmuStop();
|
||||
INT32 CDEmuPlay(UINT8 M, UINT8 S, UINT8 F);
|
||||
INT32 CDEmuLoadSector(INT32 LBA, char* pBuffer);
|
||||
UINT8* CDEmuReadTOC(INT32 track);
|
||||
UINT8* CDEmuReadQChannel();
|
||||
INT32 CDEmuGetSoundBuffer(INT16* buffer, INT32 samples);
|
||||
void wav_exit();
|
||||
|
||||
extern CDEmuStatusValue CDEmuStatus;
|
||||
extern TCHAR CDEmuImage[MAX_PATH];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (audio_mix.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <audio/audio_mix.h>
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
#elif defined(__ALTIVEC__)
|
||||
#include <altivec.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <memalign.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <audio/audio_mix.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <audio/conversion/float_to_s16.h>
|
||||
#include <audio/conversion/s16_to_float.h>
|
||||
|
||||
void audio_mix_volume_C(float *out, const float *in, float vol, size_t samples)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i] += in[i] * vol;
|
||||
}
|
||||
|
||||
#ifdef __SSE2__
|
||||
void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t samples)
|
||||
{
|
||||
size_t i;
|
||||
__m128 volume = _mm_set1_ps(vol);
|
||||
|
||||
for (i = 0; i + 16 <= samples; i += 16, out += 16, in += 16)
|
||||
{
|
||||
unsigned j;
|
||||
__m128 input[4];
|
||||
__m128 additive[4];
|
||||
|
||||
input[0] = _mm_loadu_ps(out + 0);
|
||||
input[1] = _mm_loadu_ps(out + 4);
|
||||
input[2] = _mm_loadu_ps(out + 8);
|
||||
input[3] = _mm_loadu_ps(out + 12);
|
||||
|
||||
additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in + 0));
|
||||
additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in + 4));
|
||||
additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in + 8));
|
||||
additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12));
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
_mm_storeu_ps(out + 4 * j, _mm_add_ps(input[j], additive[j]));
|
||||
}
|
||||
|
||||
audio_mix_volume_C(out, in, vol, samples - i);
|
||||
}
|
||||
#endif
|
||||
|
||||
void audio_mix_free_chunk(audio_chunk_t *chunk)
|
||||
{
|
||||
if (!chunk)
|
||||
return;
|
||||
|
||||
if (chunk->rwav && chunk->rwav->samples)
|
||||
{
|
||||
/* rwav_free only frees the samples */
|
||||
rwav_free(chunk->rwav);
|
||||
free(chunk->rwav);
|
||||
}
|
||||
|
||||
if (chunk->buf)
|
||||
free(chunk->buf);
|
||||
|
||||
if (chunk->upsample_buf)
|
||||
memalign_free(chunk->upsample_buf);
|
||||
|
||||
if (chunk->float_buf)
|
||||
memalign_free(chunk->float_buf);
|
||||
|
||||
if (chunk->float_resample_buf)
|
||||
memalign_free(chunk->float_resample_buf);
|
||||
|
||||
if (chunk->resample_buf)
|
||||
memalign_free(chunk->resample_buf);
|
||||
|
||||
if (chunk->resampler && chunk->resampler_data)
|
||||
chunk->resampler->free(chunk->resampler_data);
|
||||
|
||||
free(chunk);
|
||||
}
|
||||
|
||||
audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
|
||||
{
|
||||
int sample_size;
|
||||
int64_t len = 0;
|
||||
void *buf = NULL;
|
||||
audio_chunk_t *chunk = (audio_chunk_t*)calloc(1, sizeof(*chunk));
|
||||
|
||||
if (!chunk)
|
||||
return NULL;
|
||||
|
||||
if (!filestream_read_file(path, &buf, &len))
|
||||
{
|
||||
printf("Could not open WAV file for reading.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
chunk->sample_rate = sample_rate;
|
||||
chunk->buf = buf;
|
||||
chunk->len = len;
|
||||
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
|
||||
|
||||
if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
|
||||
{
|
||||
printf("error: could not load WAV file\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* numsamples does not know or care about
|
||||
* multiple channels, but we need space for 2 */
|
||||
chunk->upsample_buf = (int16_t*)memalign_alloc(128,
|
||||
chunk->rwav->numsamples * 2 * sizeof(int16_t));
|
||||
|
||||
sample_size = chunk->rwav->bitspersample / 8;
|
||||
|
||||
if (sample_size == 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chunk->rwav->numsamples; i++)
|
||||
{
|
||||
uint8_t *sample = (
|
||||
(uint8_t*)chunk->rwav->samples) +
|
||||
(i * chunk->rwav->numchannels);
|
||||
|
||||
chunk->upsample_buf[i * 2] = (int16_t)((sample[0] - 128) << 8);
|
||||
|
||||
if (chunk->rwav->numchannels == 1)
|
||||
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[0] - 128) << 8);
|
||||
else if (chunk->rwav->numchannels == 2)
|
||||
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[1] - 128) << 8);
|
||||
}
|
||||
}
|
||||
else if (sample_size == 2)
|
||||
{
|
||||
if (chunk->rwav->numchannels == 1)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chunk->rwav->numsamples; i++)
|
||||
{
|
||||
int16_t sample = ((int16_t*)chunk->rwav->samples)[i];
|
||||
|
||||
chunk->upsample_buf[i * 2] = sample;
|
||||
chunk->upsample_buf[(i * 2) + 1] = sample;
|
||||
}
|
||||
}
|
||||
else if (chunk->rwav->numchannels == 2)
|
||||
memcpy(chunk->upsample_buf, chunk->rwav->samples, chunk->rwav->subchunk2size);
|
||||
}
|
||||
else if (sample_size != 2)
|
||||
{
|
||||
/* we don't support any other sample size besides 8 and 16-bit yet */
|
||||
printf("error: we don't support a sample size of %d\n", sample_size);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (sample_rate != (int)chunk->rwav->samplerate)
|
||||
{
|
||||
chunk->resample = true;
|
||||
chunk->ratio = (double)sample_rate / chunk->rwav->samplerate;
|
||||
|
||||
retro_resampler_realloc(&chunk->resampler_data,
|
||||
&chunk->resampler,
|
||||
NULL,
|
||||
RESAMPLER_QUALITY_DONTCARE,
|
||||
chunk->ratio);
|
||||
|
||||
if (chunk->resampler && chunk->resampler_data)
|
||||
{
|
||||
struct resampler_data info;
|
||||
|
||||
chunk->float_buf = (float*)memalign_alloc(128, chunk->rwav->numsamples * 2 * chunk->ratio * sizeof(float));
|
||||
|
||||
/* why is *3 needed instead of just *2? does the sinc driver require more space than we know about? */
|
||||
chunk->float_resample_buf = (float*)memalign_alloc(128, chunk->rwav->numsamples * 3 * chunk->ratio * sizeof(float));
|
||||
|
||||
convert_s16_to_float(chunk->float_buf, chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);
|
||||
|
||||
info.data_in = (const float*)chunk->float_buf;
|
||||
info.data_out = chunk->float_resample_buf;
|
||||
/* a 'frame' consists of two channels, so we set this
|
||||
* to the number of samples irrespective of channel count */
|
||||
info.input_frames = chunk->rwav->numsamples;
|
||||
info.output_frames = 0;
|
||||
info.ratio = chunk->ratio;
|
||||
|
||||
chunk->resampler->process(chunk->resampler_data, &info);
|
||||
|
||||
/* number of output_frames does not increase with multiple channels, but assume we need space for 2 */
|
||||
chunk->resample_buf = (int16_t*)memalign_alloc(128, info.output_frames * 2 * sizeof(int16_t));
|
||||
chunk->resample_len = info.output_frames;
|
||||
convert_float_to_s16(chunk->resample_buf, chunk->float_resample_buf, info.output_frames * 2);
|
||||
}
|
||||
}
|
||||
|
||||
return chunk;
|
||||
|
||||
error:
|
||||
audio_mix_free_chunk(chunk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
|
||||
{
|
||||
if (!chunk)
|
||||
return 0;
|
||||
|
||||
if (chunk->rwav)
|
||||
{
|
||||
if (chunk->resample)
|
||||
return chunk->resample_len;
|
||||
return chunk->rwav->numsamples;
|
||||
}
|
||||
|
||||
/* no other filetypes supported yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* audio_mix_get_chunk_sample:
|
||||
* @chunk : audio chunk instance
|
||||
* @channel : channel of the sample (0=left, 1=right)
|
||||
* @index : index of the sample
|
||||
*
|
||||
* Get a sample from an audio chunk.
|
||||
*
|
||||
* Returns: A signed 16-bit audio sample.
|
||||
**/
|
||||
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t index)
|
||||
{
|
||||
if (!chunk)
|
||||
return 0;
|
||||
|
||||
if (chunk->rwav)
|
||||
{
|
||||
int sample_size = chunk->rwav->bitspersample / 8;
|
||||
int16_t sample_out = 0;
|
||||
|
||||
/* 0 is the first/left channel */
|
||||
uint8_t *sample = NULL;
|
||||
|
||||
if (chunk->resample)
|
||||
sample = (uint8_t*)chunk->resample_buf +
|
||||
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
|
||||
else
|
||||
sample = (uint8_t*)chunk->upsample_buf +
|
||||
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
|
||||
|
||||
sample_out = (int16_t)*sample;
|
||||
|
||||
return sample_out;
|
||||
}
|
||||
|
||||
/* no other filetypes supported yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
|
||||
{
|
||||
if (!chunk)
|
||||
return 0;
|
||||
|
||||
if (chunk->rwav)
|
||||
{
|
||||
int16_t *sample;
|
||||
|
||||
if (chunk->resample)
|
||||
sample = chunk->resample_buf;
|
||||
else
|
||||
sample = chunk->upsample_buf;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
|
||||
{
|
||||
if (!chunk)
|
||||
return 0;
|
||||
|
||||
if (chunk->rwav)
|
||||
return chunk->rwav->numchannels;
|
||||
|
||||
/* don't support other formats yet */
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,160 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (float_to_s16.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
#elif defined(__ALTIVEC__)
|
||||
#include <altivec.h>
|
||||
#endif
|
||||
|
||||
#include <features/features_cpu.h>
|
||||
#include <audio/conversion/float_to_s16.h>
|
||||
|
||||
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
static bool float_to_s16_neon_enabled = false;
|
||||
void convert_float_s16_asm(int16_t *out, const float *in, size_t samples);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* convert_float_to_s16:
|
||||
* @out : output buffer
|
||||
* @in : input buffer
|
||||
* @samples : size of samples to be converted
|
||||
*
|
||||
* Converts floating point
|
||||
* to signed integer 16-bit.
|
||||
*
|
||||
* C implementation callback function.
|
||||
**/
|
||||
void convert_float_to_s16(int16_t *out,
|
||||
const float *in, size_t samples)
|
||||
{
|
||||
size_t i = 0;
|
||||
#if defined(__SSE2__)
|
||||
__m128 factor = _mm_set1_ps((float)0x8000);
|
||||
|
||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||
{
|
||||
__m128 input_l = _mm_loadu_ps(in + 0);
|
||||
__m128 input_r = _mm_loadu_ps(in + 4);
|
||||
__m128 res_l = _mm_mul_ps(input_l, factor);
|
||||
__m128 res_r = _mm_mul_ps(input_r, factor);
|
||||
__m128i ints_l = _mm_cvtps_epi32(res_l);
|
||||
__m128i ints_r = _mm_cvtps_epi32(res_r);
|
||||
__m128i packed = _mm_packs_epi32(ints_l, ints_r);
|
||||
|
||||
_mm_storeu_si128((__m128i *)out, packed);
|
||||
}
|
||||
|
||||
samples = samples - i;
|
||||
i = 0;
|
||||
#elif defined(__ALTIVEC__)
|
||||
int samples_in = samples;
|
||||
|
||||
/* Unaligned loads/store is a bit expensive,
|
||||
* so we optimize for the good path (very likely). */
|
||||
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||
{
|
||||
vector float input0 = vec_ld( 0, in);
|
||||
vector float input1 = vec_ld(16, in);
|
||||
vector signed int result0 = vec_cts(input0, 15);
|
||||
vector signed int result1 = vec_cts(input1, 15);
|
||||
vec_st(vec_packs(result0, result1), 0, out);
|
||||
}
|
||||
|
||||
samples_in -= i;
|
||||
}
|
||||
|
||||
samples = samples_in;
|
||||
i = 0;
|
||||
#elif defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
if (float_to_s16_neon_enabled)
|
||||
{
|
||||
size_t aligned_samples = samples & ~7;
|
||||
if (aligned_samples)
|
||||
convert_float_s16_asm(out, in, aligned_samples);
|
||||
|
||||
out = out + aligned_samples;
|
||||
in = in + aligned_samples;
|
||||
samples = samples - aligned_samples;
|
||||
i = 0;
|
||||
}
|
||||
#elif defined(_MIPS_ARCH_ALLEGREX)
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Make sure the buffers are 16 byte aligned, this should be
|
||||
* the default behaviour of malloc in the PSPSDK.
|
||||
* Assume alignment. */
|
||||
retro_assert(((uintptr_t)in & 0xf) == 0);
|
||||
retro_assert(((uintptr_t)out & 0xf) == 0);
|
||||
#endif
|
||||
|
||||
for (i = 0; i + 8 <= samples; i += 8)
|
||||
{
|
||||
__asm__ (
|
||||
".set push \n"
|
||||
".set noreorder \n"
|
||||
|
||||
"lv.q c100, 0(%0) \n"
|
||||
"lv.q c110, 16(%0) \n"
|
||||
|
||||
"vf2in.q c100, c100, 31 \n"
|
||||
"vf2in.q c110, c110, 31 \n"
|
||||
"vi2s.q c100, c100 \n"
|
||||
"vi2s.q c102, c110 \n"
|
||||
|
||||
"sv.q c100, 0(%1) \n"
|
||||
|
||||
".set pop \n"
|
||||
:: "r"(in + i), "r"(out + i));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
for (; i < samples; i++)
|
||||
{
|
||||
int32_t val = (int32_t)(in[i] * 0x8000);
|
||||
out[i] = (val > 0x7FFF) ? 0x7FFF :
|
||||
(val < -0x8000 ? -0x8000 : (int16_t)val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_float_to_s16_init_simd:
|
||||
*
|
||||
* Sets up function pointers for conversion
|
||||
* functions based on CPU features.
|
||||
**/
|
||||
void convert_float_to_s16_init_simd(void)
|
||||
{
|
||||
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
unsigned cpu = cpu_features_get();
|
||||
|
||||
if (cpu & RETRO_SIMD_NEON)
|
||||
float_to_s16_neon_enabled = true;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (float_to_s16_neon.S).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
#ifndef __MACH__
|
||||
.arm
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
.globl convert_float_s16_asm
|
||||
#ifndef __MACH__
|
||||
.type convert_float_s16_asm, %function
|
||||
#endif
|
||||
.globl _convert_float_s16_asm
|
||||
#ifndef __MACH__
|
||||
.type _convert_float_s16_asm, %function
|
||||
#endif
|
||||
# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)
|
||||
convert_float_s16_asm:
|
||||
_convert_float_s16_asm:
|
||||
# Hacky way to get a constant of 2^15.
|
||||
# ((2^4)^2)^2 * 0.5 = 2^15
|
||||
vmov.f32 q8, #16.0
|
||||
vmov.f32 q9, #0.5
|
||||
vmul.f32 q8, q8, q8
|
||||
vmul.f32 q8, q8, q8
|
||||
vmul.f32 q8, q8, q9
|
||||
|
||||
1:
|
||||
# Preload here?
|
||||
vld1.f32 {q0-q1}, [r1]!
|
||||
|
||||
vmul.f32 q0, q0, q8
|
||||
vmul.f32 q1, q1, q8
|
||||
|
||||
vcvt.s32.f32 q0, q0
|
||||
vcvt.s32.f32 q1, q1
|
||||
|
||||
vqmovn.s32 d4, q0
|
||||
vqmovn.s32 d5, q1
|
||||
|
||||
vst1.f32 {d4-d5}, [r0]!
|
||||
|
||||
# Guaranteed to get samples in multiples of 8.
|
||||
subs r2, r2, #8
|
||||
bne 1b
|
||||
|
||||
bx lr
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (float_to_s16_neon.S).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
#if defined(__thumb__)
|
||||
#define DECL_ARMMODE(x) " .align 2\n" " .global " x "\n" " .thumb\n" " .thumb_func\n" " .type " x ", %function\n" x ":\n"
|
||||
#else
|
||||
#define DECL_ARMMODE(x) " .align 4\n" " .global " x "\n" " .arm\n" x ":\n"
|
||||
#endif
|
||||
|
||||
asm(
|
||||
DECL_ARMMODE("convert_float_s16_asm")
|
||||
DECL_ARMMODE("_convert_float_s16_asm")
|
||||
"# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)\n"
|
||||
" # Hacky way to get a constant of 2^15.\n"
|
||||
" # ((2^4)^2)^2 * 0.5 = 2^15\n"
|
||||
" vmov.f32 q8, #16.0\n"
|
||||
" vmov.f32 q9, #0.5\n"
|
||||
" vmul.f32 q8, q8, q8\n"
|
||||
" vmul.f32 q8, q8, q8\n"
|
||||
" vmul.f32 q8, q8, q9\n"
|
||||
"\n"
|
||||
"1:\n"
|
||||
" # Preload here?\n"
|
||||
" vld1.f32 {q0-q1}, [r1]!\n"
|
||||
"\n"
|
||||
" vmul.f32 q0, q0, q8\n"
|
||||
" vmul.f32 q1, q1, q8\n"
|
||||
"\n"
|
||||
" vcvt.s32.f32 q0, q0\n"
|
||||
" vcvt.s32.f32 q1, q1\n"
|
||||
"\n"
|
||||
" vqmovn.s32 d4, q0\n"
|
||||
" vqmovn.s32 d5, q1\n"
|
||||
"\n"
|
||||
" vst1.f32 {d4-d5}, [r0]!\n"
|
||||
"\n"
|
||||
" # Guaranteed to get samples in multiples of 8.\n"
|
||||
" subs r2, r2, #8\n"
|
||||
" bne 1b\n"
|
||||
"\n"
|
||||
" bx lr\n"
|
||||
"\n"
|
||||
);
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (s16_to_float.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#if defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
#elif defined(__ALTIVEC__)
|
||||
#include <altivec.h>
|
||||
#endif
|
||||
|
||||
#include <boolean.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <audio/conversion/s16_to_float.h>
|
||||
|
||||
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
static bool s16_to_float_neon_enabled = false;
|
||||
|
||||
/* Avoid potential hard-float/soft-float ABI issues. */
|
||||
void convert_s16_float_asm(float *out, const int16_t *in,
|
||||
size_t samples, const float *gain);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* convert_s16_to_float:
|
||||
* @out : output buffer
|
||||
* @in : input buffer
|
||||
* @samples : size of samples to be converted
|
||||
* @gain : gain applied (.e.g. audio volume)
|
||||
*
|
||||
* Converts from signed integer 16-bit
|
||||
* to floating point.
|
||||
**/
|
||||
void convert_s16_to_float(float *out,
|
||||
const int16_t *in, size_t samples, float gain)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
#if defined(__SSE2__)
|
||||
float fgain = gain / UINT32_C(0x80000000);
|
||||
__m128 factor = _mm_set1_ps(fgain);
|
||||
|
||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||
{
|
||||
__m128i input = _mm_loadu_si128((const __m128i *)in);
|
||||
__m128i regs_l = _mm_unpacklo_epi16(_mm_setzero_si128(), input);
|
||||
__m128i regs_r = _mm_unpackhi_epi16(_mm_setzero_si128(), input);
|
||||
__m128 output_l = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);
|
||||
__m128 output_r = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);
|
||||
|
||||
_mm_storeu_ps(out + 0, output_l);
|
||||
_mm_storeu_ps(out + 4, output_r);
|
||||
}
|
||||
|
||||
samples = samples - i;
|
||||
i = 0;
|
||||
#elif defined(__ALTIVEC__)
|
||||
size_t samples_in = samples;
|
||||
|
||||
/* Unaligned loads/store is a bit expensive, so we
|
||||
* optimize for the good path (very likely). */
|
||||
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
|
||||
{
|
||||
size_t i;
|
||||
const vector float gain_vec = { gain, gain , gain, gain };
|
||||
const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||
{
|
||||
vector signed short input = vec_ld(0, in);
|
||||
vector signed int hi = vec_unpackh(input);
|
||||
vector signed int lo = vec_unpackl(input);
|
||||
vector float out_hi = vec_madd(vec_ctf(hi, 15), gain_vec, zero_vec);
|
||||
vector float out_lo = vec_madd(vec_ctf(lo, 15), gain_vec, zero_vec);
|
||||
|
||||
vec_st(out_hi, 0, out);
|
||||
vec_st(out_lo, 16, out);
|
||||
}
|
||||
|
||||
samples_in -= i;
|
||||
}
|
||||
|
||||
samples = samples_in;
|
||||
i = 0;
|
||||
|
||||
#elif defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
if (s16_to_float_neon_enabled)
|
||||
{
|
||||
size_t aligned_samples = samples & ~7;
|
||||
if (aligned_samples)
|
||||
convert_s16_float_asm(out, in, aligned_samples, &gain);
|
||||
|
||||
/* Could do all conversion in ASM, but keep it simple for now. */
|
||||
out = out + aligned_samples;
|
||||
in = in + aligned_samples;
|
||||
samples = samples - aligned_samples;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
#elif defined(_MIPS_ARCH_ALLEGREX)
|
||||
#ifdef DEBUG
|
||||
/* Make sure the buffer is 16 byte aligned, this should be the
|
||||
* default behaviour of malloc in the PSPSDK.
|
||||
* Only the output buffer can be assumed to be 16-byte aligned. */
|
||||
retro_assert(((uintptr_t)out & 0xf) == 0);
|
||||
#endif
|
||||
|
||||
gain = gain / 0x8000;
|
||||
__asm__ (
|
||||
".set push \n"
|
||||
".set noreorder \n"
|
||||
"mtv %0, s200 \n"
|
||||
".set pop \n"
|
||||
::"r"(gain));
|
||||
|
||||
for (i = 0; i + 16 <= samples; i += 16)
|
||||
{
|
||||
__asm__ (
|
||||
".set push \n"
|
||||
".set noreorder \n"
|
||||
|
||||
"lv.s s100, 0(%0) \n"
|
||||
"lv.s s101, 4(%0) \n"
|
||||
"lv.s s110, 8(%0) \n"
|
||||
"lv.s s111, 12(%0) \n"
|
||||
"lv.s s120, 16(%0) \n"
|
||||
"lv.s s121, 20(%0) \n"
|
||||
"lv.s s130, 24(%0) \n"
|
||||
"lv.s s131, 28(%0) \n"
|
||||
|
||||
"vs2i.p c100, c100 \n"
|
||||
"vs2i.p c110, c110 \n"
|
||||
"vs2i.p c120, c120 \n"
|
||||
"vs2i.p c130, c130 \n"
|
||||
|
||||
"vi2f.q c100, c100, 16 \n"
|
||||
"vi2f.q c110, c110, 16 \n"
|
||||
"vi2f.q c120, c120, 16 \n"
|
||||
"vi2f.q c130, c130, 16 \n"
|
||||
|
||||
"vmscl.q e100, e100, s200 \n"
|
||||
|
||||
"sv.q c100, 0(%1) \n"
|
||||
"sv.q c110, 16(%1) \n"
|
||||
"sv.q c120, 32(%1) \n"
|
||||
"sv.q c130, 48(%1) \n"
|
||||
|
||||
".set pop \n"
|
||||
:: "r"(in + i), "r"(out + i));
|
||||
}
|
||||
|
||||
#endif
|
||||
gain = gain / 0x8000;
|
||||
|
||||
for (; i < samples; i++)
|
||||
out[i] = (float)in[i] * gain;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_s16_to_float_init_simd:
|
||||
*
|
||||
* Sets up function pointers for conversion
|
||||
* functions based on CPU features.
|
||||
**/
|
||||
void convert_s16_to_float_init_simd(void)
|
||||
{
|
||||
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
unsigned cpu = cpu_features_get();
|
||||
|
||||
if (cpu & RETRO_SIMD_NEON)
|
||||
s16_to_float_neon_enabled = true;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (s16_to_float_neon.S).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
#ifndef __MACH__
|
||||
.arm
|
||||
#endif
|
||||
|
||||
.align 4
|
||||
.globl convert_s16_float_asm
|
||||
#ifndef __MACH__
|
||||
.type convert_s16_float_asm, %function
|
||||
#endif
|
||||
.globl _convert_s16_float_asm
|
||||
#ifndef __MACH__
|
||||
.type _convert_s16_float_asm, %function
|
||||
#endif
|
||||
# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)
|
||||
convert_s16_float_asm:
|
||||
_convert_s16_float_asm:
|
||||
# Hacky way to get a constant of 2^-15.
|
||||
# Might be faster to just load a constant from memory.
|
||||
# It's just done once however ...
|
||||
vmov.f32 q8, #0.25
|
||||
vmul.f32 q8, q8, q8
|
||||
vmul.f32 q8, q8, q8
|
||||
vmul.f32 q8, q8, q8
|
||||
vadd.f32 q8, q8, q8
|
||||
|
||||
# Apply gain
|
||||
vld1.f32 {d6[0]}, [r3]
|
||||
vmul.f32 q8, q8, d6[0]
|
||||
|
||||
1:
|
||||
# Preload here?
|
||||
vld1.s16 {q0}, [r1]!
|
||||
|
||||
# Widen to 32-bit
|
||||
vmovl.s16 q1, d0
|
||||
vmovl.s16 q2, d1
|
||||
|
||||
# Convert to float
|
||||
vcvt.f32.s32 q1, q1
|
||||
vcvt.f32.s32 q2, q2
|
||||
|
||||
vmul.f32 q1, q1, q8
|
||||
vmul.f32 q2, q2, q8
|
||||
|
||||
vst1.f32 {q1-q2}, [r0]!
|
||||
|
||||
# Guaranteed to get samples in multiples of 8.
|
||||
subs r2, r2, #8
|
||||
bne 1b
|
||||
|
||||
bx lr
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (s16_to_float_neon.S).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
#if defined(__thumb__)
|
||||
#define DECL_ARMMODE(x) " .align 2\n" " .global " x "\n" " .thumb\n" " .thumb_func\n" " .type " x ", %function\n" x ":\n"
|
||||
#else
|
||||
#define DECL_ARMMODE(x) " .align 4\n" " .global " x "\n" " .arm\n" x ":\n"
|
||||
#endif
|
||||
|
||||
asm(
|
||||
DECL_ARMMODE("convert_s16_float_asm")
|
||||
DECL_ARMMODE("_convert_s16_float_asm")
|
||||
"# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)\n"
|
||||
" # Hacky way to get a constant of 2^-15.\n"
|
||||
" # Might be faster to just load a constant from memory.\n"
|
||||
" # It's just done once however ...\n"
|
||||
" vmov.f32 q8, #0.25\n"
|
||||
" vmul.f32 q8, q8, q8\n"
|
||||
" vmul.f32 q8, q8, q8\n"
|
||||
" vmul.f32 q8, q8, q8\n"
|
||||
" vadd.f32 q8, q8, q8\n"
|
||||
"\n"
|
||||
" # Apply gain\n"
|
||||
" vld1.f32 {d6[0]}, [r3]\n"
|
||||
" vmul.f32 q8, q8, d6[0]\n"
|
||||
"\n"
|
||||
"1:\n"
|
||||
" # Preload here?\n"
|
||||
" vld1.s16 {q0}, [r1]!\n"
|
||||
"\n"
|
||||
" # Widen to 32-bit\n"
|
||||
" vmovl.s16 q1, d0\n"
|
||||
" vmovl.s16 q2, d1\n"
|
||||
"\n"
|
||||
" # Convert to float\n"
|
||||
" vcvt.f32.s32 q1, q1\n"
|
||||
" vcvt.f32.s32 q2, q2\n"
|
||||
"\n"
|
||||
" vmul.f32 q1, q1, q8\n"
|
||||
" vmul.f32 q2, q2, q8\n"
|
||||
"\n"
|
||||
" vst1.f32 {q1-q2}, [r0]!\n"
|
||||
"\n"
|
||||
" # Guaranteed to get samples in multiples of 8.\n"
|
||||
" subs r2, r2, #8\n"
|
||||
" bne 1b\n"
|
||||
"\n"
|
||||
" bx lr\n"
|
||||
"\n"
|
||||
);
|
||||
#endif
|
||||
@@ -0,0 +1,325 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (dsp_filter.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <compat/posix_string.h>
|
||||
#include <dynamic/dylib.h>
|
||||
|
||||
#include <file/file_path.h>
|
||||
#include <file/config_file_userdata.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
#include <audio/dsp_filter.h>
|
||||
|
||||
struct retro_dsp_plug
|
||||
{
|
||||
#ifdef HAVE_DYLIB
|
||||
dylib_t lib;
|
||||
#endif
|
||||
const struct dspfilter_implementation *impl;
|
||||
};
|
||||
|
||||
struct retro_dsp_instance
|
||||
{
|
||||
const struct dspfilter_implementation *impl;
|
||||
void *impl_data;
|
||||
};
|
||||
|
||||
struct retro_dsp_filter
|
||||
{
|
||||
config_file_t *conf;
|
||||
|
||||
struct retro_dsp_plug *plugs;
|
||||
unsigned num_plugs;
|
||||
|
||||
struct retro_dsp_instance *instances;
|
||||
unsigned num_instances;
|
||||
};
|
||||
|
||||
static const struct dspfilter_implementation *find_implementation(
|
||||
retro_dsp_filter_t *dsp, const char *ident)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < dsp->num_plugs; i++)
|
||||
{
|
||||
if (string_is_equal(dsp->plugs[i].impl->short_ident, ident))
|
||||
return dsp->plugs[i].impl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct dspfilter_config dspfilter_config = {
|
||||
config_userdata_get_float,
|
||||
config_userdata_get_int,
|
||||
config_userdata_get_float_array,
|
||||
config_userdata_get_int_array,
|
||||
config_userdata_get_string,
|
||||
config_userdata_free,
|
||||
};
|
||||
|
||||
static bool create_filter_graph(retro_dsp_filter_t *dsp, float sample_rate)
|
||||
{
|
||||
unsigned i;
|
||||
struct retro_dsp_instance *instances = NULL;
|
||||
unsigned filters = 0;
|
||||
|
||||
if (!config_get_uint(dsp->conf, "filters", &filters))
|
||||
return false;
|
||||
|
||||
instances = (struct retro_dsp_instance*)calloc(filters, sizeof(*instances));
|
||||
if (!instances)
|
||||
return false;
|
||||
|
||||
dsp->instances = instances;
|
||||
dsp->num_instances = filters;
|
||||
|
||||
for (i = 0; i < filters; i++)
|
||||
{
|
||||
struct config_file_userdata userdata;
|
||||
struct dspfilter_info info;
|
||||
char key[64];
|
||||
char name[64];
|
||||
|
||||
key[0] = name[0] = '\0';
|
||||
|
||||
info.input_rate = sample_rate;
|
||||
|
||||
snprintf(key, sizeof(key), "filter%u", i);
|
||||
|
||||
if (!config_get_array(dsp->conf, key, name, sizeof(name)))
|
||||
return false;
|
||||
|
||||
dsp->instances[i].impl = find_implementation(dsp, name);
|
||||
if (!dsp->instances[i].impl)
|
||||
return false;
|
||||
|
||||
userdata.conf = dsp->conf;
|
||||
/* Index-specific configs take priority over ident-specific. */
|
||||
userdata.prefix[0] = key;
|
||||
userdata.prefix[1] = dsp->instances[i].impl->short_ident;
|
||||
|
||||
dsp->instances[i].impl_data = dsp->instances[i].impl->init(&info,
|
||||
&dspfilter_config, &userdata);
|
||||
if (!dsp->instances[i].impl_data)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_FILTERS_BUILTIN)
|
||||
extern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *wahwah_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *eq_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
extern const struct dspfilter_implementation *chorus_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
|
||||
|
||||
static const dspfilter_get_implementation_t dsp_plugs_builtin[] = {
|
||||
panning_dspfilter_get_implementation,
|
||||
iir_dspfilter_get_implementation,
|
||||
echo_dspfilter_get_implementation,
|
||||
phaser_dspfilter_get_implementation,
|
||||
wahwah_dspfilter_get_implementation,
|
||||
eq_dspfilter_get_implementation,
|
||||
chorus_dspfilter_get_implementation,
|
||||
};
|
||||
|
||||
static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
|
||||
{
|
||||
unsigned i;
|
||||
dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();
|
||||
struct retro_dsp_plug *plugs = (struct retro_dsp_plug*)
|
||||
calloc(ARRAY_SIZE(dsp_plugs_builtin), sizeof(*plugs));
|
||||
|
||||
if (!plugs)
|
||||
return false;
|
||||
|
||||
dsp->plugs = plugs;
|
||||
dsp->num_plugs = ARRAY_SIZE(dsp_plugs_builtin);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dsp_plugs_builtin); i++)
|
||||
{
|
||||
dsp->plugs[i].impl = dsp_plugs_builtin[i](mask);
|
||||
if (!dsp->plugs[i].impl)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#elif defined(HAVE_DYLIB)
|
||||
static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
|
||||
{
|
||||
unsigned i;
|
||||
dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();
|
||||
unsigned list_size = list ? (unsigned)list->size : 0;
|
||||
|
||||
for (i = 0; i < list_size; i++)
|
||||
{
|
||||
dspfilter_get_implementation_t cb;
|
||||
const struct dspfilter_implementation *impl = NULL;
|
||||
struct retro_dsp_plug *new_plugs = NULL;
|
||||
dylib_t lib =
|
||||
dylib_load(list->elems[i].data);
|
||||
|
||||
if (!lib)
|
||||
continue;
|
||||
|
||||
cb = (dspfilter_get_implementation_t)dylib_proc(lib, "dspfilter_get_implementation");
|
||||
if (!cb)
|
||||
{
|
||||
dylib_close(lib);
|
||||
continue;
|
||||
}
|
||||
|
||||
impl = cb(mask);
|
||||
if (!impl)
|
||||
{
|
||||
dylib_close(lib);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (impl->api_version != DSPFILTER_API_VERSION)
|
||||
{
|
||||
dylib_close(lib);
|
||||
continue;
|
||||
}
|
||||
|
||||
new_plugs = (struct retro_dsp_plug*)
|
||||
realloc(dsp->plugs, sizeof(*dsp->plugs) * (dsp->num_plugs + 1));
|
||||
if (!new_plugs)
|
||||
{
|
||||
dylib_close(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Found plug. */
|
||||
|
||||
dsp->plugs = new_plugs;
|
||||
dsp->plugs[dsp->num_plugs].lib = lib;
|
||||
dsp->plugs[dsp->num_plugs].impl = impl;
|
||||
dsp->num_plugs++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
retro_dsp_filter_t *retro_dsp_filter_new(
|
||||
const char *filter_config,
|
||||
void *string_data,
|
||||
float sample_rate)
|
||||
{
|
||||
config_file_t *conf = NULL;
|
||||
struct string_list *plugs = NULL;
|
||||
retro_dsp_filter_t *dsp = (retro_dsp_filter_t*)calloc(1, sizeof(*dsp));
|
||||
|
||||
if (!dsp)
|
||||
return NULL;
|
||||
|
||||
conf = config_file_new(filter_config);
|
||||
if (!conf) /* Did not find config. */
|
||||
goto error;
|
||||
|
||||
dsp->conf = conf;
|
||||
|
||||
if (string_data)
|
||||
plugs = (struct string_list*)string_data;
|
||||
|
||||
#if defined(HAVE_DYLIB) || defined(HAVE_FILTERS_BUILTIN)
|
||||
if (!append_plugs(dsp, plugs))
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
if (plugs)
|
||||
string_list_free(plugs);
|
||||
plugs = NULL;
|
||||
|
||||
if (!create_filter_graph(dsp, sample_rate))
|
||||
goto error;
|
||||
|
||||
return dsp;
|
||||
|
||||
error:
|
||||
if (plugs)
|
||||
string_list_free(plugs);
|
||||
retro_dsp_filter_free(dsp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void retro_dsp_filter_free(retro_dsp_filter_t *dsp)
|
||||
{
|
||||
unsigned i;
|
||||
if (!dsp)
|
||||
return;
|
||||
|
||||
for (i = 0; i < dsp->num_instances; i++)
|
||||
{
|
||||
if (dsp->instances[i].impl_data && dsp->instances[i].impl)
|
||||
dsp->instances[i].impl->free(dsp->instances[i].impl_data);
|
||||
}
|
||||
free(dsp->instances);
|
||||
|
||||
#ifdef HAVE_DYLIB
|
||||
for (i = 0; i < dsp->num_plugs; i++)
|
||||
{
|
||||
if (dsp->plugs[i].lib)
|
||||
dylib_close(dsp->plugs[i].lib);
|
||||
}
|
||||
free(dsp->plugs);
|
||||
#endif
|
||||
|
||||
if (dsp->conf)
|
||||
config_file_free(dsp->conf);
|
||||
|
||||
free(dsp);
|
||||
}
|
||||
|
||||
void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
|
||||
struct retro_dsp_data *data)
|
||||
{
|
||||
unsigned i;
|
||||
struct dspfilter_output output = {0};
|
||||
struct dspfilter_input input = {0};
|
||||
|
||||
output.samples = data->input;
|
||||
output.frames = data->input_frames;
|
||||
|
||||
for (i = 0; i < dsp->num_instances; i++)
|
||||
{
|
||||
input.samples = output.samples;
|
||||
input.frames = output.frames;
|
||||
dsp->instances[i].impl->process(
|
||||
dsp->instances[i].impl_data, &output, &input);
|
||||
}
|
||||
|
||||
data->output = output.samples;
|
||||
data->output_frames = output.frames;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
filters = 2
|
||||
filter0 = iir
|
||||
filter1 = panning
|
||||
|
||||
iir_gain = 10.0
|
||||
iir_type = BBOOST
|
||||
iir_frequency = 200.0
|
||||
|
||||
# Avoids clipping.
|
||||
panning_left_mix = "0.3 0.0"
|
||||
panning_right_mix = "0.0 0.3"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
filters = 4
|
||||
filter0 = eq
|
||||
filter1 = reverb
|
||||
filter2 = iir
|
||||
filter3 = panning
|
||||
|
||||
eq_frequencies = "32 64 125 250 500 1000 2000 4000 8000 16000 20000"
|
||||
eq_gains = "6 9 12 7 6 5 7 9 11 6 0"
|
||||
|
||||
# Reverb - slight reverb
|
||||
reverb_drytime = 0.5
|
||||
reverb_wettime = 0.15
|
||||
reverb_damping = 0.8
|
||||
reverb_roomwidth = 0.25
|
||||
reverb_roomsize = 0.25
|
||||
|
||||
# IIR - filters out some harsh sounds on the upper end
|
||||
iir_type = RIAA_CD
|
||||
|
||||
# Panning - cut the volume a bit
|
||||
panning_left_mix = "0.75 0.0"
|
||||
panning_right_mix = "0.0 0.75"
|
||||
@@ -0,0 +1,14 @@
|
||||
filters = 1
|
||||
filter0 = chorus
|
||||
|
||||
# Controls the base delay of the chorus (milliseconds).
|
||||
# chorus_delay_ms = 25.0
|
||||
#
|
||||
# Controls the depth of the delay. The delay will vary between delay_ms +/- depth_ms.
|
||||
# chorus_depth_ms = 1.0
|
||||
#
|
||||
# Frequency of LFO which controls delay.
|
||||
# chorus_lfo_freq = 0.5
|
||||
#
|
||||
# Controls dry/wet-ness of effect. 1.0 = full chorus, 0.0 = no chorus.
|
||||
# chorus_drywet = 0.8
|
||||
@@ -0,0 +1,4 @@
|
||||
filters = 1
|
||||
filter0 = crystalizer
|
||||
# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max.
|
||||
crystalizer_intensity = 5.0
|
||||
@@ -0,0 +1,41 @@
|
||||
filters = 1
|
||||
filter0 = eq
|
||||
|
||||
# Defaults
|
||||
|
||||
# Beta factor for Kaiser window.
|
||||
# Lower values will allow better frequency resolution, but more ripple.
|
||||
# eq_window_beta = 4.0
|
||||
|
||||
# The block size on which FFT is done.
|
||||
# Too high value requires more processing as well as longer latency but
|
||||
# allows finer-grained control over the spectrum.
|
||||
# eq_block_size_log2 = 8
|
||||
|
||||
# An array of which frequencies to control.
|
||||
# You can create an arbitrary amount of these sampling points.
|
||||
# The EQ will try to create a frequency response which fits well to these points.
|
||||
# The filter response is linearly interpolated between sampling points here.
|
||||
#
|
||||
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
|
||||
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
|
||||
#
|
||||
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
|
||||
# eq_frequencies = "500 1000 2000"
|
||||
# eq_gains = "0 3 0"
|
||||
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.
|
||||
|
||||
# By default, this filter has a flat frequency response.
|
||||
|
||||
# Dumps the impulse response generated by the EQ as a plain-text file
|
||||
# with one coefficient per line.
|
||||
# eq_impulse_response_output = "eq_impulse.txt"
|
||||
#
|
||||
# Using GNU Octave or Matlab, you can plot the response with:
|
||||
#
|
||||
# f = fopen('/path/to/eq_impulse.txt');
|
||||
# l = textscan(f, '%f');
|
||||
# res = l{1};
|
||||
# freqz(res, 1, 4096, 48000);
|
||||
#
|
||||
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch
|
||||
@@ -0,0 +1,19 @@
|
||||
filters = 1
|
||||
filter0 = echo
|
||||
|
||||
# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.
|
||||
# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.
|
||||
|
||||
# Defaults, 200 ms delay echo with feedback:
|
||||
# Delay in ms. Takes an array with multiple channels.
|
||||
# echo_delay = "200"
|
||||
# Feedback factor for echo.
|
||||
# echo_feedback = "0.5"
|
||||
# Overall echo amplification. If too high, the echo becomes unstable due to feedback.
|
||||
# echo_amp = "0.2"
|
||||
|
||||
# Reverby preset.
|
||||
# echo_delay = " 60 80 120 172 200 320 380"
|
||||
# echo_feedback = "0.5 0.5 0.4 0.3 0.5 0.3 0.2"
|
||||
|
||||
# echo_amp = "0.12"
|
||||
@@ -0,0 +1,12 @@
|
||||
filters = 2
|
||||
filter0 = echo
|
||||
filter1 = reverb
|
||||
|
||||
echo_delay = "200"
|
||||
echo_feedback = "0.6"
|
||||
echo_amp = "0.25"
|
||||
|
||||
reverb_roomwidth = 0.75
|
||||
reverb_roomsize = 0.75
|
||||
reverb_damping = 1.0
|
||||
reverb_wettime = 0.3
|
||||
@@ -0,0 +1,7 @@
|
||||
filters = 1
|
||||
filter0 = iir
|
||||
|
||||
iir_gain = -12.0
|
||||
iir_type = HSH
|
||||
iir_frequency = 8000.0
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
filters = 1
|
||||
filter0 = iir
|
||||
|
||||
# Defaults.
|
||||
#iir_frequency = 1024.0
|
||||
#iir_quality = 0.707
|
||||
#iir_gain = 0.0
|
||||
#iir_type = LPF
|
||||
|
||||
# Filter types:
|
||||
# LPF: Low-pass
|
||||
# HPF: High-pass
|
||||
# BPCSGF: Band-pass #1
|
||||
# BPZPGF: Band-pass #2
|
||||
# APF: Allpass
|
||||
# NOTCH: Notch filter
|
||||
# RIAA_phono: RIAA record/tape deemphasis
|
||||
# PEQ: peaking band EQ
|
||||
# BBOOST: Bassboost
|
||||
# LSH: Low-shelf
|
||||
# HSH: High-shelf
|
||||
# RIAA_CD: CD de-emphasis
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
filters = 1
|
||||
filter0 = eq
|
||||
|
||||
eq_frequencies = "8000 10000 12500 16000 20000"
|
||||
eq_gains = "0 -30 -30 -30 -30"
|
||||
|
||||
# Low pass filter for the QSound chip from CPS-1/2.
|
||||
# Some games have aliasing due low quality samples, so you can hear some annoying noisy near 11 kHz
|
||||
|
||||
# Defaults
|
||||
|
||||
# Beta factor for Kaiser window.
|
||||
# Lower values will allow better frequency resolution, but more ripple.
|
||||
# eq_window_beta = 4.0
|
||||
|
||||
# The block size on which FFT is done.
|
||||
# Too high value requires more processing as well as longer latency but
|
||||
# allows finer-grained control over the spectrum.
|
||||
# eq_block_size_log2 = 8
|
||||
|
||||
# An array of which frequencies to control.
|
||||
# You can create an arbitrary amount of these sampling points.
|
||||
# The EQ will try to create a frequency response which fits well to these points.
|
||||
# The filter response is linearly interpolated between sampling points here.
|
||||
#
|
||||
# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
|
||||
# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
|
||||
#
|
||||
# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
|
||||
# eq_frequencies = "500 1000 2000"
|
||||
# eq_gains = "0 3 0"
|
||||
# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.
|
||||
|
||||
# By default, this filter has a low pass response with cuttof frequency at ~8600 Hz.
|
||||
|
||||
# Dumps the impulse response generated by the EQ as a plain-text file
|
||||
# with one coefficient per line.
|
||||
# eq_impulse_response_output = "eq_impulse.txt"
|
||||
#
|
||||
# Using GNU Octave or Matlab, you can plot the response with:
|
||||
#
|
||||
# f = fopen('/path/to/eq_impulse.txt');
|
||||
# l = textscan(f, '%f');
|
||||
# res = l{1};
|
||||
# freqz(res, 1, 4096, 48000);
|
||||
#
|
||||
# It will give the response in Hz; 48000 is the default Output Rate of RetroArch
|
||||
@@ -0,0 +1,100 @@
|
||||
compiler := gcc
|
||||
extra_flags :=
|
||||
use_neon := 0
|
||||
build = release
|
||||
DYLIB := so
|
||||
PREFIX := /usr
|
||||
INSTALLDIR := $(PREFIX)/lib/retroarch/filters/audio
|
||||
|
||||
ifeq ($(platform),)
|
||||
platform = unix
|
||||
ifeq ($(shell uname -a),)
|
||||
platform = win
|
||||
else ifneq ($(findstring MINGW,$(shell uname -a)),)
|
||||
platform = win
|
||||
else ifneq ($(findstring Darwin,$(shell uname -a)),)
|
||||
platform = osx
|
||||
arch = intel
|
||||
ifeq ($(shell uname -p),powerpc)
|
||||
arch = ppc
|
||||
endif
|
||||
else ifneq ($(findstring win,$(shell uname -a)),)
|
||||
platform = win
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(platform),gcc)
|
||||
extra_rules_gcc := $(shell $(compiler) -dumpmachine)
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring armv7,$(extra_rules_gcc)))
|
||||
extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
|
||||
use_neon := 1
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
|
||||
extra_flags += -mfloat-abi=hard
|
||||
endif
|
||||
|
||||
ifeq (release,$(build))
|
||||
extra_flags += -O2
|
||||
endif
|
||||
|
||||
ifeq (debug,$(build))
|
||||
extra_flags += -O0 -g
|
||||
endif
|
||||
|
||||
ldflags := $(LDFLAGS) -shared -lm -Wl,--version-script=link.T
|
||||
|
||||
ifeq ($(platform), unix)
|
||||
DYLIB = so
|
||||
else ifeq ($(platform), osx)
|
||||
compiler := $(CC)
|
||||
DYLIB = dylib
|
||||
ldflags := -dynamiclib
|
||||
else
|
||||
extra_flags += -static-libgcc -static-libstdc++
|
||||
DYLIB = dll
|
||||
endif
|
||||
|
||||
CC := $(compiler) -Wall
|
||||
CXX := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall
|
||||
flags := $(CPPFLAGS) $(CFLAGS) -fPIC $(extra_flags) -I../../include
|
||||
asflags := $(ASFLAGS) -fPIC $(extra_flags)
|
||||
objects :=
|
||||
|
||||
ifeq (1,$(use_neon))
|
||||
ASMFLAGS := -INEON/asm
|
||||
asflags += -mfpu=neon
|
||||
endif
|
||||
|
||||
plugs := $(wildcard *.c)
|
||||
objects := $(plugs:.c=.o)
|
||||
targets := $(objects:.o=.$(DYLIB))
|
||||
|
||||
all: build;
|
||||
|
||||
%.o: %.S
|
||||
$(CC) -c -o $@ $(asflags) $(ASMFLAGS) $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $(flags) $<
|
||||
|
||||
%.$(DYLIB): %.o
|
||||
$(CC) -o $@ $(ldflags) $(flags) $^
|
||||
|
||||
build: $(targets)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *.$(DYLIB)
|
||||
|
||||
strip:
|
||||
strip -s *.$(DYLIB)
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(INSTALLDIR)
|
||||
cp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp
|
||||
|
||||
test-install:
|
||||
DESTDIR=/tmp/build $(MAKE) install
|
||||
@@ -0,0 +1,12 @@
|
||||
filters = 1
|
||||
filter0 = panning
|
||||
|
||||
# Gains are linear.
|
||||
|
||||
# Stereo Mono:
|
||||
panning_left_mix = "0.5 0.5"
|
||||
panning_right_mix = "0.5 0.5"
|
||||
|
||||
# Mono on one speaker:
|
||||
# panning_left_mix = "0.5 0.5"
|
||||
# panning_right_mix = "0.0 0.0"
|
||||
@@ -0,0 +1,23 @@
|
||||
filters = 1
|
||||
filter0 = panning
|
||||
|
||||
# Gains are linear.
|
||||
|
||||
# The default. Left and right channels map to each other.
|
||||
panning_left_mix = "1.0 0.0"
|
||||
panning_right_mix = "0.0 1.0"
|
||||
|
||||
# Some examples:
|
||||
#
|
||||
# Mono:
|
||||
# panning_left_mix = "0.5 0.5"
|
||||
# panning_right_mix = "0.5 0.5"
|
||||
|
||||
# Swap left and right channels:
|
||||
# panning_left_mix = "0.0 1.0"
|
||||
# panning_right_mix = "1.0 0.0"
|
||||
#
|
||||
# Mono on one speaker:
|
||||
# panning_left_mix = "0.5 0.5"
|
||||
# panning_right_mix = "0.0 0.0"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
filters = 1
|
||||
filter0 = phaser
|
||||
|
||||
# Defaults.
|
||||
# phaser_lfo_freq = 0.4
|
||||
# phaser_lfo_start_phase = 0.0
|
||||
# phaser_feedback = 0.0
|
||||
# phaser_depth = 0.4
|
||||
# phaser_dry_wet = 0.5
|
||||
# phaser_stages = 2
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
filters = 1
|
||||
filter0 = reverb
|
||||
|
||||
# Defaults.
|
||||
# reverb_drytime = 0.43
|
||||
# reverb_wettime = 0.4
|
||||
# reverb_damping = 0.8
|
||||
# reverb_roomwidth = 0.56
|
||||
# reverb_roomsize = 0.56
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
filters = 1
|
||||
filter0 = tremolo
|
||||
|
||||
# Defaults.
|
||||
#tremolo_frequency = 4.0
|
||||
#tremolo_depth = 0.9
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
filters = 1
|
||||
filter0 = vibrato
|
||||
|
||||
# Defaults.
|
||||
#vibrato_frequency = 5.0
|
||||
#vibrato_depth = 0.5
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
filters = 1
|
||||
filter0 = wahwah
|
||||
|
||||
# Defaults.
|
||||
# wahwah_lfo_freq = 1.5
|
||||
# wahwah_lfo_start_phase = 0.0
|
||||
# wahwah_freq_offset = 0.3
|
||||
# wahwah_depth = 0.7
|
||||
# wahwah_resonance = 2.5
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (chorus.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
#define CHORUS_MAX_DELAY 4096
|
||||
#define CHORUS_DELAY_MASK (CHORUS_MAX_DELAY - 1)
|
||||
|
||||
struct chorus_data
|
||||
{
|
||||
float old[2][CHORUS_MAX_DELAY];
|
||||
unsigned old_ptr;
|
||||
|
||||
float delay;
|
||||
float depth;
|
||||
float input_rate;
|
||||
float mix_dry;
|
||||
float mix_wet;
|
||||
unsigned lfo_ptr;
|
||||
unsigned lfo_period;
|
||||
};
|
||||
|
||||
static void chorus_free(void *data)
|
||||
{
|
||||
if (data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void chorus_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
float *out = NULL;
|
||||
struct chorus_data *ch = (struct chorus_data*)data;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
out = output->samples;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
unsigned delay_int;
|
||||
float delay_frac, l_a, l_b, r_a, r_b;
|
||||
float chorus_l, chorus_r;
|
||||
float in[2] = { out[0], out[1] };
|
||||
float delay = ch->delay + ch->depth * sin((2.0 * M_PI * ch->lfo_ptr++) / ch->lfo_period);
|
||||
|
||||
delay *= ch->input_rate;
|
||||
if (ch->lfo_ptr >= ch->lfo_period)
|
||||
ch->lfo_ptr = 0;
|
||||
|
||||
delay_int = (unsigned)delay;
|
||||
|
||||
if (delay_int >= CHORUS_MAX_DELAY - 1)
|
||||
delay_int = CHORUS_MAX_DELAY - 2;
|
||||
|
||||
delay_frac = delay - delay_int;
|
||||
|
||||
ch->old[0][ch->old_ptr] = in[0];
|
||||
ch->old[1][ch->old_ptr] = in[1];
|
||||
|
||||
l_a = ch->old[0][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
|
||||
l_b = ch->old[0][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];
|
||||
r_a = ch->old[1][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
|
||||
r_b = ch->old[1][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];
|
||||
|
||||
/* Lerp introduces aliasing of the chorus component,
|
||||
* but doing full polyphase here is probably overkill. */
|
||||
chorus_l = l_a * (1.0f - delay_frac) + l_b * delay_frac;
|
||||
chorus_r = r_a * (1.0f - delay_frac) + r_b * delay_frac;
|
||||
|
||||
out[0] = ch->mix_dry * in[0] + ch->mix_wet * chorus_l;
|
||||
out[1] = ch->mix_dry * in[1] + ch->mix_wet * chorus_r;
|
||||
|
||||
ch->old_ptr = (ch->old_ptr + 1) & CHORUS_DELAY_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
static void *chorus_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float delay, depth, lfo_freq, drywet;
|
||||
struct chorus_data *ch = (struct chorus_data*)calloc(1, sizeof(*ch));
|
||||
if (!ch)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "delay_ms", &delay, 25.0f);
|
||||
config->get_float(userdata, "depth_ms", &depth, 1.0f);
|
||||
config->get_float(userdata, "lfo_freq", &lfo_freq, 0.5f);
|
||||
config->get_float(userdata, "drywet", &drywet, 0.8f);
|
||||
|
||||
delay /= 1000.0f;
|
||||
depth /= 1000.0f;
|
||||
|
||||
if (depth > delay)
|
||||
depth = delay;
|
||||
|
||||
if (drywet < 0.0f)
|
||||
drywet = 0.0f;
|
||||
else if (drywet > 1.0f)
|
||||
drywet = 1.0f;
|
||||
|
||||
ch->mix_dry = 1.0f - 0.5f * drywet;
|
||||
ch->mix_wet = 0.5f * drywet;
|
||||
|
||||
ch->delay = delay;
|
||||
ch->depth = depth;
|
||||
ch->lfo_period = (1.0f / lfo_freq) * info->input_rate;
|
||||
ch->input_rate = info->input_rate;
|
||||
if (!ch->lfo_period)
|
||||
ch->lfo_period = 1;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation chorus_plug = {
|
||||
chorus_init,
|
||||
chorus_process,
|
||||
chorus_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Chorus",
|
||||
"chorus",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation chorus_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *
|
||||
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &chorus_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
PACKAGE_NAME=retroarch-filters-audio
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (echo.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
struct delta_data
|
||||
{
|
||||
float intensity;
|
||||
float old[2];
|
||||
};
|
||||
|
||||
static void delta_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void delta_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i, c;
|
||||
struct delta_data *d = (struct delta_data*)data;
|
||||
float *out = output->samples;
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
for (i = 0; i < input->frames; i++)
|
||||
{
|
||||
for (c = 0; c < 2; c++)
|
||||
{
|
||||
float current = *out;
|
||||
*out++ = current + (current - d->old[c]) * d->intensity;
|
||||
d->old[c] = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *delta_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d));
|
||||
if (!d)
|
||||
return NULL;
|
||||
config->get_float(userdata, "intensity", &d->intensity, 5.0f);
|
||||
return d;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation delta_plug = {
|
||||
delta_init,
|
||||
delta_process,
|
||||
delta_free,
|
||||
DSPFILTER_API_VERSION,
|
||||
"Delta Sharpening",
|
||||
"crystalizer",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation delta_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &delta_plug;
|
||||
}
|
||||
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (echo.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
struct echo_channel
|
||||
{
|
||||
float *buffer;
|
||||
unsigned ptr;
|
||||
unsigned frames;
|
||||
float feedback;
|
||||
};
|
||||
|
||||
struct echo_data
|
||||
{
|
||||
struct echo_channel *channels;
|
||||
unsigned num_channels;
|
||||
float amp;
|
||||
};
|
||||
|
||||
static void echo_free(void *data)
|
||||
{
|
||||
unsigned i;
|
||||
struct echo_data *echo = (struct echo_data*)data;
|
||||
|
||||
for (i = 0; i < echo->num_channels; i++)
|
||||
free(echo->channels[i].buffer);
|
||||
free(echo->channels);
|
||||
free(echo);
|
||||
}
|
||||
|
||||
static void echo_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i, c;
|
||||
float *out = NULL;
|
||||
struct echo_data *echo = (struct echo_data*)data;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
out = output->samples;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float left, right;
|
||||
float echo_left = 0.0f;
|
||||
float echo_right = 0.0f;
|
||||
|
||||
for (c = 0; c < echo->num_channels; c++)
|
||||
{
|
||||
echo_left += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0];
|
||||
echo_right += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1];
|
||||
}
|
||||
|
||||
echo_left *= echo->amp;
|
||||
echo_right *= echo->amp;
|
||||
|
||||
left = out[0] + echo_left;
|
||||
right = out[1] + echo_right;
|
||||
|
||||
for (c = 0; c < echo->num_channels; c++)
|
||||
{
|
||||
float feedback_left = out[0] + echo->channels[c].feedback * echo_left;
|
||||
float feedback_right = out[1] + echo->channels[c].feedback * echo_right;
|
||||
|
||||
echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0] = feedback_left;
|
||||
echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1] = feedback_right;
|
||||
|
||||
echo->channels[c].ptr = (echo->channels[c].ptr + 1) % echo->channels[c].frames;
|
||||
}
|
||||
|
||||
out[0] = left;
|
||||
out[1] = right;
|
||||
}
|
||||
}
|
||||
|
||||
static void *echo_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
unsigned i, channels;
|
||||
struct echo_channel *echo_channels = NULL;
|
||||
float *delay = NULL;
|
||||
float *feedback = NULL;
|
||||
unsigned num_delay = 0;
|
||||
unsigned num_feedback = 0;
|
||||
|
||||
static const float default_delay[] = { 200.0f };
|
||||
static const float default_feedback[] = { 0.5f };
|
||||
struct echo_data *echo = (struct echo_data*)
|
||||
calloc(1, sizeof(*echo));
|
||||
|
||||
if (!echo)
|
||||
return NULL;
|
||||
|
||||
config->get_float_array(userdata, "delay", &delay,
|
||||
&num_delay, default_delay, 1);
|
||||
config->get_float_array(userdata, "feedback", &feedback,
|
||||
&num_feedback, default_feedback, 1);
|
||||
config->get_float(userdata, "amp", &echo->amp, 0.2f);
|
||||
|
||||
channels = num_feedback = num_delay = MIN(num_delay, num_feedback);
|
||||
|
||||
echo_channels = (struct echo_channel*)calloc(channels,
|
||||
sizeof(*echo_channels));
|
||||
|
||||
if (!echo_channels)
|
||||
goto error;
|
||||
|
||||
echo->channels = echo_channels;
|
||||
echo->num_channels = channels;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
{
|
||||
unsigned frames = (unsigned)(delay[i] * info->input_rate / 1000.0f + 0.5f);
|
||||
if (!frames)
|
||||
goto error;
|
||||
|
||||
echo->channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float));
|
||||
if (!echo->channels[i].buffer)
|
||||
goto error;
|
||||
|
||||
echo->channels[i].frames = frames;
|
||||
echo->channels[i].feedback = feedback[i];
|
||||
}
|
||||
|
||||
config->free(delay);
|
||||
config->free(feedback);
|
||||
return echo;
|
||||
|
||||
error:
|
||||
config->free(delay);
|
||||
config->free(feedback);
|
||||
echo_free(echo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const struct dspfilter_implementation echo_plug = {
|
||||
echo_init,
|
||||
echo_process,
|
||||
echo_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Multi-Echo",
|
||||
"echo",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation echo_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &echo_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (eq.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <filters.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
#include "fft/fft.c"
|
||||
|
||||
struct eq_data
|
||||
{
|
||||
fft_t *fft;
|
||||
float buffer[8 * 1024];
|
||||
|
||||
float *save;
|
||||
float *block;
|
||||
fft_complex_t *filter;
|
||||
fft_complex_t *fftblock;
|
||||
unsigned block_size;
|
||||
unsigned block_ptr;
|
||||
};
|
||||
|
||||
struct eq_gain
|
||||
{
|
||||
float freq;
|
||||
float gain; /* Linear. */
|
||||
};
|
||||
|
||||
static void eq_free(void *data)
|
||||
{
|
||||
struct eq_data *eq = (struct eq_data*)data;
|
||||
if (!eq)
|
||||
return;
|
||||
|
||||
fft_free(eq->fft);
|
||||
free(eq->save);
|
||||
free(eq->block);
|
||||
free(eq->fftblock);
|
||||
free(eq->filter);
|
||||
free(eq);
|
||||
}
|
||||
|
||||
static void eq_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
float *out;
|
||||
const float *in;
|
||||
unsigned input_frames;
|
||||
struct eq_data *eq = (struct eq_data*)data;
|
||||
|
||||
output->samples = eq->buffer;
|
||||
output->frames = 0;
|
||||
|
||||
out = eq->buffer;
|
||||
in = input->samples;
|
||||
input_frames = input->frames;
|
||||
|
||||
while (input_frames)
|
||||
{
|
||||
unsigned write_avail = eq->block_size - eq->block_ptr;
|
||||
|
||||
if (input_frames < write_avail)
|
||||
write_avail = input_frames;
|
||||
|
||||
memcpy(eq->block + eq->block_ptr * 2, in, write_avail * 2 * sizeof(float));
|
||||
|
||||
in += write_avail * 2;
|
||||
input_frames -= write_avail;
|
||||
eq->block_ptr += write_avail;
|
||||
|
||||
// Convolve a new block.
|
||||
if (eq->block_ptr == eq->block_size)
|
||||
{
|
||||
unsigned i, c;
|
||||
|
||||
for (c = 0; c < 2; c++)
|
||||
{
|
||||
fft_process_forward(eq->fft, eq->fftblock, eq->block + c, 2);
|
||||
for (i = 0; i < 2 * eq->block_size; i++)
|
||||
eq->fftblock[i] = fft_complex_mul(eq->fftblock[i], eq->filter[i]);
|
||||
fft_process_inverse(eq->fft, out + c, eq->fftblock, 2);
|
||||
}
|
||||
|
||||
// Overlap add method, so add in saved block now.
|
||||
for (i = 0; i < 2 * eq->block_size; i++)
|
||||
out[i] += eq->save[i];
|
||||
|
||||
// Save block for later.
|
||||
memcpy(eq->save, out + 2 * eq->block_size, 2 * eq->block_size * sizeof(float));
|
||||
|
||||
out += eq->block_size * 2;
|
||||
output->frames += eq->block_size;
|
||||
eq->block_ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int gains_cmp(const void *a_, const void *b_)
|
||||
{
|
||||
const struct eq_gain *a = (const struct eq_gain*)a_;
|
||||
const struct eq_gain *b = (const struct eq_gain*)b_;
|
||||
if (a->freq < b->freq)
|
||||
return -1;
|
||||
if (a->freq > b->freq)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void generate_response(fft_complex_t *response,
|
||||
const struct eq_gain *gains, unsigned num_gains, unsigned samples)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
float start_freq = 0.0f;
|
||||
float start_gain = 1.0f;
|
||||
|
||||
float end_freq = 1.0f;
|
||||
float end_gain = 1.0f;
|
||||
|
||||
if (num_gains)
|
||||
{
|
||||
end_freq = gains->freq;
|
||||
end_gain = gains->gain;
|
||||
num_gains--;
|
||||
gains++;
|
||||
}
|
||||
|
||||
/* Create a response by linear interpolation between
|
||||
* known frequency sample points. */
|
||||
for (i = 0; i <= samples; i++)
|
||||
{
|
||||
float gain;
|
||||
float lerp = 0.5f;
|
||||
float freq = (float)i / samples;
|
||||
|
||||
while (freq >= end_freq)
|
||||
{
|
||||
if (num_gains)
|
||||
{
|
||||
start_freq = end_freq;
|
||||
start_gain = end_gain;
|
||||
end_freq = gains->freq;
|
||||
end_gain = gains->gain;
|
||||
|
||||
gains++;
|
||||
num_gains--;
|
||||
}
|
||||
else
|
||||
{
|
||||
start_freq = end_freq;
|
||||
start_gain = end_gain;
|
||||
end_freq = 1.0f;
|
||||
end_gain = 1.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Edge case where i == samples. */
|
||||
if (end_freq > start_freq)
|
||||
lerp = (freq - start_freq) / (end_freq - start_freq);
|
||||
gain = (1.0f - lerp) * start_gain + lerp * end_gain;
|
||||
|
||||
response[i].real = gain;
|
||||
response[i].imag = 0.0f;
|
||||
response[2 * samples - i].real = gain;
|
||||
response[2 * samples - i].imag = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void create_filter(struct eq_data *eq, unsigned size_log2,
|
||||
struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
|
||||
{
|
||||
int i;
|
||||
int half_block_size = eq->block_size >> 1;
|
||||
double window_mod = 1.0 / kaiser_window_function(0.0, beta);
|
||||
|
||||
fft_t *fft = fft_new(size_log2);
|
||||
float *time_filter = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
|
||||
if (!fft || !time_filter)
|
||||
goto end;
|
||||
|
||||
/* Make sure bands are in correct order. */
|
||||
qsort(gains, num_gains, sizeof(*gains), gains_cmp);
|
||||
|
||||
/* Compute desired filter response. */
|
||||
generate_response(eq->filter, gains, num_gains, half_block_size);
|
||||
|
||||
/* Get equivalent time-domain filter. */
|
||||
fft_process_inverse(fft, time_filter, eq->filter, 1);
|
||||
|
||||
/* ifftshift() to create the correct linear phase filter.
|
||||
* The filter response was designed with zero phase, which
|
||||
* won't work unless we compensate
|
||||
* for the repeating property of the FFT here
|
||||
* by flipping left and right blocks. */
|
||||
for (i = 0; i < half_block_size; i++)
|
||||
{
|
||||
float tmp = time_filter[i + half_block_size];
|
||||
time_filter[i + half_block_size] = time_filter[i];
|
||||
time_filter[i] = tmp;
|
||||
}
|
||||
|
||||
/* Apply a window to smooth out the frequency repsonse. */
|
||||
for (i = 0; i < (int)eq->block_size; i++)
|
||||
{
|
||||
/* Kaiser window. */
|
||||
double phase = (double)i / eq->block_size;
|
||||
phase = 2.0 * (phase - 0.5);
|
||||
time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
|
||||
}
|
||||
|
||||
/* Debugging. */
|
||||
if (filter_path)
|
||||
{
|
||||
FILE *file = fopen(filter_path, "w");
|
||||
if (file)
|
||||
{
|
||||
for (i = 0; i < (int)eq->block_size - 1; i++)
|
||||
fprintf(file, "%.8f\n", time_filter[i + 1]);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
/* Padded FFT to create our FFT filter.
|
||||
* Make our even-length filter odd by discarding the first coefficient.
|
||||
* For some interesting reason, this allows us to design an odd-length linear phase filter.
|
||||
*/
|
||||
fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);
|
||||
|
||||
end:
|
||||
fft_free(fft);
|
||||
free(time_filter);
|
||||
}
|
||||
|
||||
static void *eq_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float *frequencies, *gain;
|
||||
unsigned num_freq, num_gain, i, size;
|
||||
int size_log2;
|
||||
float beta;
|
||||
struct eq_gain *gains = NULL;
|
||||
char *filter_path = NULL;
|
||||
const float default_freq[] = { 0.0f, info->input_rate };
|
||||
const float default_gain[] = { 0.0f, 0.0f };
|
||||
struct eq_data *eq = (struct eq_data*)calloc(1, sizeof(*eq));
|
||||
if (!eq)
|
||||
return NULL;
|
||||
|
||||
|
||||
config->get_float(userdata, "window_beta", &beta, 4.0f);
|
||||
|
||||
config->get_int(userdata, "block_size_log2", &size_log2, 8);
|
||||
size = 1 << size_log2;
|
||||
|
||||
config->get_float_array(userdata, "frequencies", &frequencies, &num_freq, default_freq, 2);
|
||||
config->get_float_array(userdata, "gains", &gain, &num_gain, default_gain, 2);
|
||||
|
||||
if (!config->get_string(userdata, "impulse_response_output", &filter_path, ""))
|
||||
{
|
||||
config->free(filter_path);
|
||||
filter_path = NULL;
|
||||
}
|
||||
|
||||
num_gain = num_freq = MIN(num_gain, num_freq);
|
||||
|
||||
gains = (struct eq_gain*)calloc(num_gain, sizeof(*gains));
|
||||
if (!gains)
|
||||
goto error;
|
||||
|
||||
for (i = 0; i < num_gain; i++)
|
||||
{
|
||||
gains[i].freq = frequencies[i] / (0.5f * info->input_rate);
|
||||
gains[i].gain = pow(10.0, gain[i] / 20.0);
|
||||
}
|
||||
config->free(frequencies);
|
||||
config->free(gain);
|
||||
|
||||
eq->block_size = size;
|
||||
|
||||
eq->save = (float*)calloc( size, 2 * sizeof(*eq->save));
|
||||
eq->block = (float*)calloc(2 * size, 2 * sizeof(*eq->block));
|
||||
eq->fftblock = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));
|
||||
eq->filter = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));
|
||||
|
||||
/* Use an FFT which is twice the block size with zero-padding
|
||||
* to make circular convolution => proper convolution.
|
||||
*/
|
||||
eq->fft = fft_new(size_log2 + 1);
|
||||
|
||||
if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)
|
||||
goto error;
|
||||
|
||||
create_filter(eq, size_log2, gains, num_gain, beta, filter_path);
|
||||
config->free(filter_path);
|
||||
filter_path = NULL;
|
||||
|
||||
free(gains);
|
||||
return eq;
|
||||
|
||||
error:
|
||||
free(gains);
|
||||
eq_free(eq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation eq_plug = {
|
||||
eq_init,
|
||||
eq_process,
|
||||
eq_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Linear-Phase FFT Equalizer",
|
||||
"eq",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation eq_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &eq_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fft.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fft.h"
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
struct fft
|
||||
{
|
||||
fft_complex_t *interleave_buffer;
|
||||
fft_complex_t *phase_lut;
|
||||
unsigned *bitinverse_buffer;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
static unsigned bitswap(unsigned x, unsigned size_log2)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned ret = 0;
|
||||
for (i = 0; i < size_log2; i++)
|
||||
ret |= ((x >> i) & 1) << (size_log2 - i - 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void build_bitinverse(unsigned *bitinverse, unsigned size_log2)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned size = 1 << size_log2;
|
||||
for (i = 0; i < size; i++)
|
||||
bitinverse[i] = bitswap(i, size_log2);
|
||||
}
|
||||
|
||||
static fft_complex_t exp_imag(double phase)
|
||||
{
|
||||
fft_complex_t out = { cos(phase), sin(phase) };
|
||||
return out;
|
||||
}
|
||||
|
||||
static void build_phase_lut(fft_complex_t *out, int size)
|
||||
{
|
||||
int i;
|
||||
out += size;
|
||||
for (i = -size; i <= size; i++)
|
||||
out[i] = exp_imag((M_PI * i) / size);
|
||||
}
|
||||
|
||||
static void interleave_complex(const unsigned *bitinverse,
|
||||
fft_complex_t *out, const fft_complex_t *in,
|
||||
unsigned samples, unsigned step)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < samples; i++, in += step)
|
||||
out[bitinverse[i]] = *in;
|
||||
}
|
||||
|
||||
static void interleave_float(const unsigned *bitinverse,
|
||||
fft_complex_t *out, const float *in,
|
||||
unsigned samples, unsigned step)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < samples; i++, in += step)
|
||||
{
|
||||
unsigned inv_i = bitinverse[i];
|
||||
out[inv_i].real = *in;
|
||||
out[inv_i].imag = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_float(float *out, const fft_complex_t *in, unsigned samples,
|
||||
float gain, unsigned step)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < samples; i++, in++, out += step)
|
||||
*out = gain * in->real;
|
||||
}
|
||||
|
||||
fft_t *fft_new(unsigned block_size_log2)
|
||||
{
|
||||
unsigned size;
|
||||
fft_t *fft = (fft_t*)calloc(1, sizeof(*fft));
|
||||
if (!fft)
|
||||
return NULL;
|
||||
|
||||
size = 1 << block_size_log2;
|
||||
fft->interleave_buffer = (fft_complex_t*)calloc(size, sizeof(*fft->interleave_buffer));
|
||||
fft->bitinverse_buffer = (unsigned*)calloc(size, sizeof(*fft->bitinverse_buffer));
|
||||
fft->phase_lut = (fft_complex_t*)calloc(2 * size + 1, sizeof(*fft->phase_lut));
|
||||
|
||||
if (!fft->interleave_buffer || !fft->bitinverse_buffer || !fft->phase_lut)
|
||||
goto error;
|
||||
|
||||
fft->size = size;
|
||||
|
||||
build_bitinverse(fft->bitinverse_buffer, block_size_log2);
|
||||
build_phase_lut(fft->phase_lut, size);
|
||||
return fft;
|
||||
|
||||
error:
|
||||
fft_free(fft);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fft_free(fft_t *fft)
|
||||
{
|
||||
if (!fft)
|
||||
return;
|
||||
|
||||
free(fft->interleave_buffer);
|
||||
free(fft->bitinverse_buffer);
|
||||
free(fft->phase_lut);
|
||||
free(fft);
|
||||
}
|
||||
|
||||
static void butterfly(fft_complex_t *a, fft_complex_t *b, fft_complex_t mod)
|
||||
{
|
||||
mod = fft_complex_mul(mod, *b);
|
||||
*b = fft_complex_sub(*a, mod);
|
||||
*a = fft_complex_add(*a, mod);
|
||||
}
|
||||
|
||||
static void butterflies(fft_complex_t *butterfly_buf,
|
||||
const fft_complex_t *phase_lut,
|
||||
int phase_dir, unsigned step_size, unsigned samples)
|
||||
{
|
||||
unsigned i, j;
|
||||
for (i = 0; i < samples; i += step_size << 1)
|
||||
{
|
||||
int phase_step = (int)samples * phase_dir / (int)step_size;
|
||||
for (j = i; j < i + step_size; j++)
|
||||
butterfly(&butterfly_buf[j], &butterfly_buf[j + step_size],
|
||||
phase_lut[phase_step * (int)(j - i)]);
|
||||
}
|
||||
}
|
||||
|
||||
void fft_process_forward_complex(fft_t *fft,
|
||||
fft_complex_t *out, const fft_complex_t *in, unsigned step)
|
||||
{
|
||||
unsigned step_size;
|
||||
unsigned samples = fft->size;
|
||||
interleave_complex(fft->bitinverse_buffer, out, in, samples, step);
|
||||
|
||||
for (step_size = 1; step_size < samples; step_size <<= 1)
|
||||
{
|
||||
butterflies(out,
|
||||
fft->phase_lut + samples,
|
||||
-1, step_size, samples);
|
||||
}
|
||||
}
|
||||
|
||||
void fft_process_forward(fft_t *fft,
|
||||
fft_complex_t *out, const float *in, unsigned step)
|
||||
{
|
||||
unsigned step_size;
|
||||
unsigned samples = fft->size;
|
||||
interleave_float(fft->bitinverse_buffer, out, in, samples, step);
|
||||
|
||||
for (step_size = 1; step_size < fft->size; step_size <<= 1)
|
||||
{
|
||||
butterflies(out,
|
||||
fft->phase_lut + samples,
|
||||
-1, step_size, samples);
|
||||
}
|
||||
}
|
||||
|
||||
void fft_process_inverse(fft_t *fft,
|
||||
float *out, const fft_complex_t *in, unsigned step)
|
||||
{
|
||||
unsigned step_size;
|
||||
unsigned samples = fft->size;
|
||||
|
||||
interleave_complex(fft->bitinverse_buffer, fft->interleave_buffer,
|
||||
in, samples, 1);
|
||||
|
||||
for (step_size = 1; step_size < samples; step_size <<= 1)
|
||||
{
|
||||
butterflies(fft->interleave_buffer,
|
||||
fft->phase_lut + samples,
|
||||
1, step_size, samples);
|
||||
}
|
||||
|
||||
resolve_float(out, fft->interleave_buffer, samples, 1.0f / samples, step);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fft.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef RARCH_FFT_H__
|
||||
#define RARCH_FFT_H__
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <math/complex.h>
|
||||
|
||||
typedef struct fft fft_t;
|
||||
|
||||
fft_t *fft_new(unsigned block_size_log2);
|
||||
|
||||
void fft_free(fft_t *fft);
|
||||
|
||||
void fft_process_forward_complex(fft_t *fft,
|
||||
fft_complex_t *out, const fft_complex_t *in, unsigned step);
|
||||
|
||||
void fft_process_forward(fft_t *fft,
|
||||
fft_complex_t *out, const float *in, unsigned step);
|
||||
|
||||
void fft_process_inverse(fft_t *fft,
|
||||
float *out, const fft_complex_t *in, unsigned step);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (iir.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#define sqr(a) ((a) * (a))
|
||||
|
||||
/* filter types */
|
||||
enum IIRFilter
|
||||
{
|
||||
LPF, /* low pass filter */
|
||||
HPF, /* High pass filter */
|
||||
BPCSGF, /* band pass filter 1 */
|
||||
BPZPGF, /* band pass filter 2 */
|
||||
APF, /* Allpass filter*/
|
||||
NOTCH, /* Notch Filter */
|
||||
RIAA_phono, /* RIAA record/tape deemphasis */
|
||||
PEQ, /* Peaking band EQ filter */
|
||||
BBOOST, /* Bassboost filter */
|
||||
LSH, /* Low shelf filter */
|
||||
HSH, /* High shelf filter */
|
||||
RIAA_CD /* CD de-emphasis */
|
||||
};
|
||||
|
||||
struct iir_data
|
||||
{
|
||||
float b0, b1, b2;
|
||||
float a0, a1, a2;
|
||||
|
||||
struct
|
||||
{
|
||||
float xn1, xn2;
|
||||
float yn1, yn2;
|
||||
} l, r;
|
||||
};
|
||||
|
||||
static void iir_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void iir_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
struct iir_data *iir = (struct iir_data*)data;
|
||||
float *out = output->samples;
|
||||
|
||||
float b0 = iir->b0;
|
||||
float b1 = iir->b1;
|
||||
float b2 = iir->b2;
|
||||
float a0 = iir->a0;
|
||||
float a1 = iir->a1;
|
||||
float a2 = iir->a2;
|
||||
|
||||
float xn1_l = iir->l.xn1;
|
||||
float xn2_l = iir->l.xn2;
|
||||
float yn1_l = iir->l.yn1;
|
||||
float yn2_l = iir->l.yn2;
|
||||
|
||||
float xn1_r = iir->r.xn1;
|
||||
float xn2_r = iir->r.xn2;
|
||||
float yn1_r = iir->r.yn1;
|
||||
float yn2_r = iir->r.yn2;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float in_l = out[0];
|
||||
float in_r = out[1];
|
||||
|
||||
float l = (b0 * in_l + b1 * xn1_l + b2 * xn2_l - a1 * yn1_l - a2 * yn2_l) / a0;
|
||||
float r = (b0 * in_r + b1 * xn1_r + b2 * xn2_r - a1 * yn1_r - a2 * yn2_r) / a0;
|
||||
|
||||
xn2_l = xn1_l;
|
||||
xn1_l = in_l;
|
||||
yn2_l = yn1_l;
|
||||
yn1_l = l;
|
||||
|
||||
xn2_r = xn1_r;
|
||||
xn1_r = in_r;
|
||||
yn2_r = yn1_r;
|
||||
yn1_r = r;
|
||||
|
||||
out[0] = l;
|
||||
out[1] = r;
|
||||
}
|
||||
|
||||
iir->l.xn1 = xn1_l;
|
||||
iir->l.xn2 = xn2_l;
|
||||
iir->l.yn1 = yn1_l;
|
||||
iir->l.yn2 = yn2_l;
|
||||
|
||||
iir->r.xn1 = xn1_r;
|
||||
iir->r.xn2 = xn2_r;
|
||||
iir->r.yn1 = yn1_r;
|
||||
iir->r.yn2 = yn2_r;
|
||||
}
|
||||
|
||||
#define CHECK(x) if (string_is_equal(str, #x)) return x
|
||||
static enum IIRFilter str_to_type(const char *str)
|
||||
{
|
||||
CHECK(LPF);
|
||||
CHECK(HPF);
|
||||
CHECK(BPCSGF);
|
||||
CHECK(BPZPGF);
|
||||
CHECK(APF);
|
||||
CHECK(NOTCH);
|
||||
CHECK(RIAA_phono);
|
||||
CHECK(PEQ);
|
||||
CHECK(BBOOST);
|
||||
CHECK(LSH);
|
||||
CHECK(HSH);
|
||||
CHECK(RIAA_CD);
|
||||
|
||||
return LPF; /* Fallback. */
|
||||
}
|
||||
|
||||
static void make_poly_from_roots(
|
||||
const double *roots, unsigned num_roots, float *poly)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
poly[0] = 1;
|
||||
poly[1] = -roots[0];
|
||||
memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
|
||||
|
||||
for (i = 1; i < num_roots; i++)
|
||||
for (j = num_roots; j > 0; j--)
|
||||
poly[j] -= poly[j - 1] * roots[i];
|
||||
}
|
||||
|
||||
static void iir_filter_init(struct iir_data *iir,
|
||||
float sample_rate, float freq, float qual, float gain, enum IIRFilter filter_type)
|
||||
{
|
||||
double omega = 2.0 * M_PI * freq / sample_rate;
|
||||
double cs = cos(omega);
|
||||
double sn = sin(omega);
|
||||
double a1pha = sn / (2.0 * qual);
|
||||
double A = exp(log(10.0) * gain / 40.0);
|
||||
double beta = sqrt(A + A);
|
||||
|
||||
float b0 = 0.0, b1 = 0.0, b2 = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0;
|
||||
|
||||
/* Set up filter coefficients according to type */
|
||||
switch (filter_type)
|
||||
{
|
||||
case LPF:
|
||||
b0 = (1.0 - cs) / 2.0;
|
||||
b1 = 1.0 - cs ;
|
||||
b2 = (1.0 - cs) / 2.0;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case HPF:
|
||||
b0 = (1.0 + cs) / 2.0;
|
||||
b1 = -(1.0 + cs);
|
||||
b2 = (1.0 + cs) / 2.0;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case APF:
|
||||
b0 = 1.0 - a1pha;
|
||||
b1 = -2.0 * cs;
|
||||
b2 = 1.0 + a1pha;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case BPZPGF:
|
||||
b0 = a1pha;
|
||||
b1 = 0.0;
|
||||
b2 = -a1pha;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case BPCSGF:
|
||||
b0 = sn / 2.0;
|
||||
b1 = 0.0;
|
||||
b2 = -sn / 2.0;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case NOTCH:
|
||||
b0 = 1.0;
|
||||
b1 = -2.0 * cs;
|
||||
b2 = 1.0;
|
||||
a0 = 1.0 + a1pha;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha;
|
||||
break;
|
||||
case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */
|
||||
{
|
||||
double y, b_re, a_re, b_im, a_im, g;
|
||||
float b[3], a[3];
|
||||
|
||||
if ((int)sample_rate == 44100)
|
||||
{
|
||||
static const double zeros[] = {-0.2014898, 0.9233820};
|
||||
static const double poles[] = {0.7083149, 0.9924091};
|
||||
make_poly_from_roots(zeros, 2, b);
|
||||
make_poly_from_roots(poles, 2, a);
|
||||
}
|
||||
else if ((int)sample_rate == 48000)
|
||||
{
|
||||
static const double zeros[] = {-0.1766069, 0.9321590};
|
||||
static const double poles[] = {0.7396325, 0.9931330};
|
||||
make_poly_from_roots(zeros, 2, b);
|
||||
make_poly_from_roots(poles, 2, a);
|
||||
}
|
||||
else if ((int)sample_rate == 88200)
|
||||
{
|
||||
static const double zeros[] = {-0.1168735, 0.9648312};
|
||||
static const double poles[] = {0.8590646, 0.9964002};
|
||||
make_poly_from_roots(zeros, 2, b);
|
||||
make_poly_from_roots(poles, 2, a);
|
||||
}
|
||||
else if ((int)sample_rate == 96000)
|
||||
{
|
||||
static const double zeros[] = {-0.1141486, 0.9676817};
|
||||
static const double poles[] = {0.8699137, 0.9966946};
|
||||
make_poly_from_roots(zeros, 2, b);
|
||||
make_poly_from_roots(poles, 2, a);
|
||||
}
|
||||
|
||||
b0 = b[0];
|
||||
b1 = b[1];
|
||||
b2 = b[2];
|
||||
a0 = a[0];
|
||||
a1 = a[1];
|
||||
a2 = a[2];
|
||||
|
||||
|
||||
/* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
|
||||
y = 2.0 * M_PI * 1000.0 / sample_rate;
|
||||
b_re = b0 + b1 * cos(-y) + b2 * cos(-2.0 * y);
|
||||
a_re = a0 + a1 * cos(-y) + a2 * cos(-2.0 * y);
|
||||
b_im = b1 * sin(-y) + b2 * sin(-2.0 * y);
|
||||
a_im = a1 * sin(-y) + a2 * sin(-2.0 * y);
|
||||
g = 1.0 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
|
||||
b0 *= g; b1 *= g; b2 *= g;
|
||||
break;
|
||||
}
|
||||
case PEQ:
|
||||
b0 = 1.0 + a1pha * A;
|
||||
b1 = -2.0 * cs;
|
||||
b2 = 1.0 - a1pha * A;
|
||||
a0 = 1.0 + a1pha / A;
|
||||
a1 = -2.0 * cs;
|
||||
a2 = 1.0 - a1pha / A;
|
||||
break;
|
||||
case BBOOST:
|
||||
beta = sqrt((A * A + 1) / 1.0 - (pow((A - 1), 2)));
|
||||
b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
|
||||
b1 = 2 * A * ((A - 1) - (A + 1) * cs);
|
||||
b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
|
||||
a0 = ((A + 1) + (A - 1) * cs + beta * sn);
|
||||
a1 = -2 * ((A - 1) + (A + 1) * cs);
|
||||
a2 = (A + 1) + (A - 1) * cs - beta * sn;
|
||||
break;
|
||||
case LSH:
|
||||
b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
|
||||
b1 = 2 * A * ((A - 1) - (A + 1) * cs);
|
||||
b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
|
||||
a0 = (A + 1) + (A - 1) * cs + beta * sn;
|
||||
a1 = -2 * ((A - 1) + (A + 1) * cs);
|
||||
a2 = (A + 1) + (A - 1) * cs - beta * sn;
|
||||
break;
|
||||
case RIAA_CD:
|
||||
omega = 2.0 * M_PI * 5283.0 / sample_rate;
|
||||
cs = cos(omega);
|
||||
sn = sin(omega);
|
||||
a1pha = sn / (2.0 * 0.4845);
|
||||
A = exp(log(10.0) * -9.477 / 40.0);
|
||||
beta = sqrt(A + A);
|
||||
(void)a1pha;
|
||||
case HSH:
|
||||
b0 = A * ((A + 1.0) + (A - 1.0) * cs + beta * sn);
|
||||
b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cs);
|
||||
b2 = A * ((A + 1.0) + (A - 1.0) * cs - beta * sn);
|
||||
a0 = (A + 1.0) - (A - 1.0) * cs + beta * sn;
|
||||
a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cs);
|
||||
a2 = (A + 1.0) - (A - 1.0) * cs - beta * sn;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iir->b0 = b0;
|
||||
iir->b1 = b1;
|
||||
iir->b2 = b2;
|
||||
iir->a0 = a0;
|
||||
iir->a1 = a1;
|
||||
iir->a2 = a2;
|
||||
}
|
||||
|
||||
static void *iir_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float freq, qual, gain;
|
||||
enum IIRFilter filter = LPF;
|
||||
char *type = NULL;
|
||||
struct iir_data *iir = (struct iir_data*)calloc(1, sizeof(*iir));
|
||||
if (!iir)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "frequency", &freq, 1024.0f);
|
||||
config->get_float(userdata, "quality", &qual, 0.707f);
|
||||
config->get_float(userdata, "gain", &gain, 0.0f);
|
||||
|
||||
config->get_string(userdata, "type", &type, "LPF");
|
||||
|
||||
filter = str_to_type(type);
|
||||
config->free(type);
|
||||
|
||||
iir_filter_init(iir, info->input_rate, freq, qual, gain, filter);
|
||||
return iir;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation iir_plug = {
|
||||
iir_init,
|
||||
iir_process,
|
||||
iir_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"IIR",
|
||||
"iir",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation iir_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &iir_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
global: dspfilter_get_implementation;
|
||||
local: *;
|
||||
};
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (panning.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
struct panning_data
|
||||
{
|
||||
float left[2];
|
||||
float right[2];
|
||||
};
|
||||
|
||||
static void panning_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void panning_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
struct panning_data *pan = (struct panning_data*)data;
|
||||
float *out = output->samples;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float left = out[0];
|
||||
float right = out[1];
|
||||
out[0] = left * pan->left[0] + right * pan->left[1];
|
||||
out[1] = left * pan->right[0] + right * pan->right[1];
|
||||
}
|
||||
}
|
||||
|
||||
static void *panning_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
static const float default_left[] = { 1.0f, 0.0f };
|
||||
static const float default_right[] = { 0.0f, 1.0f };
|
||||
float *left = NULL;
|
||||
float *right = NULL;
|
||||
unsigned num_left = 0;
|
||||
unsigned num_right = 0;
|
||||
struct panning_data *pan = (struct panning_data*)
|
||||
calloc(1, sizeof(*pan));
|
||||
|
||||
if (!pan)
|
||||
return NULL;
|
||||
|
||||
config->get_float_array(userdata, "left_mix",
|
||||
&left, &num_left, default_left, 2);
|
||||
config->get_float_array(userdata, "right_mix",
|
||||
&right, &num_right, default_right, 2);
|
||||
|
||||
memcpy(pan->left, (num_left == 2) ?
|
||||
left : default_left, sizeof(pan->left));
|
||||
memcpy(pan->right, (num_right == 2) ?
|
||||
right : default_right, sizeof(pan->right));
|
||||
|
||||
config->free(left);
|
||||
config->free(right);
|
||||
|
||||
return pan;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation panning = {
|
||||
panning_init,
|
||||
panning_process,
|
||||
panning_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Panning",
|
||||
"panning",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation panning_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *
|
||||
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &panning;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (phaser.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
#define phaserlfoshape 4.0
|
||||
#define phaserlfoskipsamples 20
|
||||
|
||||
struct phaser_data
|
||||
{
|
||||
float freq;
|
||||
float startphase;
|
||||
float fb;
|
||||
float depth;
|
||||
float drywet;
|
||||
float old[2][24];
|
||||
float gain;
|
||||
float fbout[2];
|
||||
float lfoskip;
|
||||
float phase;
|
||||
|
||||
int stages;
|
||||
unsigned long skipcount;
|
||||
};
|
||||
|
||||
static void phaser_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void phaser_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i, c;
|
||||
int s;
|
||||
float m[2], tmp[2];
|
||||
struct phaser_data *ph = (struct phaser_data*)data;
|
||||
float *out = output->samples;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float in[2] = { out[0], out[1] };
|
||||
|
||||
for (c = 0; c < 2; c++)
|
||||
m[c] = in[c] + ph->fbout[c] * ph->fb * 0.01f;
|
||||
|
||||
if ((ph->skipcount++ % phaserlfoskipsamples) == 0)
|
||||
{
|
||||
ph->gain = 0.5 * (1.0 + cos(ph->skipcount * ph->lfoskip + ph->phase));
|
||||
ph->gain = (exp(ph->gain * phaserlfoshape) - 1.0) / (exp(phaserlfoshape) - 1);
|
||||
ph->gain = 1.0 - ph->gain * ph->depth;
|
||||
}
|
||||
|
||||
for (s = 0; s < ph->stages; s++)
|
||||
{
|
||||
for (c = 0; c < 2; c++)
|
||||
{
|
||||
tmp[c] = ph->old[c][s];
|
||||
ph->old[c][s] = ph->gain * tmp[c] + m[c];
|
||||
m[c] = tmp[c] - ph->gain * ph->old[c][s];
|
||||
}
|
||||
}
|
||||
|
||||
for (c = 0; c < 2; c++)
|
||||
{
|
||||
ph->fbout[c] = m[c];
|
||||
out[c] = m[c] * ph->drywet + in[c] * (1.0f - ph->drywet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *phaser_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float lfo_freq, lfo_start_phase;
|
||||
struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
|
||||
if (!ph)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f);
|
||||
config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f);
|
||||
config->get_float(userdata, "feedback", &ph->fb, 0.0f);
|
||||
config->get_float(userdata, "depth", &ph->depth, 0.4f);
|
||||
config->get_float(userdata, "dry_wet", &ph->drywet, 0.5f);
|
||||
config->get_int(userdata, "stages", &ph->stages, 2);
|
||||
|
||||
if (ph->stages < 1)
|
||||
ph->stages = 1;
|
||||
else if (ph->stages > 24)
|
||||
ph->stages = 24;
|
||||
|
||||
ph->lfoskip = lfo_freq * 2.0 * M_PI / info->input_rate;
|
||||
ph->phase = lfo_start_phase * M_PI / 180.0;
|
||||
|
||||
return ph;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation phaser_plug = {
|
||||
phaser_init,
|
||||
phaser_process,
|
||||
phaser_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Phaser",
|
||||
"phaser",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation phaser_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &phaser_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (reverb.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
struct comb
|
||||
{
|
||||
float *buffer;
|
||||
unsigned bufsize;
|
||||
unsigned bufidx;
|
||||
|
||||
float feedback;
|
||||
float filterstore;
|
||||
float damp1, damp2;
|
||||
};
|
||||
|
||||
struct allpass
|
||||
{
|
||||
float *buffer;
|
||||
float feedback;
|
||||
unsigned bufsize;
|
||||
unsigned bufidx;
|
||||
};
|
||||
|
||||
static INLINE float comb_process(struct comb *c, float input)
|
||||
{
|
||||
float output = c->buffer[c->bufidx];
|
||||
c->filterstore = (output * c->damp2) + (c->filterstore * c->damp1);
|
||||
|
||||
c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);
|
||||
|
||||
c->bufidx++;
|
||||
if (c->bufidx >= c->bufsize)
|
||||
c->bufidx = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
static INLINE float allpass_process(struct allpass *a, float input)
|
||||
{
|
||||
float bufout = a->buffer[a->bufidx];
|
||||
float output = -input + bufout;
|
||||
a->buffer[a->bufidx] = input + bufout * a->feedback;
|
||||
|
||||
a->bufidx++;
|
||||
if (a->bufidx >= a->bufsize)
|
||||
a->bufidx = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#define numcombs 8
|
||||
#define numallpasses 4
|
||||
static const float muted = 0;
|
||||
static const float fixedgain = 0.015f;
|
||||
static const float scalewet = 3;
|
||||
static const float scaledry = 2;
|
||||
static const float scaledamp = 0.4f;
|
||||
static const float scaleroom = 0.28f;
|
||||
static const float offsetroom = 0.7f;
|
||||
static const float initialroom = 0.5f;
|
||||
static const float initialdamp = 0.5f;
|
||||
static const float initialwet = 1.0f / 3.0f;
|
||||
static const float initialdry = 0;
|
||||
static const float initialwidth = 1;
|
||||
static const float initialmode = 0;
|
||||
static const float freezemode = 0.5f;
|
||||
|
||||
struct revmodel
|
||||
{
|
||||
struct comb combL[numcombs];
|
||||
struct allpass allpassL[numallpasses];
|
||||
|
||||
float *bufcomb[numcombs];
|
||||
float *bufallpass[numallpasses];
|
||||
|
||||
float gain;
|
||||
float roomsize, roomsize1;
|
||||
float damp, damp1;
|
||||
float wet, wet1, wet2;
|
||||
float dry;
|
||||
float width;
|
||||
float mode;
|
||||
};
|
||||
|
||||
static float revmodel_process(struct revmodel *rev, float in)
|
||||
{
|
||||
int i;
|
||||
float mono_out = 0.0f;
|
||||
float mono_in = in;
|
||||
float input = mono_in * rev->gain;
|
||||
|
||||
for (i = 0; i < numcombs; i++)
|
||||
mono_out += comb_process(&rev->combL[i], input);
|
||||
|
||||
for (i = 0; i < numallpasses; i++)
|
||||
mono_out = allpass_process(&rev->allpassL[i], mono_out);
|
||||
|
||||
return mono_in * rev->dry + mono_out * rev->wet1;
|
||||
}
|
||||
|
||||
static void revmodel_update(struct revmodel *rev)
|
||||
{
|
||||
int i;
|
||||
rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
|
||||
|
||||
if (rev->mode >= freezemode)
|
||||
{
|
||||
rev->roomsize1 = 1.0f;
|
||||
rev->damp1 = 0.0f;
|
||||
rev->gain = muted;
|
||||
}
|
||||
else
|
||||
{
|
||||
rev->roomsize1 = rev->roomsize;
|
||||
rev->damp1 = rev->damp;
|
||||
rev->gain = fixedgain;
|
||||
}
|
||||
|
||||
for (i = 0; i < numcombs; i++)
|
||||
{
|
||||
rev->combL[i].feedback = rev->roomsize1;
|
||||
rev->combL[i].damp1 = rev->damp1;
|
||||
rev->combL[i].damp2 = 1.0f - rev->damp1;
|
||||
}
|
||||
}
|
||||
|
||||
static void revmodel_setroomsize(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->roomsize = value * scaleroom + offsetroom;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_setdamp(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->damp = value * scaledamp;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_setwet(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->wet = value * scalewet;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_setdry(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->dry = value * scaledry;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_setwidth(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->width = value;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_setmode(struct revmodel *rev, float value)
|
||||
{
|
||||
rev->mode = value;
|
||||
revmodel_update(rev);
|
||||
}
|
||||
|
||||
static void revmodel_init(struct revmodel *rev,int srate)
|
||||
{
|
||||
|
||||
static const int comb_lengths[8] = { 1116,1188,1277,1356,1422,1491,1557,1617 };
|
||||
static const int allpass_lengths[4] = { 225,341,441,556 };
|
||||
double r = srate * (1 / 44100.0);
|
||||
unsigned c;
|
||||
|
||||
for (c = 0; c < numcombs; ++c)
|
||||
{
|
||||
rev->bufcomb[c] = malloc(r*comb_lengths[c]*sizeof(float));
|
||||
rev->combL[c].buffer = rev->bufcomb[c];
|
||||
memset(rev->combL[c].buffer,0,r*comb_lengths[c]*sizeof(float));
|
||||
rev->combL[c].bufsize=r*comb_lengths[c];
|
||||
}
|
||||
|
||||
for (c = 0; c < numallpasses; ++c)
|
||||
{
|
||||
rev->bufallpass[c] = malloc(r*allpass_lengths[c]*sizeof(float));
|
||||
rev->allpassL[c].buffer = rev->bufallpass[c];
|
||||
memset(rev->allpassL[c].buffer,0,r*allpass_lengths[c]*sizeof(float));
|
||||
rev->allpassL[c].bufsize=r*allpass_lengths[c];
|
||||
rev->allpassL[c].feedback = 0.5f;
|
||||
}
|
||||
|
||||
revmodel_setwet(rev, initialwet);
|
||||
revmodel_setroomsize(rev, initialroom);
|
||||
revmodel_setdry(rev, initialdry);
|
||||
revmodel_setdamp(rev, initialdamp);
|
||||
revmodel_setwidth(rev, initialwidth);
|
||||
revmodel_setmode(rev, initialmode);
|
||||
}
|
||||
|
||||
struct reverb_data
|
||||
{
|
||||
struct revmodel left, right;
|
||||
};
|
||||
|
||||
static void reverb_free(void *data)
|
||||
{
|
||||
struct reverb_data *rev = (struct reverb_data*)data;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
free(rev->left.bufcomb[i]);
|
||||
free(rev->right.bufcomb[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
free(rev->left.bufallpass[i]);
|
||||
free(rev->right.bufallpass[i]);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void reverb_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
float *out;
|
||||
struct reverb_data *rev = (struct reverb_data*)data;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
out = output->samples;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float in[2] = { out[0], out[1] };
|
||||
|
||||
out[0] = revmodel_process(&rev->left, in[0]);
|
||||
out[1] = revmodel_process(&rev->right, in[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void *reverb_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float drytime, wettime, damping, roomwidth, roomsize;
|
||||
struct reverb_data *rev = (struct reverb_data*)
|
||||
calloc(1, sizeof(*rev));
|
||||
if (!rev)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "drytime", &drytime, 0.43f);
|
||||
config->get_float(userdata, "wettime", &wettime, 0.4f);
|
||||
config->get_float(userdata, "damping", &damping, 0.8f);
|
||||
config->get_float(userdata, "roomwidth", &roomwidth, 0.56f);
|
||||
config->get_float(userdata, "roomsize", &roomsize, 0.56f);
|
||||
|
||||
revmodel_init(&rev->left,info->input_rate);
|
||||
revmodel_init(&rev->right,info->input_rate);
|
||||
|
||||
revmodel_setdamp(&rev->left, damping);
|
||||
revmodel_setdry(&rev->left, drytime);
|
||||
revmodel_setwet(&rev->left, wettime);
|
||||
revmodel_setwidth(&rev->left, roomwidth);
|
||||
revmodel_setroomsize(&rev->left, roomsize);
|
||||
|
||||
revmodel_setdamp(&rev->right, damping);
|
||||
revmodel_setdry(&rev->right, drytime);
|
||||
revmodel_setwet(&rev->right, wettime);
|
||||
revmodel_setwidth(&rev->right, roomwidth);
|
||||
revmodel_setroomsize(&rev->right, roomsize);
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation reverb_plug = {
|
||||
reverb_init,
|
||||
reverb_process,
|
||||
reverb_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Reverb",
|
||||
"reverb",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation reverb_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &reverb_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (tremolo.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#define sqr(a) ((a) * (a))
|
||||
|
||||
struct tremolo_core
|
||||
{
|
||||
float freq;
|
||||
float depth;
|
||||
float* wavetable;
|
||||
int index;
|
||||
int maxindex;
|
||||
};
|
||||
|
||||
struct tremolo
|
||||
{
|
||||
struct tremolo_core left, right;
|
||||
};
|
||||
|
||||
static void tremolo_free(void *data)
|
||||
{
|
||||
struct tremolo *tre = (struct tremolo*)data;
|
||||
free(tre->left.wavetable);
|
||||
free(tre->right.wavetable);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void tremolocore_init(struct tremolo_core *core,float depth,int samplerate,float freq)
|
||||
{
|
||||
const double offset = 1. - depth / 2.;
|
||||
unsigned i;
|
||||
double env;
|
||||
core->index = 0;
|
||||
core->maxindex = samplerate/freq;
|
||||
core->wavetable = malloc(core->maxindex*sizeof(float));
|
||||
memset(core->wavetable, 0, core->maxindex * sizeof(float));
|
||||
for (i = 0; i < core->maxindex; i++) {
|
||||
env = freq * i / samplerate;
|
||||
env = sin((M_PI*2) * fmod(env + 0.25, 1.0));
|
||||
core->wavetable[i] = env * (1 - fabs(offset)) + offset;
|
||||
}
|
||||
}
|
||||
|
||||
float tremolocore_core(struct tremolo_core *core,float in)
|
||||
{
|
||||
core->index = core->index % core->maxindex;
|
||||
return in * core->wavetable[core->index++];
|
||||
}
|
||||
|
||||
static void tremolo_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
float *out;
|
||||
struct tremolo *tre = (struct tremolo*)data;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
out = output->samples;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float in[2] = { out[0], out[1] };
|
||||
|
||||
out[0] = tremolocore_core(&tre->left, in[0]);
|
||||
out[1] = tremolocore_core(&tre->right, in[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void *tremolo_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float freq, depth;
|
||||
struct tremolo *tre = (struct tremolo*)calloc(1, sizeof(*tre));
|
||||
if (!tre)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "freq", &freq,4.0f);
|
||||
config->get_float(userdata, "depth", &depth, 0.9f);
|
||||
tremolocore_init(&tre->left,depth,info->input_rate,freq);
|
||||
tremolocore_init(&tre->right,depth,info->input_rate,freq);
|
||||
return tre;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation tremolo_plug = {
|
||||
tremolo_init,
|
||||
tremolo_process,
|
||||
tremolo_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Tremolo",
|
||||
"tremolo",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation tremolo_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &tremolo_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (vibrato.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#define sqr(a) ((a) * (a))
|
||||
|
||||
|
||||
const float BASE_DELAY_SEC = 0.002; // 2 ms
|
||||
const float VIBRATO_FREQUENCY_DEFAULT_HZ = 2;
|
||||
const float VIBRATO_FREQUENCY_MAX_HZ = 14;
|
||||
const float VIBRATO_DEPTH_DEFAULT_PERCENT = 50;
|
||||
const int add_delay = 3;
|
||||
|
||||
float hermite_interp(float x, float *y)
|
||||
{
|
||||
float c0, c1, c2, c3;
|
||||
c0 = y[1];
|
||||
c1 = (1.0 / 2.0)*(y[2] - y[0]);
|
||||
c2 = (y[0] - (5.0 / 2.0)*y[1]) + (2.0*y[2] - (1.0 / 2.0)*y[3]);
|
||||
c3 = (1.0 / 2.0)*(y[3] - y[0]) + (3.0 / 2.0)*(y[1] - y[2]);
|
||||
return ((c3*x + c2)*x + c1)*x + c0;
|
||||
}
|
||||
|
||||
struct vibrato_core
|
||||
{
|
||||
float freq;
|
||||
float samplerate;
|
||||
int phase;
|
||||
float depth;
|
||||
float* buffer;
|
||||
int writeindex;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct vibrato
|
||||
{
|
||||
struct vibrato_core left, right;
|
||||
};
|
||||
|
||||
static void vibrato_free(void *data)
|
||||
{
|
||||
struct vibrato *vib = (struct vibrato*)data;
|
||||
free(vib->left.buffer);
|
||||
free(vib->right.buffer);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void vibratocore_init(struct vibrato_core *core,float depth,int samplerate,float freq)
|
||||
{
|
||||
core->size = BASE_DELAY_SEC * samplerate * 2;
|
||||
core->buffer = malloc((core->size + add_delay)*sizeof(float));
|
||||
memset(core->buffer, 0, (core->size + add_delay) * sizeof(float));
|
||||
core->samplerate = samplerate;
|
||||
core->freq = freq;
|
||||
core->depth = depth;
|
||||
core->phase = 0;
|
||||
core->writeindex = 0;
|
||||
}
|
||||
|
||||
float vibratocore_core(struct vibrato_core *core,float in)
|
||||
{
|
||||
float M = core->freq / core->samplerate;
|
||||
int maxphase = core->samplerate / core->freq;
|
||||
float lfo = sin(M * 2. * M_PI * core->phase++);
|
||||
core->phase = core->phase % maxphase;
|
||||
lfo = (lfo + 1) * 1.; // transform from [-1; 1] to [0; 1]
|
||||
int maxdelay = BASE_DELAY_SEC * core->samplerate;
|
||||
float delay = lfo * core->depth * maxdelay;
|
||||
delay += add_delay;
|
||||
float readindex = core->writeindex - 1 - delay;
|
||||
while (readindex < 0)readindex += core->size;
|
||||
while (readindex >= core->size)readindex -= core->size;
|
||||
int ipart = (int)readindex; // integer part of the delay
|
||||
float fpart = readindex - ipart; // fractional part of the delay
|
||||
float value = hermite_interp(fpart, &(core->buffer[ipart]));
|
||||
core->buffer[core->writeindex] = in;
|
||||
if (core->writeindex < add_delay){
|
||||
core->buffer[core->size + core->writeindex] = in;
|
||||
}
|
||||
core->writeindex++;
|
||||
if (core->writeindex == core->size) {
|
||||
core->writeindex = 0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static void vibrato_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
float *out;
|
||||
struct vibrato *vib = (struct vibrato*)data;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
out = output->samples;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float in[2] = { out[0], out[1] };
|
||||
|
||||
out[0] = vibratocore_core(&vib->left, in[0]);
|
||||
out[1] = vibratocore_core(&vib->right, in[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void *vibrato_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
float freq, depth;
|
||||
struct vibrato *vib = (struct vibrato*)calloc(1, sizeof(*vib));
|
||||
if (!vib)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "freq", &freq,5.0f);
|
||||
config->get_float(userdata, "depth", &depth, 0.5f);
|
||||
vibratocore_init(&vib->left,depth,info->input_rate,freq);
|
||||
vibratocore_init(&vib->right,depth,info->input_rate,freq);
|
||||
return vib;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation vibrato_plug = {
|
||||
vibrato_init,
|
||||
vibrato_process,
|
||||
vibrato_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Vibrato",
|
||||
"vibrato",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation vibrato_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &vibrato_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (wahwah.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <libretro_dspfilter.h>
|
||||
|
||||
#define WAHWAH_LFO_SKIP_SAMPLES 30
|
||||
|
||||
struct wahwah_data
|
||||
{
|
||||
float phase;
|
||||
float lfoskip;
|
||||
float b0, b1, b2, a0, a1, a2;
|
||||
float freq, startphase;
|
||||
float depth, freqofs, res;
|
||||
unsigned long skipcount;
|
||||
|
||||
struct
|
||||
{
|
||||
float xn1, xn2, yn1, yn2;
|
||||
} l, r;
|
||||
};
|
||||
|
||||
static void wahwah_free(void *data)
|
||||
{
|
||||
if (data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void wahwah_process(void *data, struct dspfilter_output *output,
|
||||
const struct dspfilter_input *input)
|
||||
{
|
||||
unsigned i;
|
||||
struct wahwah_data *wah = (struct wahwah_data*)data;
|
||||
float *out = output->samples;
|
||||
|
||||
output->samples = input->samples;
|
||||
output->frames = input->frames;
|
||||
|
||||
for (i = 0; i < input->frames; i++, out += 2)
|
||||
{
|
||||
float out_l, out_r;
|
||||
float in[2] = { out[0], out[1] };
|
||||
|
||||
if ((wah->skipcount++ % WAHWAH_LFO_SKIP_SAMPLES) == 0)
|
||||
{
|
||||
float omega, sn, cs, alpha;
|
||||
float frequency = (1.0 + cos(wah->skipcount * wah->lfoskip + wah->phase)) / 2.0;
|
||||
|
||||
frequency = frequency * wah->depth * (1.0 - wah->freqofs) + wah->freqofs;
|
||||
frequency = exp((frequency - 1.0) * 6.0);
|
||||
|
||||
omega = M_PI * frequency;
|
||||
sn = sin(omega);
|
||||
cs = cos(omega);
|
||||
alpha = sn / (2.0 * wah->res);
|
||||
|
||||
wah->b0 = (1.0 - cs) / 2.0;
|
||||
wah->b1 = 1.0 - cs;
|
||||
wah->b2 = (1.0 - cs) / 2.0;
|
||||
wah->a0 = 1.0 + alpha;
|
||||
wah->a1 = -2.0 * cs;
|
||||
wah->a2 = 1.0 - alpha;
|
||||
}
|
||||
|
||||
out_l = (wah->b0 * in[0] + wah->b1 * wah->l.xn1 + wah->b2 * wah->l.xn2 - wah->a1 * wah->l.yn1 - wah->a2 * wah->l.yn2) / wah->a0;
|
||||
out_r = (wah->b0 * in[1] + wah->b1 * wah->r.xn1 + wah->b2 * wah->r.xn2 - wah->a1 * wah->r.yn1 - wah->a2 * wah->r.yn2) / wah->a0;
|
||||
|
||||
wah->l.xn2 = wah->l.xn1;
|
||||
wah->l.xn1 = in[0];
|
||||
wah->l.yn2 = wah->l.yn1;
|
||||
wah->l.yn1 = out_l;
|
||||
|
||||
wah->r.xn2 = wah->r.xn1;
|
||||
wah->r.xn1 = in[1];
|
||||
wah->r.yn2 = wah->r.yn1;
|
||||
wah->r.yn1 = out_r;
|
||||
|
||||
out[0] = out_l;
|
||||
out[1] = out_r;
|
||||
}
|
||||
}
|
||||
|
||||
static void *wahwah_init(const struct dspfilter_info *info,
|
||||
const struct dspfilter_config *config, void *userdata)
|
||||
{
|
||||
struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah));
|
||||
if (!wah)
|
||||
return NULL;
|
||||
|
||||
config->get_float(userdata, "lfo_freq", &wah->freq, 1.5f);
|
||||
config->get_float(userdata, "lfo_start_phase", &wah->startphase, 0.0f);
|
||||
config->get_float(userdata, "freq_offset", &wah->freqofs, 0.3f);
|
||||
config->get_float(userdata, "depth", &wah->depth, 0.7f);
|
||||
config->get_float(userdata, "resonance", &wah->res, 2.5f);
|
||||
|
||||
wah->lfoskip = wah->freq * 2.0 * M_PI / info->input_rate;
|
||||
wah->phase = wah->startphase * M_PI / 180.0;
|
||||
|
||||
return wah;
|
||||
}
|
||||
|
||||
static const struct dspfilter_implementation wahwah_plug = {
|
||||
wahwah_init,
|
||||
wahwah_process,
|
||||
wahwah_free,
|
||||
|
||||
DSPFILTER_API_VERSION,
|
||||
"Wah-Wah",
|
||||
"wahwah",
|
||||
};
|
||||
|
||||
#ifdef HAVE_FILTERS_BUILTIN
|
||||
#define dspfilter_get_implementation wahwah_dspfilter_get_implementation
|
||||
#endif
|
||||
|
||||
const struct dspfilter_implementation *
|
||||
dspfilter_get_implementation(dspfilter_simd_mask_t mask)
|
||||
{
|
||||
(void)mask;
|
||||
return &wahwah_plug;
|
||||
}
|
||||
|
||||
#undef dspfilter_get_implementation
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (audio_resampler.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string/stdstring.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <file/config_file_userdata.h>
|
||||
|
||||
#include <audio/audio_resampler.h>
|
||||
|
||||
static const retro_resampler_t *resampler_drivers[] = {
|
||||
&sinc_resampler,
|
||||
#ifdef HAVE_CC_RESAMPLER
|
||||
&CC_resampler,
|
||||
#endif
|
||||
&nearest_resampler,
|
||||
&null_resampler,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct resampler_config resampler_config = {
|
||||
config_userdata_get_float,
|
||||
config_userdata_get_int,
|
||||
config_userdata_get_float_array,
|
||||
config_userdata_get_int_array,
|
||||
config_userdata_get_string,
|
||||
config_userdata_free,
|
||||
};
|
||||
|
||||
/**
|
||||
* find_resampler_driver_index:
|
||||
* @ident : Identifier of resampler driver to find.
|
||||
*
|
||||
* Finds resampler driver index by @ident name.
|
||||
*
|
||||
* Returns: resampler driver index if resampler driver was found, otherwise
|
||||
* -1.
|
||||
**/
|
||||
static int find_resampler_driver_index(const char *ident)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; resampler_drivers[i]; i++)
|
||||
if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* audio_resampler_driver_find_handle:
|
||||
* @idx : index of driver to get handle to.
|
||||
*
|
||||
* Returns: handle to audio resampler driver at index. Can be NULL
|
||||
* if nothing found.
|
||||
**/
|
||||
const void *audio_resampler_driver_find_handle(int idx)
|
||||
{
|
||||
const void *drv = resampler_drivers[idx];
|
||||
if (!drv)
|
||||
return NULL;
|
||||
return drv;
|
||||
}
|
||||
|
||||
/**
|
||||
* audio_resampler_driver_find_ident:
|
||||
* @idx : index of driver to get handle to.
|
||||
*
|
||||
* Returns: Human-readable identifier of audio resampler driver at index.
|
||||
* Can be NULL if nothing found.
|
||||
**/
|
||||
const char *audio_resampler_driver_find_ident(int idx)
|
||||
{
|
||||
const retro_resampler_t *drv = resampler_drivers[idx];
|
||||
if (!drv)
|
||||
return NULL;
|
||||
return drv->ident;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_resampler_driver:
|
||||
* @ident : Identifier of resampler driver to find.
|
||||
*
|
||||
* Finds resampler by @ident name.
|
||||
*
|
||||
* Returns: resampler driver if resampler driver was found, otherwise
|
||||
* NULL.
|
||||
**/
|
||||
static const retro_resampler_t *find_resampler_driver(const char *ident)
|
||||
{
|
||||
int i = find_resampler_driver_index(ident);
|
||||
|
||||
if (i >= 0)
|
||||
return resampler_drivers[i];
|
||||
|
||||
return resampler_drivers[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* resampler_append_plugs:
|
||||
* @re : Resampler handle
|
||||
* @backend : Resampler backend that is about to be set.
|
||||
* @bw_ratio : Bandwidth ratio.
|
||||
*
|
||||
* Initializes resampler driver based on queried CPU features.
|
||||
*
|
||||
* Returns: true (1) if successfully initialized, otherwise false (0).
|
||||
**/
|
||||
static bool resampler_append_plugs(void **re,
|
||||
const retro_resampler_t **backend,
|
||||
enum resampler_quality quality,
|
||||
double bw_ratio)
|
||||
{
|
||||
resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();
|
||||
|
||||
if (*backend)
|
||||
*re = (*backend)->init(&resampler_config, bw_ratio, quality, mask);
|
||||
|
||||
if (!*re)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* retro_resampler_realloc:
|
||||
* @re : Resampler handle
|
||||
* @backend : Resampler backend that is about to be set.
|
||||
* @ident : Identifier name for resampler we want.
|
||||
* @bw_ratio : Bandwidth ratio.
|
||||
*
|
||||
* Reallocates resampler. Will free previous handle before
|
||||
* allocating a new one. If ident is NULL, first resampler will be used.
|
||||
*
|
||||
* Returns: true (1) if successful, otherwise false (0).
|
||||
**/
|
||||
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
|
||||
const char *ident, enum resampler_quality quality, double bw_ratio)
|
||||
{
|
||||
if (*re && *backend)
|
||||
(*backend)->free(*re);
|
||||
|
||||
*re = NULL;
|
||||
*backend = find_resampler_driver(ident);
|
||||
|
||||
if (!resampler_append_plugs(re, backend, quality, bw_ratio))
|
||||
{
|
||||
if (!*re)
|
||||
*backend = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (nearest_resampler.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <audio/audio_resampler.h>
|
||||
|
||||
typedef struct rarch_nearest_resampler
|
||||
{
|
||||
float fraction;
|
||||
} rarch_nearest_resampler_t;
|
||||
|
||||
static void resampler_nearest_process(
|
||||
void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
|
||||
audio_frame_float_t *inp = (audio_frame_float_t*)data->data_in;
|
||||
audio_frame_float_t *inp_max = (audio_frame_float_t*)inp + data->input_frames;
|
||||
audio_frame_float_t *outp = (audio_frame_float_t*)data->data_out;
|
||||
float ratio = 1.0 / data->ratio;
|
||||
|
||||
while(inp != inp_max)
|
||||
{
|
||||
while(re->fraction > 1)
|
||||
{
|
||||
*outp++ = *inp;
|
||||
re->fraction -= ratio;
|
||||
}
|
||||
re->fraction++;
|
||||
inp++;
|
||||
}
|
||||
|
||||
data->output_frames = (outp - (audio_frame_float_t*)data->data_out);
|
||||
}
|
||||
|
||||
static void resampler_nearest_free(void *re_)
|
||||
{
|
||||
rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
|
||||
if (re)
|
||||
free(re);
|
||||
}
|
||||
|
||||
static void *resampler_nearest_init(const struct resampler_config *config,
|
||||
double bandwidth_mod,
|
||||
enum resampler_quality quality,
|
||||
resampler_simd_mask_t mask)
|
||||
{
|
||||
rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)
|
||||
calloc(1, sizeof(rarch_nearest_resampler_t));
|
||||
|
||||
(void)config;
|
||||
(void)mask;
|
||||
|
||||
if (!re)
|
||||
return NULL;
|
||||
|
||||
re->fraction = 0;
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
retro_resampler_t nearest_resampler = {
|
||||
resampler_nearest_init,
|
||||
resampler_nearest_process,
|
||||
resampler_nearest_free,
|
||||
RESAMPLER_API_VERSION,
|
||||
"nearest",
|
||||
"nearest"
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (null_resampler.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <audio/audio_resampler.h>
|
||||
|
||||
typedef struct rarch_null_resampler
|
||||
{
|
||||
void *empty;
|
||||
} rarch_null_resampler_t;
|
||||
|
||||
static void resampler_null_process(
|
||||
void *re_, struct resampler_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void resampler_null_free(void *re_)
|
||||
{
|
||||
}
|
||||
|
||||
static void *resampler_null_init(const struct resampler_config *config,
|
||||
double bandwidth_mod,
|
||||
enum resampler_quality quality,
|
||||
resampler_simd_mask_t mask)
|
||||
{
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
retro_resampler_t null_resampler = {
|
||||
resampler_null_init,
|
||||
resampler_null_process,
|
||||
resampler_null_free,
|
||||
RESAMPLER_API_VERSION,
|
||||
"null",
|
||||
"null"
|
||||
};
|
||||
@@ -0,0 +1,720 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (sinc_resampler.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Bog-standard windowed SINC implementation. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <filters.h>
|
||||
#include <memalign.h>
|
||||
|
||||
#include <audio/audio_resampler.h>
|
||||
#include <filters.h>
|
||||
|
||||
#ifdef __SSE__
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__AVX__)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
/* Rough SNR values for upsampling:
|
||||
* LOWEST: 40 dB
|
||||
* LOWER: 55 dB
|
||||
* NORMAL: 70 dB
|
||||
* HIGHER: 110 dB
|
||||
* HIGHEST: 140 dB
|
||||
*/
|
||||
|
||||
/* TODO, make all this more configurable. */
|
||||
|
||||
enum sinc_window
|
||||
{
|
||||
SINC_WINDOW_NONE = 0,
|
||||
SINC_WINDOW_KAISER,
|
||||
SINC_WINDOW_LANCZOS
|
||||
};
|
||||
|
||||
/* For the little amount of taps we're using,
|
||||
* SSE1 is faster than AVX for some reason.
|
||||
* AVX code is kept here though as by increasing number
|
||||
* of sinc taps, the AVX code is clearly faster than SSE1.
|
||||
*/
|
||||
|
||||
typedef struct rarch_sinc_resampler
|
||||
{
|
||||
unsigned enable_avx;
|
||||
unsigned phase_bits;
|
||||
unsigned subphase_bits;
|
||||
unsigned subphase_mask;
|
||||
unsigned taps;
|
||||
unsigned ptr;
|
||||
uint32_t time;
|
||||
float subphase_mod;
|
||||
float kaiser_beta;
|
||||
enum sinc_window window_type;
|
||||
|
||||
/* A buffer for phase_table, buffer_l and buffer_r
|
||||
* are created in a single calloc().
|
||||
* Ensure that we get as good cache locality as we can hope for. */
|
||||
float *main_buffer;
|
||||
float *phase_table;
|
||||
float *buffer_l;
|
||||
float *buffer_r;
|
||||
} rarch_sinc_resampler_t;
|
||||
|
||||
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
|
||||
#if TARGET_OS_IPHONE
|
||||
#else
|
||||
#define WANT_NEON
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WANT_NEON
|
||||
/* Assumes that taps >= 8, and that taps is a multiple of 8. */
|
||||
void process_sinc_neon_asm(float *out, const float *left,
|
||||
const float *right, const float *coeff, unsigned taps);
|
||||
|
||||
static void resampler_sinc_process_neon(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
|
||||
unsigned phases = 1 << (resamp->phase_bits + resamp->subphase_bits);
|
||||
|
||||
uint32_t ratio = phases / data->ratio;
|
||||
const float *input = data->data_in;
|
||||
float *output = data->data_out;
|
||||
size_t frames = data->input_frames;
|
||||
size_t out_frames = 0;
|
||||
|
||||
while (frames)
|
||||
{
|
||||
while (frames && resamp->time >= phases)
|
||||
{
|
||||
/* Push in reverse to make filter more obvious. */
|
||||
if (!resamp->ptr)
|
||||
resamp->ptr = resamp->taps;
|
||||
resamp->ptr--;
|
||||
|
||||
resamp->buffer_l[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_l[resamp->ptr] = *input++;
|
||||
|
||||
resamp->buffer_r[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_r[resamp->ptr] = *input++;
|
||||
|
||||
resamp->time -= phases;
|
||||
frames--;
|
||||
}
|
||||
|
||||
while (resamp->time < phases)
|
||||
{
|
||||
const float *buffer_l = resamp->buffer_l + resamp->ptr;
|
||||
const float *buffer_r = resamp->buffer_r + resamp->ptr;
|
||||
unsigned taps = resamp->taps;
|
||||
unsigned phase = resamp->time >> resamp->subphase_bits;
|
||||
const float *phase_table = resamp->phase_table + phase * taps;
|
||||
|
||||
process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
|
||||
|
||||
output += 2;
|
||||
out_frames++;
|
||||
resamp->time += ratio;
|
||||
}
|
||||
}
|
||||
|
||||
data->output_frames = out_frames;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__AVX__)
|
||||
static void resampler_sinc_process_avx(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
|
||||
unsigned phases = 1 << (resamp->phase_bits + resamp->subphase_bits);
|
||||
|
||||
uint32_t ratio = phases / data->ratio;
|
||||
const float *input = data->data_in;
|
||||
float *output = data->data_out;
|
||||
size_t frames = data->input_frames;
|
||||
size_t out_frames = 0;
|
||||
|
||||
while (frames)
|
||||
{
|
||||
while (frames && resamp->time >= phases)
|
||||
{
|
||||
/* Push in reverse to make filter more obvious. */
|
||||
if (!resamp->ptr)
|
||||
resamp->ptr = resamp->taps;
|
||||
resamp->ptr--;
|
||||
|
||||
resamp->buffer_l[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_l[resamp->ptr] = *input++;
|
||||
|
||||
resamp->buffer_r[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_r[resamp->ptr] = *input++;
|
||||
|
||||
resamp->time -= phases;
|
||||
frames--;
|
||||
}
|
||||
|
||||
while (resamp->time < phases)
|
||||
{
|
||||
unsigned i;
|
||||
__m256 delta, sum_l, sum_r;
|
||||
float *delta_table = NULL;
|
||||
float *phase_table = NULL;
|
||||
const float *buffer_l = resamp->buffer_l + resamp->ptr;
|
||||
const float *buffer_r = resamp->buffer_r + resamp->ptr;
|
||||
unsigned taps = resamp->taps;
|
||||
unsigned phase = resamp->time >> resamp->subphase_bits;
|
||||
|
||||
phase_table = resamp->phase_table + phase * taps;
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
{
|
||||
phase_table = resamp->phase_table + phase * taps * 2;
|
||||
delta_table = phase_table + taps;
|
||||
delta = _mm256_set1_ps((float)
|
||||
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
|
||||
}
|
||||
|
||||
sum_l = _mm256_setzero_ps();
|
||||
sum_r = _mm256_setzero_ps();
|
||||
|
||||
for (i = 0; i < taps; i += 8)
|
||||
{
|
||||
__m256 sinc;
|
||||
__m256 buf_l = _mm256_loadu_ps(buffer_l + i);
|
||||
__m256 buf_r = _mm256_loadu_ps(buffer_r + i);
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
{
|
||||
__m256 deltas = _mm256_load_ps(delta_table + i);
|
||||
sinc = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
|
||||
_mm256_mul_ps(deltas, delta));
|
||||
}
|
||||
else
|
||||
{
|
||||
sinc = _mm256_load_ps((const float*)phase_table + i);
|
||||
}
|
||||
|
||||
sum_l = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
|
||||
sum_r = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
|
||||
}
|
||||
|
||||
/* hadd on AVX is weird, and acts on low-lanes
|
||||
* and high-lanes separately. */
|
||||
__m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
|
||||
__m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
|
||||
res_l = _mm256_hadd_ps(res_l, res_l);
|
||||
res_r = _mm256_hadd_ps(res_r, res_r);
|
||||
res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
|
||||
res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
|
||||
|
||||
/* This is optimized to mov %xmmN, [mem].
|
||||
* There doesn't seem to be any _mm256_store_ss intrinsic. */
|
||||
_mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
|
||||
_mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
|
||||
|
||||
output += 2;
|
||||
out_frames++;
|
||||
resamp->time += ratio;
|
||||
}
|
||||
}
|
||||
|
||||
data->output_frames = out_frames;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SSE__)
|
||||
static void resampler_sinc_process_sse(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
|
||||
unsigned phases = 1 << (resamp->phase_bits + resamp->subphase_bits);
|
||||
|
||||
uint32_t ratio = phases / data->ratio;
|
||||
const float *input = data->data_in;
|
||||
float *output = data->data_out;
|
||||
size_t frames = data->input_frames;
|
||||
size_t out_frames = 0;
|
||||
|
||||
while (frames)
|
||||
{
|
||||
while (frames && resamp->time >= phases)
|
||||
{
|
||||
/* Push in reverse to make filter more obvious. */
|
||||
if (!resamp->ptr)
|
||||
resamp->ptr = resamp->taps;
|
||||
resamp->ptr--;
|
||||
|
||||
resamp->buffer_l[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_l[resamp->ptr] = *input++;
|
||||
|
||||
resamp->buffer_r[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_r[resamp->ptr] = *input++;
|
||||
|
||||
resamp->time -= phases;
|
||||
frames--;
|
||||
}
|
||||
|
||||
while (resamp->time < phases)
|
||||
{
|
||||
unsigned i;
|
||||
__m128 sum, sum_l, sum_r, delta;
|
||||
float *phase_table = NULL;
|
||||
float *delta_table = NULL;
|
||||
const float *buffer_l = resamp->buffer_l + resamp->ptr;
|
||||
const float *buffer_r = resamp->buffer_r + resamp->ptr;
|
||||
unsigned taps = resamp->taps;
|
||||
unsigned phase = resamp->time >> resamp->subphase_bits;
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
{
|
||||
phase_table = resamp->phase_table + phase * taps * 2;
|
||||
delta_table = phase_table + taps;
|
||||
delta = _mm_set1_ps((float)
|
||||
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
|
||||
}
|
||||
else
|
||||
{
|
||||
phase_table = resamp->phase_table + phase * taps;
|
||||
}
|
||||
|
||||
sum_l = _mm_setzero_ps();
|
||||
sum_r = _mm_setzero_ps();
|
||||
|
||||
for (i = 0; i < taps; i += 4)
|
||||
{
|
||||
__m128 deltas, _sinc;
|
||||
__m128 buf_l = _mm_loadu_ps(buffer_l + i);
|
||||
__m128 buf_r = _mm_loadu_ps(buffer_r + i);
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
{
|
||||
deltas = _mm_load_ps(delta_table + i);
|
||||
_sinc = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
|
||||
_mm_mul_ps(deltas, delta));
|
||||
}
|
||||
else
|
||||
{
|
||||
_sinc = _mm_load_ps((const float*)phase_table + i);
|
||||
}
|
||||
sum_l = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
|
||||
sum_r = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
|
||||
}
|
||||
|
||||
/* Them annoying shuffles.
|
||||
* sum_l = { l3, l2, l1, l0 }
|
||||
* sum_r = { r3, r2, r1, r0 }
|
||||
*/
|
||||
|
||||
sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
|
||||
_MM_SHUFFLE(1, 0, 1, 0)),
|
||||
_mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
/* sum = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
|
||||
* sum = { R1, R0, L1, L0 }
|
||||
*/
|
||||
|
||||
sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
|
||||
|
||||
/* sum = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
|
||||
* sum = { X, R, X, L }
|
||||
*/
|
||||
|
||||
/* Store L */
|
||||
_mm_store_ss(output + 0, sum);
|
||||
|
||||
/* movehl { X, R, X, L } == { X, R, X, R } */
|
||||
_mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
|
||||
|
||||
output += 2;
|
||||
out_frames++;
|
||||
resamp->time += ratio;
|
||||
}
|
||||
}
|
||||
|
||||
data->output_frames = out_frames;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void resampler_sinc_process_c(void *re_, struct resampler_data *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
|
||||
unsigned phases = 1 << (resamp->phase_bits + resamp->subphase_bits);
|
||||
|
||||
uint32_t ratio = phases / data->ratio;
|
||||
const float *input = data->data_in;
|
||||
float *output = data->data_out;
|
||||
size_t frames = data->input_frames;
|
||||
size_t out_frames = 0;
|
||||
|
||||
while (frames)
|
||||
{
|
||||
while (frames && resamp->time >= phases)
|
||||
{
|
||||
/* Push in reverse to make filter more obvious. */
|
||||
if (!resamp->ptr)
|
||||
resamp->ptr = resamp->taps;
|
||||
resamp->ptr--;
|
||||
|
||||
resamp->buffer_l[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_l[resamp->ptr] = *input++;
|
||||
|
||||
resamp->buffer_r[resamp->ptr + resamp->taps] =
|
||||
resamp->buffer_r[resamp->ptr] = *input++;
|
||||
|
||||
resamp->time -= phases;
|
||||
frames--;
|
||||
}
|
||||
|
||||
while (resamp->time < phases)
|
||||
{
|
||||
unsigned i;
|
||||
float delta = 0.0f;
|
||||
float sum_l = 0.0f;
|
||||
float sum_r = 0.0f;
|
||||
float *phase_table = NULL;
|
||||
float *delta_table = NULL;
|
||||
const float *buffer_l = resamp->buffer_l + resamp->ptr;
|
||||
const float *buffer_r = resamp->buffer_r + resamp->ptr;
|
||||
unsigned taps = resamp->taps;
|
||||
unsigned phase = resamp->time >> resamp->subphase_bits;
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
{
|
||||
phase_table = resamp->phase_table + phase * taps * 2;
|
||||
delta_table = phase_table + taps;
|
||||
delta = (float)
|
||||
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
phase_table = resamp->phase_table + phase * taps;
|
||||
}
|
||||
|
||||
for (i = 0; i < taps; i++)
|
||||
{
|
||||
float sinc_val = phase_table[i];
|
||||
|
||||
if (resamp->window_type == SINC_WINDOW_KAISER)
|
||||
sinc_val = sinc_val + delta_table[i] * delta;
|
||||
|
||||
sum_l += buffer_l[i] * sinc_val;
|
||||
sum_r += buffer_r[i] * sinc_val;
|
||||
}
|
||||
|
||||
output[0] = sum_l;
|
||||
output[1] = sum_r;
|
||||
|
||||
output += 2;
|
||||
out_frames++;
|
||||
resamp->time += ratio;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data->output_frames = out_frames;
|
||||
}
|
||||
|
||||
static void resampler_sinc_free(void *data)
|
||||
{
|
||||
rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data;
|
||||
if (resamp)
|
||||
memalign_free(resamp->main_buffer);
|
||||
free(resamp);
|
||||
}
|
||||
|
||||
static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,
|
||||
double cutoff,
|
||||
float *phase_table, int phases, int taps, bool calculate_delta)
|
||||
{
|
||||
int i, j;
|
||||
double window_mod = kaiser_window_function(0.0, resamp->kaiser_beta); /* Need to normalize w(0) to 1.0. */
|
||||
int stride = calculate_delta ? 2 : 1;
|
||||
double sidelobes = taps / 2.0;
|
||||
|
||||
for (i = 0; i < phases; i++)
|
||||
{
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
double sinc_phase;
|
||||
float val;
|
||||
int n = j * phases + i;
|
||||
double window_phase = (double)n / (phases * taps); /* [0, 1). */
|
||||
window_phase = 2.0 * window_phase - 1.0; /* [-1, 1) */
|
||||
sinc_phase = sidelobes * window_phase;
|
||||
val = cutoff * sinc(M_PI * sinc_phase * cutoff) *
|
||||
kaiser_window_function(window_phase, resamp->kaiser_beta) / window_mod;
|
||||
phase_table[i * stride * taps + j] = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (calculate_delta)
|
||||
{
|
||||
int phase;
|
||||
int p;
|
||||
|
||||
for (p = 0; p < phases - 1; p++)
|
||||
{
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
float delta = phase_table[(p + 1) * stride * taps + j] -
|
||||
phase_table[p * stride * taps + j];
|
||||
phase_table[(p * stride + 1) * taps + j] = delta;
|
||||
}
|
||||
}
|
||||
|
||||
phase = phases - 1;
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
float val, delta;
|
||||
double sinc_phase;
|
||||
int n = j * phases + (phase + 1);
|
||||
double window_phase = (double)n / (phases * taps); /* (0, 1]. */
|
||||
window_phase = 2.0 * window_phase - 1.0; /* (-1, 1] */
|
||||
sinc_phase = sidelobes * window_phase;
|
||||
|
||||
val = cutoff * sinc(M_PI * sinc_phase * cutoff) *
|
||||
kaiser_window_function(window_phase, resamp->kaiser_beta) / window_mod;
|
||||
delta = (val - phase_table[phase * stride * taps + j]);
|
||||
phase_table[(phase * stride + 1) * taps + j] = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sinc_init_table_lanczos(rarch_sinc_resampler_t *resamp, double cutoff,
|
||||
float *phase_table, int phases, int taps, bool calculate_delta)
|
||||
{
|
||||
int i, j;
|
||||
double window_mod = lanzcos_window_function(0.0); /* Need to normalize w(0) to 1.0. */
|
||||
int stride = calculate_delta ? 2 : 1;
|
||||
double sidelobes = taps / 2.0;
|
||||
|
||||
for (i = 0; i < phases; i++)
|
||||
{
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
double sinc_phase;
|
||||
float val;
|
||||
int n = j * phases + i;
|
||||
double window_phase = (double)n / (phases * taps); /* [0, 1). */
|
||||
window_phase = 2.0 * window_phase - 1.0; /* [-1, 1) */
|
||||
sinc_phase = sidelobes * window_phase;
|
||||
val = cutoff * sinc(M_PI * sinc_phase * cutoff) *
|
||||
lanzcos_window_function(window_phase) / window_mod;
|
||||
phase_table[i * stride * taps + j] = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (calculate_delta)
|
||||
{
|
||||
int phase;
|
||||
int p;
|
||||
|
||||
for (p = 0; p < phases - 1; p++)
|
||||
{
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
float delta = phase_table[(p + 1) * stride * taps + j] -
|
||||
phase_table[p * stride * taps + j];
|
||||
phase_table[(p * stride + 1) * taps + j] = delta;
|
||||
}
|
||||
}
|
||||
|
||||
phase = phases - 1;
|
||||
for (j = 0; j < taps; j++)
|
||||
{
|
||||
float val, delta;
|
||||
double sinc_phase;
|
||||
int n = j * phases + (phase + 1);
|
||||
double window_phase = (double)n / (phases * taps); /* (0, 1]. */
|
||||
window_phase = 2.0 * window_phase - 1.0; /* (-1, 1] */
|
||||
sinc_phase = sidelobes * window_phase;
|
||||
|
||||
val = cutoff * sinc(M_PI * sinc_phase * cutoff) *
|
||||
lanzcos_window_function(window_phase) / window_mod;
|
||||
delta = (val - phase_table[phase * stride * taps + j]);
|
||||
phase_table[(phase * stride + 1) * taps + j] = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *resampler_sinc_new(const struct resampler_config *config,
|
||||
double bandwidth_mod, enum resampler_quality quality,
|
||||
resampler_simd_mask_t mask)
|
||||
{
|
||||
double cutoff = 0.0;
|
||||
size_t phase_elems = 0;
|
||||
size_t elems = 0;
|
||||
unsigned sidelobes = 0;
|
||||
rarch_sinc_resampler_t *re = (rarch_sinc_resampler_t*)
|
||||
calloc(1, sizeof(*re));
|
||||
|
||||
if (!re)
|
||||
return NULL;
|
||||
|
||||
re->window_type = SINC_WINDOW_NONE;
|
||||
|
||||
switch (quality)
|
||||
{
|
||||
case RESAMPLER_QUALITY_LOWEST:
|
||||
cutoff = 0.98;
|
||||
sidelobes = 2;
|
||||
re->phase_bits = 12;
|
||||
re->subphase_bits = 10;
|
||||
re->window_type = SINC_WINDOW_LANCZOS;
|
||||
re->enable_avx = 0;
|
||||
break;
|
||||
case RESAMPLER_QUALITY_LOWER:
|
||||
cutoff = 0.98;
|
||||
sidelobes = 4;
|
||||
re->phase_bits = 12;
|
||||
re->subphase_bits = 10;
|
||||
re->window_type = SINC_WINDOW_LANCZOS;
|
||||
re->enable_avx = 0;
|
||||
break;
|
||||
case RESAMPLER_QUALITY_HIGHER:
|
||||
cutoff = 0.90;
|
||||
sidelobes = 32;
|
||||
re->phase_bits = 10;
|
||||
re->subphase_bits = 14;
|
||||
re->window_type = SINC_WINDOW_KAISER;
|
||||
re->kaiser_beta = 10.5;
|
||||
re->enable_avx = 1;
|
||||
break;
|
||||
case RESAMPLER_QUALITY_HIGHEST:
|
||||
cutoff = 0.962;
|
||||
sidelobes = 128;
|
||||
re->phase_bits = 10;
|
||||
re->subphase_bits = 14;
|
||||
re->window_type = SINC_WINDOW_KAISER;
|
||||
re->kaiser_beta = 14.5;
|
||||
re->enable_avx = 1;
|
||||
break;
|
||||
case RESAMPLER_QUALITY_NORMAL:
|
||||
case RESAMPLER_QUALITY_DONTCARE:
|
||||
cutoff = 0.825;
|
||||
sidelobes = 8;
|
||||
re->phase_bits = 8;
|
||||
re->subphase_bits = 16;
|
||||
re->window_type = SINC_WINDOW_KAISER;
|
||||
re->kaiser_beta = 5.5;
|
||||
re->enable_avx = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
re->subphase_mask = (1 << re->subphase_bits) - 1;
|
||||
re->subphase_mod = 1.0f / (1 << re->subphase_bits);
|
||||
re->taps = sidelobes * 2;
|
||||
|
||||
/* Downsampling, must lower cutoff, and extend number of
|
||||
* taps accordingly to keep same stopband attenuation. */
|
||||
if (bandwidth_mod < 1.0)
|
||||
{
|
||||
cutoff *= bandwidth_mod;
|
||||
re->taps = (unsigned)ceil(re->taps / bandwidth_mod);
|
||||
}
|
||||
|
||||
/* Be SIMD-friendly. */
|
||||
#if defined(__AVX__)
|
||||
if (re->enable_avx)
|
||||
re->taps = (re->taps + 7) & ~7;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(WANT_NEON)
|
||||
re->taps = (re->taps + 7) & ~7;
|
||||
#else
|
||||
re->taps = (re->taps + 3) & ~3;
|
||||
#endif
|
||||
}
|
||||
|
||||
phase_elems = ((1 << re->phase_bits) * re->taps);
|
||||
if (re->window_type == SINC_WINDOW_KAISER)
|
||||
phase_elems = phase_elems * 2;
|
||||
elems = phase_elems + 4 * re->taps;
|
||||
|
||||
re->main_buffer = (float*)memalign_alloc(128, sizeof(float) * elems);
|
||||
if (!re->main_buffer)
|
||||
goto error;
|
||||
|
||||
re->phase_table = re->main_buffer;
|
||||
re->buffer_l = re->main_buffer + phase_elems;
|
||||
re->buffer_r = re->buffer_l + 2 * re->taps;
|
||||
|
||||
switch (re->window_type)
|
||||
{
|
||||
case SINC_WINDOW_LANCZOS:
|
||||
sinc_init_table_lanczos(re, cutoff, re->phase_table,
|
||||
1 << re->phase_bits, re->taps, false);
|
||||
break;
|
||||
case SINC_WINDOW_KAISER:
|
||||
sinc_init_table_kaiser(re, cutoff, re->phase_table,
|
||||
1 << re->phase_bits, re->taps, true);
|
||||
break;
|
||||
case SINC_WINDOW_NONE:
|
||||
goto error;
|
||||
}
|
||||
|
||||
sinc_resampler.process = resampler_sinc_process_c;
|
||||
|
||||
if (mask & RESAMPLER_SIMD_AVX && re->enable_avx)
|
||||
{
|
||||
#if defined(__AVX__)
|
||||
sinc_resampler.process = resampler_sinc_process_avx;
|
||||
#endif
|
||||
}
|
||||
else if (mask & RESAMPLER_SIMD_SSE)
|
||||
{
|
||||
#if defined(__SSE__)
|
||||
sinc_resampler.process = resampler_sinc_process_sse;
|
||||
#endif
|
||||
}
|
||||
else if (mask & RESAMPLER_SIMD_NEON && re->window_type != SINC_WINDOW_KAISER)
|
||||
{
|
||||
#if defined(WANT_NEON)
|
||||
sinc_resampler.process = resampler_sinc_process_neon;
|
||||
#endif
|
||||
}
|
||||
|
||||
return re;
|
||||
|
||||
error:
|
||||
resampler_sinc_free(re);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retro_resampler_t sinc_resampler = {
|
||||
resampler_sinc_new,
|
||||
resampler_sinc_process_c,
|
||||
resampler_sinc_free,
|
||||
RESAMPLER_API_VERSION,
|
||||
"sinc",
|
||||
"sinc"
|
||||
};
|
||||
|
||||
#undef WANT_NEON
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (sinc_resampler_neon.S).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__ARM_NEON__)
|
||||
|
||||
#ifndef __MACH__
|
||||
.arm
|
||||
#endif
|
||||
.align 4
|
||||
.globl process_sinc_neon_asm
|
||||
#ifndef __MACH__
|
||||
.type process_sinc_neon_asm, %function
|
||||
#endif
|
||||
.globl _process_sinc_neon_asm
|
||||
#ifndef __MACH__
|
||||
.type _process_sinc_neon_asm, %function
|
||||
#endif
|
||||
# void process_sinc_neon(float *out, const float *left, const float *right, const float *coeff, unsigned taps)
|
||||
# Assumes taps is >= 8, and a multiple of 8.
|
||||
process_sinc_neon_asm:
|
||||
_process_sinc_neon_asm:
|
||||
|
||||
push {r4, lr}
|
||||
vmov.f32 q0, #0.0
|
||||
vmov.f32 q8, #0.0
|
||||
|
||||
# Taps argument (r4) goes on stack in armeabi.
|
||||
ldr r4, [sp, #8]
|
||||
|
||||
1:
|
||||
# Left
|
||||
vld1.f32 {q2-q3}, [r1]!
|
||||
# Right
|
||||
vld1.f32 {q10-q11}, [r2]!
|
||||
# Coeff
|
||||
vld1.f32 {q12-q13}, [r3, :128]!
|
||||
|
||||
# Left / Right
|
||||
vmla.f32 q0, q2, q12
|
||||
vmla.f32 q8, q10, q12
|
||||
vmla.f32 q0, q3, q13
|
||||
vmla.f32 q8, q11, q13
|
||||
|
||||
subs r4, r4, #8
|
||||
bne 1b
|
||||
|
||||
# Add everything together
|
||||
vadd.f32 d0, d0, d1
|
||||
vadd.f32 d16, d16, d17
|
||||
vpadd.f32 d0, d0, d16
|
||||
vst1.f32 d0, [r0]
|
||||
|
||||
pop {r4, pc}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,159 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_fnmatch.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if __TEST_FNMATCH__
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#include <compat/fnmatch.h>
|
||||
|
||||
/* Implemnentation of fnmatch(3) so it can be
|
||||
* distributed to non *nix platforms.
|
||||
*
|
||||
* No flags are implemented ATM.
|
||||
* We don't use them. Add flags as needed. */
|
||||
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
int rv;
|
||||
const char *c = NULL;
|
||||
int charmatch = 0;
|
||||
|
||||
for (c = pattern; *c != '\0'; c++)
|
||||
{
|
||||
/* String ended before pattern */
|
||||
if ((*c != '*') && (*string == '\0'))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
switch (*c)
|
||||
{
|
||||
/* Match any number of unknown chars */
|
||||
case '*':
|
||||
/* Find next node in the pattern
|
||||
* ignoring multiple asterixes
|
||||
*/
|
||||
do {
|
||||
c++;
|
||||
if (*c == '\0')
|
||||
return 0;
|
||||
} while (*c == '*');
|
||||
|
||||
/* Match the remaining pattern
|
||||
* ignoring more and more characters. */
|
||||
do {
|
||||
/* We reached the end of the string without a
|
||||
* match. There is a way to optimize this by
|
||||
* calculating the minimum chars needed to
|
||||
* match the remaining pattern but I don't
|
||||
* think it is worth the work ATM.
|
||||
*/
|
||||
if (*string == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
rv = rl_fnmatch(c, string, flags);
|
||||
string++;
|
||||
} while (rv != 0);
|
||||
|
||||
return 0;
|
||||
/* Match char from list */
|
||||
case '[':
|
||||
charmatch = 0;
|
||||
for (c++; *c != ']'; c++)
|
||||
{
|
||||
/* Bad format */
|
||||
if (*c == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* Match already found */
|
||||
if (charmatch)
|
||||
continue;
|
||||
|
||||
if (*c == *string)
|
||||
charmatch = 1;
|
||||
}
|
||||
|
||||
/* No match in list */
|
||||
if (!charmatch)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
string++;
|
||||
break;
|
||||
/* Has any character */
|
||||
case '?':
|
||||
string++;
|
||||
break;
|
||||
/* Match following character verbatim */
|
||||
case '\\':
|
||||
c++;
|
||||
/* Dangling escape at end of pattern.
|
||||
* FIXME: Was c == '\0' (makes no sense).
|
||||
* Not sure if c == NULL or *c == '\0'
|
||||
* is intended. Assuming *c due to c++ right before. */
|
||||
if (*c == '\0')
|
||||
return FNM_NOMATCH;
|
||||
default:
|
||||
if (*c != *string)
|
||||
return FNM_NOMATCH;
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
/* End of string and end of pattend */
|
||||
if (*string == '\0')
|
||||
return 0;
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
#if __TEST_FNMATCH__
|
||||
int main(void)
|
||||
{
|
||||
assert(rl_fnmatch("TEST", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
|
||||
assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
|
||||
assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
|
||||
assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
|
||||
assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
|
||||
assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
|
||||
assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
|
||||
assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_getopt.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <boolean.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <compat/getopt.h>
|
||||
#include <compat/strl.h>
|
||||
#include <compat/strcasestr.h>
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
#include <retro_assert.h>
|
||||
|
||||
char *optarg;
|
||||
int optind, opterr, optopt;
|
||||
|
||||
static bool is_short_option(const char *str)
|
||||
{
|
||||
return str[0] == '-' && str[1] != '-';
|
||||
}
|
||||
|
||||
static bool is_long_option(const char *str)
|
||||
{
|
||||
return str[0] == '-' && str[1] == '-';
|
||||
}
|
||||
|
||||
static int find_short_index(char * const *argv)
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0; argv[idx]; idx++)
|
||||
{
|
||||
if (is_short_option(argv[idx]))
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_long_index(char * const *argv)
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0; argv[idx]; idx++)
|
||||
{
|
||||
if (is_long_option(argv[idx]))
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_short(const char *optstring, char * const *argv)
|
||||
{
|
||||
bool extra_opt, takes_arg, embedded_arg;
|
||||
const char *opt = NULL;
|
||||
char arg = argv[0][1];
|
||||
|
||||
if (arg == ':')
|
||||
return '?';
|
||||
|
||||
opt = strchr(optstring, arg);
|
||||
if (!opt)
|
||||
return '?';
|
||||
|
||||
extra_opt = argv[0][2];
|
||||
takes_arg = opt[1] == ':';
|
||||
|
||||
/* If we take an argument, and we see additional characters,
|
||||
* this is in fact the argument (i.e. -cfoo is same as -c foo). */
|
||||
embedded_arg = extra_opt && takes_arg;
|
||||
|
||||
if (takes_arg)
|
||||
{
|
||||
if (embedded_arg)
|
||||
{
|
||||
optarg = argv[0] + 2;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
optarg = argv[1];
|
||||
optind += 2;
|
||||
}
|
||||
|
||||
return optarg ? opt[0] : '?';
|
||||
}
|
||||
|
||||
if (embedded_arg)
|
||||
{
|
||||
/* If we see additional characters,
|
||||
* and they don't take arguments, this
|
||||
* means we have multiple flags in one. */
|
||||
memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);
|
||||
return opt[0];
|
||||
}
|
||||
|
||||
optind++;
|
||||
return opt[0];
|
||||
}
|
||||
|
||||
static int parse_long(const struct option *longopts, char * const *argv)
|
||||
{
|
||||
size_t indice;
|
||||
const struct option *opt = NULL;
|
||||
for (indice = 0; longopts[indice].name; indice++)
|
||||
{
|
||||
if (!strcmp(longopts[indice].name, &argv[0][2]))
|
||||
{
|
||||
opt = &longopts[indice];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt)
|
||||
return '?';
|
||||
|
||||
/* getopt_long has an "optional" arg, but we don't bother with that. */
|
||||
if (opt->has_arg && !argv[1])
|
||||
return '?';
|
||||
|
||||
if (opt->has_arg)
|
||||
{
|
||||
optarg = argv[1];
|
||||
optind += 2;
|
||||
}
|
||||
else
|
||||
optind++;
|
||||
|
||||
if (opt->flag)
|
||||
{
|
||||
*opt->flag = opt->val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return opt->val;
|
||||
}
|
||||
|
||||
static void shuffle_block(char **begin, char **last, char **end)
|
||||
{
|
||||
ptrdiff_t len = last - begin;
|
||||
const char **tmp = (const char**)calloc(len, sizeof(const char*));
|
||||
|
||||
retro_assert(tmp);
|
||||
|
||||
memcpy((void*)tmp, begin, len * sizeof(const char*));
|
||||
memmove(begin, last, (end - last) * sizeof(const char*));
|
||||
memcpy(end - len, tmp, len * sizeof(const char*));
|
||||
|
||||
free((void*)tmp);
|
||||
}
|
||||
|
||||
int getopt_long(int argc, char *argv[],
|
||||
const char *optstring, const struct option *longopts, int *longindex)
|
||||
{
|
||||
int short_index, long_index;
|
||||
|
||||
(void)longindex;
|
||||
|
||||
if (optind == 0)
|
||||
optind = 1;
|
||||
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
|
||||
short_index = find_short_index(&argv[optind]);
|
||||
long_index = find_long_index(&argv[optind]);
|
||||
|
||||
/* We're done here. */
|
||||
if (short_index == -1 && long_index == -1)
|
||||
return -1;
|
||||
|
||||
/* Reorder argv so that non-options come last.
|
||||
* Non-POSIXy, but that's what getopt does by default. */
|
||||
if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))
|
||||
{
|
||||
shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);
|
||||
short_index = 0;
|
||||
}
|
||||
else if ((long_index > 0) && ((long_index < short_index)
|
||||
|| (short_index == -1)))
|
||||
{
|
||||
shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);
|
||||
long_index = 0;
|
||||
}
|
||||
|
||||
retro_assert(short_index == 0 || long_index == 0);
|
||||
|
||||
if (short_index == 0)
|
||||
return parse_short(optstring, &argv[optind]);
|
||||
if (long_index == 0)
|
||||
return parse_long(longopts, &argv[optind]);
|
||||
|
||||
return '?';
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
Copyright (c) 2013, Kenneth MacKay
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <compat/ifaddrs.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
struct NetlinkList *m_next;
|
||||
struct nlmsghdr *m_data;
|
||||
unsigned int m_size;
|
||||
} NetlinkList;
|
||||
|
||||
static int netlink_socket(void)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
if(l_socket < 0)
|
||||
return -1;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return l_socket;
|
||||
}
|
||||
|
||||
static int netlink_send(int p_socket, int p_request)
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct nlmsghdr m_hdr;
|
||||
struct rtgenmsg m_msg;
|
||||
} l_data;
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
memset(&l_data, 0, sizeof(l_data));
|
||||
|
||||
l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
|
||||
l_data.m_hdr.nlmsg_type = p_request;
|
||||
l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
l_data.m_hdr.nlmsg_pid = 0;
|
||||
l_data.m_hdr.nlmsg_seq = p_socket;
|
||||
l_data.m_msg.rtgen_family = AF_UNSPEC;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
|
||||
}
|
||||
|
||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
|
||||
{
|
||||
struct msghdr l_msg;
|
||||
struct iovec l_iov = { p_buffer, p_len };
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
l_msg.msg_name = (void *)&l_addr;
|
||||
l_msg.msg_namelen = sizeof(l_addr);
|
||||
l_msg.msg_iov = &l_iov;
|
||||
l_msg.msg_iovlen = 1;
|
||||
l_msg.msg_control = NULL;
|
||||
l_msg.msg_controllen = 0;
|
||||
l_msg.msg_flags = 0;
|
||||
int l_result = recvmsg(p_socket, &l_msg, 0);
|
||||
|
||||
if(l_result < 0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
|
||||
return -1;
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
|
||||
{
|
||||
size_t l_size = 4096;
|
||||
void *l_buffer = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
free(l_buffer);
|
||||
l_buffer = malloc(l_size);
|
||||
if (l_buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
int l_read = netlink_recv(p_socket, l_buffer, l_size);
|
||||
*p_size = l_read;
|
||||
|
||||
if(l_read == -2)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(l_read >= 0)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
*p_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return l_buffer;
|
||||
}
|
||||
|
||||
l_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
|
||||
{
|
||||
NetlinkList *l_item = malloc(sizeof(NetlinkList));
|
||||
if (l_item == NULL)
|
||||
return NULL;
|
||||
|
||||
l_item->m_next = NULL;
|
||||
l_item->m_data = p_data;
|
||||
l_item->m_size = p_size;
|
||||
return l_item;
|
||||
}
|
||||
|
||||
static void freeResultList(NetlinkList *p_list)
|
||||
{
|
||||
NetlinkList *l_cur;
|
||||
while(p_list)
|
||||
{
|
||||
l_cur = p_list;
|
||||
p_list = p_list->m_next;
|
||||
free(l_cur->m_data);
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *getResultList(int p_socket, int p_request)
|
||||
{
|
||||
if(netlink_send(p_socket, p_request) < 0)
|
||||
return NULL;
|
||||
|
||||
NetlinkList *l_list = NULL;
|
||||
NetlinkList *l_end = NULL;
|
||||
int l_size;
|
||||
int l_done = 0;
|
||||
while(!l_done)
|
||||
{
|
||||
NetlinkList *l_item = NULL;
|
||||
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
|
||||
if(!l_hdr)
|
||||
goto error;
|
||||
|
||||
l_item = newListItem(l_hdr, l_size);
|
||||
if (!l_item)
|
||||
goto error;
|
||||
|
||||
if(!l_list)
|
||||
l_list = l_item;
|
||||
else
|
||||
l_end->m_next = l_item;
|
||||
l_end = l_item;
|
||||
}
|
||||
|
||||
return l_list;
|
||||
|
||||
error:
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t maxSize(size_t a, size_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_PACKET:
|
||||
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
|
||||
}
|
||||
|
||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_PACKET:
|
||||
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
|
||||
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
|
||||
break;
|
||||
default:
|
||||
memcpy(p_dest->sa_data, p_data, p_size);
|
||||
break;
|
||||
}
|
||||
p_dest->sa_family = p_family;
|
||||
}
|
||||
|
||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
|
||||
{
|
||||
if(!*p_resultList)
|
||||
*p_resultList = p_entry;
|
||||
else
|
||||
{
|
||||
struct ifaddrs *l_cur = *p_resultList;
|
||||
while(l_cur->ifa_next)
|
||||
l_cur = l_cur->ifa_next;
|
||||
l_cur->ifa_next = p_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifaddrs *l_entry = NULL;
|
||||
struct rtattr *l_rta = NULL;
|
||||
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
size_t l_dataSize = 0;
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
l_dataSize += NLMSG_ALIGN(l_rtaSize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
|
||||
if (l_entry == NULL)
|
||||
return -1;
|
||||
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = "";
|
||||
|
||||
char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_name = l_index + sizeof(int);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
char *l_data = l_addr + l_addrSize;
|
||||
|
||||
// save the interface index so we can look it up when handling the addresses.
|
||||
memcpy(l_index, &l_info->ifi_index, sizeof(int));
|
||||
|
||||
l_entry->ifa_flags = l_info->ifi_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
|
||||
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
|
||||
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
|
||||
if(l_rta->rta_type == IFLA_ADDRESS)
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
else
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFLA_IFNAME:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
memcpy(l_data, l_rtaData, l_rtaDataSize);
|
||||
l_entry->ifa_data = l_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
|
||||
{
|
||||
int l_num = 0;
|
||||
struct ifaddrs *l_cur = *p_links;
|
||||
while(l_cur && l_num < p_numLinks)
|
||||
{
|
||||
int l_index;
|
||||
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
|
||||
|
||||
memcpy(&l_index, l_indexPtr, sizeof(int));
|
||||
if(l_index == p_index)
|
||||
return l_cur;
|
||||
|
||||
l_cur = l_cur->ifa_next;
|
||||
++l_num;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
int l_addedNetmask = 0;
|
||||
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
|
||||
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
|
||||
|
||||
if(l_info->ifa_family == AF_PACKET)
|
||||
return 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
struct rtattr *l_rta;
|
||||
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{
|
||||
/* make room for netmask */
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
|
||||
if (l_entry == NULL)
|
||||
return -1;
|
||||
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
|
||||
|
||||
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifa_flags;
|
||||
if(l_interface)
|
||||
l_entry->ifa_flags |= l_interface->ifa_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_BROADCAST:
|
||||
case IFA_LOCAL:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
|
||||
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
if(l_info->ifa_family == AF_INET6)
|
||||
{
|
||||
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
|
||||
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
|
||||
}
|
||||
|
||||
if(l_rta->rta_type == IFA_ADDRESS)
|
||||
{
|
||||
/* apparently in a point-to-point network IFA_ADDRESS
|
||||
* contains the dest address and IFA_LOCAL contains the local address */
|
||||
if(l_entry->ifa_addr)
|
||||
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
|
||||
else
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else if(l_rta->rta_type == IFA_LOCAL)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
l_entry->ifa_dstaddr = l_entry->ifa_addr;
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFA_LABEL:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_entry->ifa_addr &&
|
||||
( l_entry->ifa_addr->sa_family == AF_INET
|
||||
|| l_entry->ifa_addr->sa_family == AF_INET6))
|
||||
{
|
||||
unsigned i;
|
||||
char l_mask[16];
|
||||
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET
|
||||
? 32 : 128);
|
||||
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix
|
||||
? l_maxPrefix : l_info->ifa_prefixlen);
|
||||
|
||||
l_mask[0] = '\0';
|
||||
|
||||
for(i=0; i<(l_prefix/8); ++i)
|
||||
l_mask[i] = 0xff;
|
||||
if(l_prefix % 8)
|
||||
l_mask[i] = 0xff << (8 - (l_prefix % 8));
|
||||
|
||||
makeSockaddr(l_entry->ifa_addr->sa_family,
|
||||
(struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
|
||||
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
|
||||
struct ifaddrs **p_resultList)
|
||||
{
|
||||
int l_numLinks = 0;
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
struct nlmsghdr *l_hdr = NULL;
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
if(interpretLink(l_hdr, p_resultList) == -1)
|
||||
return -1;
|
||||
++l_numLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_numLinks;
|
||||
}
|
||||
|
||||
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
|
||||
struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
struct nlmsghdr *l_hdr = NULL;
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int l_socket = 0;
|
||||
int l_result = 0;
|
||||
if(!ifap)
|
||||
return -1;
|
||||
*ifap = NULL;
|
||||
|
||||
l_socket = netlink_socket();
|
||||
if(l_socket < 0)
|
||||
return -1;
|
||||
|
||||
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
|
||||
if(!l_linkResults)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
|
||||
if(!l_addrResults)
|
||||
{
|
||||
close(l_socket);
|
||||
freeResultList(l_linkResults);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
|
||||
|
||||
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
|
||||
l_result = -1;
|
||||
|
||||
freeResultList(l_linkResults);
|
||||
freeResultList(l_addrResults);
|
||||
close(l_socket);
|
||||
return l_result;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
struct ifaddrs *l_cur = NULL;
|
||||
|
||||
while(ifa)
|
||||
{
|
||||
l_cur = ifa;
|
||||
ifa = ifa->ifa_next;
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_posix_string.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#undef strcasecmp
|
||||
#undef strdup
|
||||
#undef isblank
|
||||
#undef strtok_r
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int retro_strcasecmp__(const char *a, const char *b)
|
||||
{
|
||||
while (*a && *b)
|
||||
{
|
||||
int a_ = tolower(*a);
|
||||
int b_ = tolower(*b);
|
||||
|
||||
if (a_ != b_)
|
||||
return a_ - b_;
|
||||
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return tolower(*a) - tolower(*b);
|
||||
}
|
||||
|
||||
char *retro_strdup__(const char *orig)
|
||||
{
|
||||
size_t len = strlen(orig) + 1;
|
||||
char *ret = (char*)malloc(len);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
strlcpy(ret, orig, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int retro_isblank__(int c)
|
||||
{
|
||||
return (c == ' ') || (c == '\t');
|
||||
}
|
||||
|
||||
char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
|
||||
{
|
||||
char *first = NULL;
|
||||
if (!saveptr || !delim)
|
||||
return NULL;
|
||||
|
||||
if (str)
|
||||
*saveptr = str;
|
||||
|
||||
do
|
||||
{
|
||||
char *ptr = NULL;
|
||||
first = *saveptr;
|
||||
while (*first && strchr(delim, *first))
|
||||
*first++ = '\0';
|
||||
|
||||
if (*first == '\0')
|
||||
return NULL;
|
||||
|
||||
ptr = first + 1;
|
||||
|
||||
while (*ptr && !strchr(delim, *ptr))
|
||||
ptr++;
|
||||
|
||||
*saveptr = ptr + (*ptr ? 1 : 0);
|
||||
*ptr = '\0';
|
||||
} while (strlen(first) == 0);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_snprintf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if _MSC_VER < 1800
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
#if _MSC_VER < 1300
|
||||
#define _vscprintf c89_vscprintf_retro__
|
||||
|
||||
static int c89_vscprintf_retro__(const char *format, va_list pargs)
|
||||
{
|
||||
int retval;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, pargs);
|
||||
retval = vsnprintf(NULL, 0, format, argcopy);
|
||||
va_end(argcopy);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
|
||||
|
||||
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
#if (_MSC_VER <= 1310)
|
||||
count = _vsnprintf(outBuf, size - 1, format, ap);
|
||||
#else
|
||||
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
if (count == size)
|
||||
{
|
||||
/* there was no room for a NULL, so truncate the last character */
|
||||
outBuf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strcasestr.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strcasestr.h>
|
||||
|
||||
/* Pretty much strncasecmp. */
|
||||
static int casencmp(const char *a, const char *b, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int a_lower = tolower(a[i]);
|
||||
int b_lower = tolower(b[i]);
|
||||
if (a_lower != b_lower)
|
||||
return a_lower - b_lower;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcasestr_retro__(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t i, search_off;
|
||||
size_t hay_len = strlen(haystack);
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
if (needle_len > hay_len)
|
||||
return NULL;
|
||||
|
||||
search_off = hay_len - needle_len;
|
||||
for (i = 0; i <= search_off; i++)
|
||||
if (!casencmp(haystack + i, needle, needle_len))
|
||||
return (char*)haystack + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strl.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
|
||||
|
||||
#ifndef __MACH__
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t src_size = 0;
|
||||
size_t n = size;
|
||||
|
||||
if (n)
|
||||
while (--n && (*dest++ = *source++)) src_size++;
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if (size) *dest = '\0';
|
||||
while (*source++) src_size++;
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
|
||||
size_t strlcat(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t len = strlen(dest);
|
||||
|
||||
dest += len;
|
||||
|
||||
if (len > size)
|
||||
size = 0;
|
||||
else
|
||||
size -= len;
|
||||
|
||||
return len + strlcpy(dest, source, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n)
|
||||
{
|
||||
char *dst = (char*)malloc(sizeof(char) * (n + 1));
|
||||
strlcpy(dst, s, n);
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_snprintf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <retro_common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
#define va_copy(dst, src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
int c89_vscprintf_retro__(const char *format, va_list pargs)
|
||||
{
|
||||
int retval;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, pargs);
|
||||
retval = vsnprintf(NULL, 0, format, argcopy);
|
||||
va_end(argcopy);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fopen_utf8.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef fopen
|
||||
|
||||
void *fopen_utf8(const char * filename, const char * mode)
|
||||
{
|
||||
#if defined(_XBOX)
|
||||
return fopen(filename, mode);
|
||||
#elif defined(LEGACY_WIN32)
|
||||
FILE *ret = NULL;
|
||||
char * filename_local = utf8_to_local_string_alloc(filename);
|
||||
|
||||
if (!filename_local)
|
||||
return NULL;
|
||||
ret = fopen(filename_local, mode);
|
||||
if (filename_local)
|
||||
free(filename_local);
|
||||
return ret;
|
||||
#else
|
||||
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
||||
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
||||
FILE* ret = _wfopen(filename_w, mode_w);
|
||||
free(filename_w);
|
||||
free(mode_w);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __LIBRETRO_SDK_CRT_STRING_H_
|
||||
#define __LIBRETRO_SDK_CRT_STRING_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t len);
|
||||
|
||||
void *memset(void *b, int c, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifdef _MSC_VER
|
||||
#include <cruntime.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void *memset(void *dst, int val, size_t count)
|
||||
{
|
||||
void *start = dst;
|
||||
|
||||
#if defined(_M_IA64) || defined (_M_AMD64) || defined(_M_ALPHA) || defined (_M_PPC)
|
||||
extern void RtlFillMemory(void *, size_t count, char);
|
||||
|
||||
RtlFillMemory(dst, count, (char)val);
|
||||
#else
|
||||
while (count--)
|
||||
{
|
||||
*(char*)dst = (char)val;
|
||||
dst = (char*)dst + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
|
||||
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (dylib.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <dynamic/dylib.h>
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#ifdef NEED_DYNAMIC
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <compat/posix_string.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
/* Assume W-functions do not work below Win2K and Xbox platforms */
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static char last_dyn_error[512];
|
||||
|
||||
static void set_dl_error(void)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
|
||||
if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
last_dyn_error,
|
||||
sizeof(last_dyn_error) - 1,
|
||||
NULL) == 0)
|
||||
snprintf(last_dyn_error, sizeof(last_dyn_error) - 1,
|
||||
"unknown error %lu", err);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dylib_load:
|
||||
* @path : Path to libretro core library.
|
||||
*
|
||||
* Platform independent dylib loading.
|
||||
*
|
||||
* Returns: library handle on success, otherwise NULL.
|
||||
**/
|
||||
dylib_t dylib_load(const char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||||
#ifdef LEGACY_WIN32
|
||||
dylib_t lib = LoadLibrary(path);
|
||||
#else
|
||||
wchar_t *pathW = utf8_to_utf16_string_alloc(path);
|
||||
dylib_t lib = LoadLibraryW(pathW);
|
||||
|
||||
free(pathW);
|
||||
#endif
|
||||
|
||||
SetErrorMode(prevmode);
|
||||
|
||||
if (!lib)
|
||||
{
|
||||
set_dl_error();
|
||||
return NULL;
|
||||
}
|
||||
last_dyn_error[0] = 0;
|
||||
#else
|
||||
dylib_t lib = dlopen(path, RTLD_LAZY);
|
||||
#endif
|
||||
return lib;
|
||||
}
|
||||
|
||||
char *dylib_error(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (last_dyn_error[0])
|
||||
return last_dyn_error;
|
||||
return NULL;
|
||||
#else
|
||||
return (char*)dlerror();
|
||||
#endif
|
||||
}
|
||||
|
||||
function_t dylib_proc(dylib_t lib, const char *proc)
|
||||
{
|
||||
function_t sym;
|
||||
|
||||
#ifdef _WIN32
|
||||
sym = (function_t)GetProcAddress(lib ?
|
||||
(HMODULE)lib : GetModuleHandle(NULL), proc);
|
||||
if (!sym)
|
||||
{
|
||||
set_dl_error();
|
||||
return NULL;
|
||||
}
|
||||
last_dyn_error[0] = 0;
|
||||
#else
|
||||
void *ptr_sym = NULL;
|
||||
|
||||
if (lib)
|
||||
ptr_sym = dlsym(lib, proc);
|
||||
else
|
||||
{
|
||||
void *handle = dlopen(NULL, RTLD_LAZY);
|
||||
if (handle)
|
||||
{
|
||||
ptr_sym = dlsym(handle, proc);
|
||||
dlclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dirty hack to workaround the non-legality of
|
||||
* (void*) -> fn-pointer casts. */
|
||||
memcpy(&sym, &ptr_sym, sizeof(void*));
|
||||
#endif
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/**
|
||||
* dylib_close:
|
||||
* @lib : Library handle.
|
||||
*
|
||||
* Frees library handle.
|
||||
**/
|
||||
void dylib_close(dylib_t lib)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!FreeLibrary((HMODULE)lib))
|
||||
set_dl_error();
|
||||
last_dyn_error[0] = 0;
|
||||
#else
|
||||
#ifndef NO_DLCLOSE
|
||||
dlclose(lib);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_crc32.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <encodings/crc32.h>
|
||||
|
||||
static const uint32_t crc32_table[256] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len)
|
||||
{
|
||||
crc = crc ^ 0xffffffff;
|
||||
|
||||
while (len--)
|
||||
crc = crc32_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_utf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#elif defined(_XBOX)
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
static unsigned leading_ones(uint8_t c)
|
||||
{
|
||||
unsigned ones = 0;
|
||||
while (c & 0x80)
|
||||
{
|
||||
ones++;
|
||||
c <<= 1;
|
||||
}
|
||||
|
||||
return ones;
|
||||
}
|
||||
|
||||
/* Simple implementation. Assumes the sequence is
|
||||
* properly synchronized and terminated. */
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size)
|
||||
{
|
||||
unsigned i;
|
||||
size_t ret = 0;
|
||||
while (in_size && out_chars)
|
||||
{
|
||||
unsigned extra, shift;
|
||||
uint32_t c;
|
||||
uint8_t first = *in++;
|
||||
unsigned ones = leading_ones(first);
|
||||
|
||||
if (ones > 6 || ones == 1) /* Invalid or desync. */
|
||||
break;
|
||||
|
||||
extra = ones ? ones - 1 : ones;
|
||||
if (1 + extra > in_size) /* Overflow. */
|
||||
break;
|
||||
|
||||
shift = (extra - 1) * 6;
|
||||
c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
|
||||
|
||||
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||
c |= (*in & 0x3f) << shift;
|
||||
|
||||
*out++ = c;
|
||||
in_size -= 1 + extra;
|
||||
out_chars--;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size)
|
||||
{
|
||||
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned numAdds;
|
||||
uint32_t value;
|
||||
|
||||
if (in_pos == in_size)
|
||||
{
|
||||
*out_chars = out_pos;
|
||||
return true;
|
||||
}
|
||||
value = in[in_pos++];
|
||||
if (value < 0x80)
|
||||
{
|
||||
if (out)
|
||||
out[out_pos] = (char)value;
|
||||
out_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value >= 0xD800 && value < 0xE000)
|
||||
{
|
||||
uint32_t c2;
|
||||
|
||||
if (value >= 0xDC00 || in_pos == in_size)
|
||||
break;
|
||||
c2 = in[in_pos++];
|
||||
if (c2 < 0xDC00 || c2 >= 0xE000)
|
||||
break;
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for (numAdds = 1; numAdds < 5; numAdds++)
|
||||
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
|
||||
break;
|
||||
if (out)
|
||||
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
|
||||
+ (value >> (6 * numAdds)));
|
||||
out_pos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
if (out)
|
||||
out[out_pos] = (char)(0x80
|
||||
+ ((value >> (6 * numAdds)) & 0x3F));
|
||||
out_pos++;
|
||||
}while (numAdds != 0);
|
||||
}
|
||||
|
||||
*out_chars = out_pos;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Acts mostly like strlcpy.
|
||||
*
|
||||
* Copies the given number of UTF-8 characters,
|
||||
* but at most d_len bytes.
|
||||
*
|
||||
* Always NULL terminates.
|
||||
* Does not copy half a character.
|
||||
*
|
||||
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||
* Use only if 'chars' is considerably less than 'd_len'. */
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||
{
|
||||
const uint8_t *sb = (const uint8_t*)s;
|
||||
const uint8_t *sb_org = sb;
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
while (*sb && chars-- > 0)
|
||||
{
|
||||
sb++;
|
||||
while ((*sb & 0xC0) == 0x80) sb++;
|
||||
}
|
||||
|
||||
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||
{
|
||||
sb = sb_org + d_len-1;
|
||||
while ((*sb & 0xC0) == 0x80) sb--;
|
||||
}
|
||||
|
||||
memcpy(d, sb_org, sb-sb_org);
|
||||
d[sb-sb_org] = '\0';
|
||||
|
||||
return sb-sb_org;
|
||||
}
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars)
|
||||
{
|
||||
const uint8_t *strb = (const uint8_t*)str;
|
||||
if (!chars)
|
||||
return str;
|
||||
do
|
||||
{
|
||||
strb++;
|
||||
while ((*strb & 0xC0)==0x80) strb++;
|
||||
chars--;
|
||||
} while(chars);
|
||||
return (const char*)strb;
|
||||
}
|
||||
|
||||
size_t utf8len(const char *string)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
if (!string)
|
||||
return 0;
|
||||
|
||||
while (*string)
|
||||
{
|
||||
if ((*string & 0xC0) != 0x80)
|
||||
ret++;
|
||||
string++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint8_t utf8_walkbyte(const char **string)
|
||||
{
|
||||
return *((*string)++);
|
||||
}
|
||||
|
||||
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
||||
uint32_t utf8_walk(const char **string)
|
||||
{
|
||||
uint8_t first = utf8_walkbyte(string);
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (first < 128)
|
||||
return first;
|
||||
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xE0)
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xF0)
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
|
||||
if (first >= 0xF0)
|
||||
return ret | (first & 7) << 18;
|
||||
if (first >= 0xE0)
|
||||
return ret | (first & 15) << 12;
|
||||
return ret | (first & 31) << 6;
|
||||
}
|
||||
|
||||
static bool utf16_to_char(uint8_t **utf_data,
|
||||
size_t *dest_len, const uint16_t *in)
|
||||
{
|
||||
unsigned len = 0;
|
||||
|
||||
while (in[len] != '\0')
|
||||
len++;
|
||||
|
||||
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||
*dest_len += 1;
|
||||
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||
if (*utf_data == 0)
|
||||
return false;
|
||||
|
||||
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||
}
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||
{
|
||||
size_t dest_len = 0;
|
||||
uint8_t *utf16_data = NULL;
|
||||
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
utf16_data[dest_len] = 0;
|
||||
strlcpy(s, (const char*)utf16_data, len);
|
||||
}
|
||||
|
||||
free(utf16_data);
|
||||
utf16_data = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
static char* mb_to_mb_string_alloc(const char *str,
|
||||
enum CodePage cp_in, enum CodePage cp_out)
|
||||
{
|
||||
char *path_buf = NULL;
|
||||
wchar_t *path_buf_wide = NULL;
|
||||
int path_buf_len = 0;
|
||||
int path_buf_wide_len = 0;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
(void)path_buf;
|
||||
(void)path_buf_wide;
|
||||
(void)path_buf_len;
|
||||
(void)path_buf_wide_len;
|
||||
|
||||
#if !defined(_WIN32) || defined(_XBOX)
|
||||
/* assume string needs no modification if not on Windows */
|
||||
return strdup(str);
|
||||
#else
|
||||
#ifdef UNICODE
|
||||
/* TODO/FIXME: Not implemented. */
|
||||
return strdup(str);
|
||||
#else
|
||||
|
||||
/* Windows 95 will return 0 from these functions with a UTF8 codepage set without MSLU. From an unknown MSDN version (others omit this info):
|
||||
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later: Translate using UTF-8. When this is set, dwFlags must be zero.
|
||||
* - Windows 95: Under the Microsoft Layer for Unicode, MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||
*/
|
||||
path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||
|
||||
if (path_buf_wide_len)
|
||||
{
|
||||
path_buf_wide = (wchar_t*)
|
||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||
|
||||
if (path_buf_wide)
|
||||
{
|
||||
MultiByteToWideChar(cp_in, 0,
|
||||
str, -1, path_buf_wide, path_buf_wide_len);
|
||||
|
||||
if (*path_buf_wide)
|
||||
{
|
||||
path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (path_buf_len)
|
||||
{
|
||||
path_buf = (char*)
|
||||
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||
|
||||
if (path_buf)
|
||||
{
|
||||
WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, path_buf,
|
||||
path_buf_len, NULL, NULL);
|
||||
|
||||
free(path_buf_wide);
|
||||
|
||||
if (*path_buf)
|
||||
return path_buf;
|
||||
|
||||
free(path_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(path_buf_wide);
|
||||
return strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return strdup(str);
|
||||
|
||||
if (path_buf_wide)
|
||||
free(path_buf_wide);
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf8_to_local_string_alloc(const char *str)
|
||||
{
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* local_to_utf8_string_alloc(const char *str)
|
||||
{
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
#endif
|
||||
wchar_t *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fallback to ANSI codepage instead */
|
||||
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_len < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||
len = mbstowcs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = mbstowcs(buf, str, len);
|
||||
}
|
||||
|
||||
if (out_len == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
#endif
|
||||
char *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fallback to ANSI codepage instead */
|
||||
len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = WideCharToMultiByte(CP_ACP, 0, str, -1, buf, len, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_len < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||
len = wcstombs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = wcstombs(buf, str, len);
|
||||
}
|
||||
|
||||
if (out_len == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -0,0 +1,817 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (features_cpu.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <libretro.h>
|
||||
#include <features/features_cpu.h>
|
||||
#include <retro_timers.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#ifndef _PPU_INTRINSICS_H
|
||||
#include <ppu_intrinsics.h>
|
||||
#endif
|
||||
#elif defined(_XBOX360)
|
||||
#include <PPCIntrinsics.h>
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
|
||||
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
|
||||
#define CLOCK_MONOTONIC 2
|
||||
#endif
|
||||
|
||||
#if defined(PSP)
|
||||
#include <pspkernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <psprtc.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#include <psp2/kernel/processmgr.h>
|
||||
#include <psp2/rtc.h>
|
||||
#endif
|
||||
|
||||
#if defined(__PSL1GHT__)
|
||||
#include <sys/time.h>
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <sys/sys_time.h>
|
||||
#endif
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIIU
|
||||
#include <wiiu/os/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBNX)
|
||||
#include <switch.h>
|
||||
#elif defined(SWITCH)
|
||||
#include <libtransistor/types.h>
|
||||
#include <libtransistor/svc.h>
|
||||
#endif
|
||||
|
||||
#if defined(_3DS)
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/services/cfgu.h>
|
||||
#endif
|
||||
|
||||
/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
|
||||
#ifdef __MACH__
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 0
|
||||
#endif
|
||||
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 0
|
||||
#endif
|
||||
|
||||
/* this function is part of iOS 10 now */
|
||||
static int ra_clock_gettime(int clk_ik, struct timespec *t)
|
||||
{
|
||||
struct timeval now;
|
||||
int rv = gettimeofday(&now, NULL);
|
||||
if (rv)
|
||||
return rv;
|
||||
t->tv_sec = now.tv_sec;
|
||||
t->tv_nsec = now.tv_usec * 1000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
|
||||
#else
|
||||
#define ra_clock_gettime clock_gettime
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#if defined(BSD) || defined(__APPLE__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* cpu_features_get_perf_counter:
|
||||
*
|
||||
* Gets performance counter.
|
||||
*
|
||||
* Returns: performance counter.
|
||||
**/
|
||||
retro_perf_tick_t cpu_features_get_perf_counter(void)
|
||||
{
|
||||
retro_perf_tick_t time_ticks = 0;
|
||||
#if defined(_WIN32)
|
||||
long tv_sec, tv_usec;
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
static const unsigned __int64 epoch = 11644473600000000;
|
||||
#else
|
||||
static const unsigned __int64 epoch = 11644473600000000ULL;
|
||||
#endif
|
||||
FILETIME file_time;
|
||||
SYSTEMTIME system_time;
|
||||
ULARGE_INTEGER ularge;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
ularge.LowPart = file_time.dwLowDateTime;
|
||||
ularge.HighPart = file_time.dwHighDateTime;
|
||||
|
||||
tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
|
||||
tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||
time_ticks = (1000000 * tv_sec + tv_usec);
|
||||
#elif defined(__linux__) || defined(__QNX__) || defined(__MACH__)
|
||||
struct timespec tv = {0};
|
||||
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
||||
time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
|
||||
(retro_perf_tick_t)tv.tv_nsec;
|
||||
|
||||
#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__)
|
||||
__asm__ volatile ("rdtsc" : "=A" (time_ticks));
|
||||
#elif defined(__GNUC__) && defined(__x86_64__)
|
||||
unsigned a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
|
||||
#elif defined(__ARM_ARCH_6__)
|
||||
__asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
|
||||
#elif defined(__CELLOS_LV2__) || defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__)
|
||||
time_ticks = __mftb();
|
||||
#elif defined(GEKKO)
|
||||
time_ticks = gettime();
|
||||
#elif defined(PSP)
|
||||
sceRtcGetCurrentTick((uint64_t*)&time_ticks);
|
||||
#elif defined(VITA)
|
||||
sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
|
||||
#elif defined(_3DS)
|
||||
time_ticks = svcGetSystemTick();
|
||||
#elif defined(WIIU)
|
||||
time_ticks = OSGetSystemTime();
|
||||
#elif defined(__mips__)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
time_ticks = (1000000 * tv.tv_sec + tv.tv_usec);
|
||||
#endif
|
||||
|
||||
return time_ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpu_features_get_time_usec:
|
||||
*
|
||||
* Gets time in microseconds.
|
||||
*
|
||||
* Returns: time in microseconds.
|
||||
**/
|
||||
retro_time_t cpu_features_get_time_usec(void)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static LARGE_INTEGER freq;
|
||||
LARGE_INTEGER count;
|
||||
|
||||
/* Frequency is guaranteed to not change. */
|
||||
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
|
||||
return 0;
|
||||
|
||||
if (!QueryPerformanceCounter(&count))
|
||||
return 0;
|
||||
return count.QuadPart * 1000000 / freq.QuadPart;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return sys_time_get_system_time();
|
||||
#elif defined(GEKKO)
|
||||
return ticks_to_microsecs(gettime());
|
||||
#elif defined(WIIU)
|
||||
return ticks_to_us(OSGetSystemTime());
|
||||
#elif defined(SWITCH) || defined(HAVE_LIBNX)
|
||||
return (svcGetSystemTick() * 10) / 192;
|
||||
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
|
||||
struct timespec tv = {0};
|
||||
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||
return 0;
|
||||
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return emscripten_get_now() * 1000;
|
||||
#elif defined(__mips__) || defined(DJGPP)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return (1000000 * tv.tv_sec + tv.tv_usec);
|
||||
#elif defined(_3DS)
|
||||
return osGetTime() * 1000;
|
||||
#elif defined(VITA)
|
||||
return sceKernelGetProcessTimeWide();
|
||||
#else
|
||||
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
|
||||
#define CPU_X86
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#if (_MSC_VER > 1310)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CPU_X86) && !defined(__MACH__)
|
||||
void x86_cpuid(int func, int flags[4])
|
||||
{
|
||||
/* On Android, we compile RetroArch with PIC, and we
|
||||
* are not allowed to clobber the ebx register. */
|
||||
#ifdef __x86_64__
|
||||
#define REG_b "rbx"
|
||||
#define REG_S "rsi"
|
||||
#else
|
||||
#define REG_b "ebx"
|
||||
#define REG_S "esi"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__asm__ volatile (
|
||||
"mov %%" REG_b ", %%" REG_S "\n"
|
||||
"cpuid\n"
|
||||
"xchg %%" REG_b ", %%" REG_S "\n"
|
||||
: "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
|
||||
: "a"(func));
|
||||
#elif defined(_MSC_VER)
|
||||
__cpuid(flags, func);
|
||||
#else
|
||||
printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
|
||||
memset(flags, 0, 4 * sizeof(int));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Only runs on i686 and above. Needs to be conditionally run. */
|
||||
static uint64_t xgetbv_x86(uint32_t idx)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
uint32_t eax, edx;
|
||||
__asm__ volatile (
|
||||
/* Older GCC versions (Apple's GCC for example) do
|
||||
* not understand xgetbv instruction.
|
||||
* Stamp out the machine code directly.
|
||||
*/
|
||||
".byte 0x0f, 0x01, 0xd0\n"
|
||||
: "=a"(eax), "=d"(edx) : "c"(idx));
|
||||
return ((uint64_t)edx << 32) | eax;
|
||||
#elif _MSC_FULL_VER >= 160040219
|
||||
/* Intrinsic only works on 2010 SP1 and above. */
|
||||
return _xgetbv(idx);
|
||||
#else
|
||||
printf("Unknown compiler. Cannot check xgetbv bits.\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_NEON__)
|
||||
static void arm_enable_runfast_mode(void)
|
||||
{
|
||||
/* RunFast mode. Enables flush-to-zero and some
|
||||
* floating point optimizations. */
|
||||
static const unsigned x = 0x04086060;
|
||||
static const unsigned y = 0x03000000;
|
||||
int r;
|
||||
__asm__ volatile(
|
||||
"fmrx %0, fpscr \n\t" /* r0 = FPSCR */
|
||||
"and %0, %0, %1 \n\t" /* r0 = r0 & 0x04086060 */
|
||||
"orr %0, %0, %2 \n\t" /* r0 = r0 | 0x03000000 */
|
||||
"fmxr fpscr, %0 \n\t" /* FPSCR = r0 */
|
||||
: "=r"(r)
|
||||
: "r"(x), "r"(y)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(CPU_X86)
|
||||
static unsigned char check_arm_cpu_feature(const char* feature)
|
||||
{
|
||||
char line[1024];
|
||||
unsigned char status = 0;
|
||||
RFILE *fp = filestream_open("/proc/cpuinfo",
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (filestream_gets(fp, line, sizeof(line)) != NULL)
|
||||
{
|
||||
if (strncmp(line, "Features\t: ", 11))
|
||||
continue;
|
||||
|
||||
if (strstr(line + 11, feature) != NULL)
|
||||
status = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
filestream_close(fp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#if !defined(_SC_NPROCESSORS_ONLN)
|
||||
/* Parse an decimal integer starting from 'input', but not going further
|
||||
* than 'limit'. Return the value into '*result'.
|
||||
*
|
||||
* NOTE: Does not skip over leading spaces, or deal with sign characters.
|
||||
* NOTE: Ignores overflows.
|
||||
*
|
||||
* The function returns NULL in case of error (bad format), or the new
|
||||
* position after the decimal number in case of success (which will always
|
||||
* be <= 'limit').
|
||||
*/
|
||||
static const char *parse_decimal(const char* input,
|
||||
const char* limit, int* result)
|
||||
{
|
||||
const char* p = input;
|
||||
int val = 0;
|
||||
|
||||
while (p < limit)
|
||||
{
|
||||
int d = (*p - '0');
|
||||
if ((unsigned)d >= 10U)
|
||||
break;
|
||||
val = val*10 + d;
|
||||
p++;
|
||||
}
|
||||
if (p == input)
|
||||
return NULL;
|
||||
|
||||
*result = val;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Parse a textual list of cpus and store the result inside a CpuList object.
|
||||
* Input format is the following:
|
||||
* - comma-separated list of items (no spaces)
|
||||
* - each item is either a single decimal number (cpu index), or a range made
|
||||
* of two numbers separated by a single dash (-). Ranges are inclusive.
|
||||
*
|
||||
* Examples: 0
|
||||
* 2,4-127,128-143
|
||||
* 0-1
|
||||
*/
|
||||
static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
|
||||
{
|
||||
const char* p = (const char*)buf;
|
||||
const char* end = p + length;
|
||||
|
||||
/* NOTE: the input line coming from sysfs typically contains a
|
||||
* trailing newline, so take care of it in the code below
|
||||
*/
|
||||
while (p < end && *p != '\n')
|
||||
{
|
||||
int val, start_value, end_value;
|
||||
/* Find the end of current item, and put it into 'q' */
|
||||
const char *q = (const char*)memchr(p, ',', end-p);
|
||||
|
||||
if (!q)
|
||||
q = end;
|
||||
|
||||
/* Get first value */
|
||||
p = parse_decimal(p, q, &start_value);
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
end_value = start_value;
|
||||
|
||||
/* If we're not at the end of the item, expect a dash and
|
||||
* and integer; extract end value.
|
||||
*/
|
||||
if (p < q && *p == '-')
|
||||
{
|
||||
p = parse_decimal(p+1, q, &end_value);
|
||||
if (p == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set bits CPU list bits */
|
||||
for (val = start_value; val <= end_value; val++)
|
||||
{
|
||||
if ((unsigned)val < 32)
|
||||
list->mask |= (uint32_t)(1U << val);
|
||||
}
|
||||
|
||||
/* Jump to next item */
|
||||
p = q;
|
||||
if (p < end)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a CPU list from one sysfs file */
|
||||
static void cpulist_read_from(CpuList* list, const char* filename)
|
||||
{
|
||||
ssize_t length;
|
||||
char *buf = NULL;
|
||||
|
||||
list->mask = 0;
|
||||
|
||||
if (filestream_read_file(filename, (void**)&buf, &length) != 1)
|
||||
return;
|
||||
|
||||
cpulist_parse(list, &buf, length);
|
||||
if (buf)
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cpu_features_get_core_amount:
|
||||
*
|
||||
* Gets the amount of available CPU cores.
|
||||
*
|
||||
* Returns: amount of CPU cores available.
|
||||
**/
|
||||
unsigned cpu_features_get_core_amount(void)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
|
||||
/* Win32 */
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
return sysinfo.dwNumberOfProcessors;
|
||||
#elif defined(GEKKO)
|
||||
return 1;
|
||||
#elif defined(PSP)
|
||||
return 1;
|
||||
#elif defined(VITA)
|
||||
return 4;
|
||||
#elif defined(HAVE_LIBNX) || defined(SWITCH)
|
||||
return 4;
|
||||
#elif defined(_3DS)
|
||||
u8 device_model = 0xFF;
|
||||
CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
|
||||
switch (device_model)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
/*Old 3/2DS*/
|
||||
return 2;
|
||||
|
||||
case 2:
|
||||
case 4:
|
||||
case 5:
|
||||
/*New 3/2DS*/
|
||||
return 4;
|
||||
|
||||
default:
|
||||
/*Unknown Device Or Check Failed*/
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
#elif defined(WIIU)
|
||||
return 3;
|
||||
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||
/* Linux, most UNIX-likes. */
|
||||
long ret = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (ret <= 0)
|
||||
return (unsigned)1;
|
||||
return (unsigned)ret;
|
||||
#elif defined(BSD) || defined(__APPLE__)
|
||||
/* BSD */
|
||||
/* Copypasta from stackoverflow, dunno if it works. */
|
||||
int num_cpu = 0;
|
||||
int mib[4];
|
||||
size_t len = sizeof(num_cpu);
|
||||
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_AVAILCPU;
|
||||
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||
if (num_cpu < 1)
|
||||
{
|
||||
mib[1] = HW_NCPU;
|
||||
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||
if (num_cpu < 1)
|
||||
num_cpu = 1;
|
||||
}
|
||||
return num_cpu;
|
||||
#elif defined(__linux__)
|
||||
CpuList cpus_present[1];
|
||||
CpuList cpus_possible[1];
|
||||
int amount = 0;
|
||||
|
||||
cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
|
||||
cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
|
||||
|
||||
/* Compute the intersection of both sets to get the actual number of
|
||||
* CPU cores that can be used on this device by the kernel.
|
||||
*/
|
||||
cpus_present->mask &= cpus_possible->mask;
|
||||
amount = __builtin_popcount(cpus_present->mask);
|
||||
|
||||
if (amount == 0)
|
||||
return 1;
|
||||
return amount;
|
||||
#elif defined(_XBOX360)
|
||||
return 3;
|
||||
#else
|
||||
/* No idea, assume single core. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* According to http://en.wikipedia.org/wiki/CPUID */
|
||||
#define VENDOR_INTEL_b 0x756e6547
|
||||
#define VENDOR_INTEL_c 0x6c65746e
|
||||
#define VENDOR_INTEL_d 0x49656e69
|
||||
|
||||
/**
|
||||
* cpu_features_get:
|
||||
*
|
||||
* Gets CPU features..
|
||||
*
|
||||
* Returns: bitmask of all CPU features available.
|
||||
**/
|
||||
uint64_t cpu_features_get(void)
|
||||
{
|
||||
int flags[4];
|
||||
int vendor_shuffle[3];
|
||||
char vendor[13];
|
||||
size_t len = 0;
|
||||
uint64_t cpu_flags = 0;
|
||||
uint64_t cpu = 0;
|
||||
unsigned max_flag = 0;
|
||||
#if defined(CPU_X86) && !defined(__MACH__)
|
||||
int vendor_is_intel = 0;
|
||||
const int avx_flags = (1 << 27) | (1 << 28);
|
||||
#endif
|
||||
|
||||
char buf[sizeof(" MMX MMXEXT SSE SSE2 SSE3 SSSE3 SS4 SSE4.2 AES AVX AVX2 NEON VMX VMX128 VFPU PS")];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
(void)len;
|
||||
(void)cpu_flags;
|
||||
(void)flags;
|
||||
(void)max_flag;
|
||||
(void)vendor;
|
||||
(void)vendor_shuffle;
|
||||
|
||||
#if defined(__MACH__)
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
|
||||
{
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
|
||||
{
|
||||
cpu |= RETRO_SIMD_CMOV;
|
||||
}
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE2;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE3;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSSE3;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE4;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_SSE42;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AES;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AVX;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_AVX2;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_VMX;
|
||||
|
||||
len = sizeof(size_t);
|
||||
if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
|
||||
#elif defined(_XBOX1)
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
#elif defined(CPU_X86)
|
||||
(void)avx_flags;
|
||||
|
||||
x86_cpuid(0, flags);
|
||||
vendor_shuffle[0] = flags[1];
|
||||
vendor_shuffle[1] = flags[3];
|
||||
vendor_shuffle[2] = flags[2];
|
||||
|
||||
vendor[0] = '\0';
|
||||
memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
|
||||
|
||||
/* printf("[CPUID]: Vendor: %s\n", vendor); */
|
||||
|
||||
vendor_is_intel = (
|
||||
flags[1] == VENDOR_INTEL_b &&
|
||||
flags[2] == VENDOR_INTEL_c &&
|
||||
flags[3] == VENDOR_INTEL_d);
|
||||
|
||||
max_flag = flags[0];
|
||||
if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
|
||||
return 0;
|
||||
|
||||
x86_cpuid(1, flags);
|
||||
|
||||
if (flags[3] & (1 << 15))
|
||||
cpu |= RETRO_SIMD_CMOV;
|
||||
|
||||
if (flags[3] & (1 << 23))
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
|
||||
if (flags[3] & (1 << 25))
|
||||
{
|
||||
/* SSE also implies MMXEXT (according to FFmpeg source). */
|
||||
cpu |= RETRO_SIMD_SSE;
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
|
||||
|
||||
if (flags[3] & (1 << 26))
|
||||
cpu |= RETRO_SIMD_SSE2;
|
||||
|
||||
if (flags[2] & (1 << 0))
|
||||
cpu |= RETRO_SIMD_SSE3;
|
||||
|
||||
if (flags[2] & (1 << 9))
|
||||
cpu |= RETRO_SIMD_SSSE3;
|
||||
|
||||
if (flags[2] & (1 << 19))
|
||||
cpu |= RETRO_SIMD_SSE4;
|
||||
|
||||
if (flags[2] & (1 << 20))
|
||||
cpu |= RETRO_SIMD_SSE42;
|
||||
|
||||
if ((flags[2] & (1 << 23)))
|
||||
cpu |= RETRO_SIMD_POPCNT;
|
||||
|
||||
if (vendor_is_intel && (flags[2] & (1 << 22)))
|
||||
cpu |= RETRO_SIMD_MOVBE;
|
||||
|
||||
if (flags[2] & (1 << 25))
|
||||
cpu |= RETRO_SIMD_AES;
|
||||
|
||||
|
||||
/* Must only perform xgetbv check if we have
|
||||
* AVX CPU support (guaranteed to have at least i686). */
|
||||
if (((flags[2] & avx_flags) == avx_flags)
|
||||
&& ((xgetbv_x86(0) & 0x6) == 0x6))
|
||||
cpu |= RETRO_SIMD_AVX;
|
||||
|
||||
if (max_flag >= 7)
|
||||
{
|
||||
x86_cpuid(7, flags);
|
||||
if (flags[1] & (1 << 5))
|
||||
cpu |= RETRO_SIMD_AVX2;
|
||||
}
|
||||
|
||||
x86_cpuid(0x80000000, flags);
|
||||
max_flag = flags[0];
|
||||
if (max_flag >= 0x80000001u)
|
||||
{
|
||||
x86_cpuid(0x80000001, flags);
|
||||
if (flags[3] & (1 << 23))
|
||||
cpu |= RETRO_SIMD_MMX;
|
||||
if (flags[3] & (1 << 22))
|
||||
cpu |= RETRO_SIMD_MMXEXT;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
if (check_arm_cpu_feature("neon"))
|
||||
{
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
#ifdef __ARM_NEON__
|
||||
arm_enable_runfast_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (check_arm_cpu_feature("vfpv3"))
|
||||
cpu |= RETRO_SIMD_VFPV3;
|
||||
|
||||
if (check_arm_cpu_feature("vfpv4"))
|
||||
cpu |= RETRO_SIMD_VFPV4;
|
||||
|
||||
if (check_arm_cpu_feature("asimd"))
|
||||
{
|
||||
cpu |= RETRO_SIMD_ASIMD;
|
||||
#ifdef __ARM_NEON__
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
arm_enable_runfast_mode();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
check_arm_cpu_feature("swp");
|
||||
check_arm_cpu_feature("half");
|
||||
check_arm_cpu_feature("thumb");
|
||||
check_arm_cpu_feature("fastmult");
|
||||
check_arm_cpu_feature("vfp");
|
||||
check_arm_cpu_feature("edsp");
|
||||
check_arm_cpu_feature("thumbee");
|
||||
check_arm_cpu_feature("tls");
|
||||
check_arm_cpu_feature("idiva");
|
||||
check_arm_cpu_feature("idivt");
|
||||
#endif
|
||||
|
||||
#elif defined(__ARM_NEON__)
|
||||
cpu |= RETRO_SIMD_NEON;
|
||||
arm_enable_runfast_mode();
|
||||
#elif defined(__ALTIVEC__)
|
||||
cpu |= RETRO_SIMD_VMX;
|
||||
#elif defined(XBOX360)
|
||||
cpu |= RETRO_SIMD_VMX128;
|
||||
#elif defined(PSP)
|
||||
cpu |= RETRO_SIMD_VFPU;
|
||||
#elif defined(GEKKO)
|
||||
cpu |= RETRO_SIMD_PS;
|
||||
#endif
|
||||
|
||||
if (cpu & RETRO_SIMD_MMX) strlcat(buf, " MMX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_MMXEXT) strlcat(buf, " MMXEXT", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE) strlcat(buf, " SSE", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE2) strlcat(buf, " SSE2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE3) strlcat(buf, " SSE3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSSE3) strlcat(buf, " SSSE3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE4) strlcat(buf, " SSE4", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_SSE42) strlcat(buf, " SSE4.2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AES) strlcat(buf, " AES", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AVX) strlcat(buf, " AVX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_AVX2) strlcat(buf, " AVX2", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_NEON) strlcat(buf, " NEON", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPV3) strlcat(buf, " VFPv3", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPV4) strlcat(buf, " VFPv4", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VMX) strlcat(buf, " VMX", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VMX128) strlcat(buf, " VMX128", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_VFPU) strlcat(buf, " VFPU", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_PS) strlcat(buf, " PS", sizeof(buf));
|
||||
if (cpu & RETRO_SIMD_ASIMD) strlcat(buf, " ASIMD", sizeof(buf));
|
||||
|
||||
return cpu;
|
||||
}
|
||||
@@ -0,0 +1,908 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <file/archive_file.h>
|
||||
#include <file/file_path.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
struct file_archive_file_data
|
||||
{
|
||||
#ifdef HAVE_MMAP
|
||||
int fd;
|
||||
#endif
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t file_archive_size(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
return data->size;
|
||||
}
|
||||
|
||||
static const uint8_t *file_archive_data(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return NULL;
|
||||
return (const uint8_t*)data->data;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
/* Closes, unmaps and frees. */
|
||||
static void file_archive_free(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->data)
|
||||
munmap(data->data, data->size);
|
||||
if (data->fd >= 0)
|
||||
close(data->fd);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static file_archive_file_data_t* file_archive_open(const char *path)
|
||||
{
|
||||
file_archive_file_data_t *data = (file_archive_file_data_t*)calloc(1, sizeof(*data));
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->fd = open(path, O_RDONLY);
|
||||
|
||||
/* Failed to open archive. */
|
||||
if (data->fd < 0)
|
||||
goto error;
|
||||
|
||||
data->size = path_get_size(path);
|
||||
if (!data->size)
|
||||
return data;
|
||||
|
||||
data->data = mmap(NULL, data->size, PROT_READ, MAP_SHARED, data->fd, 0);
|
||||
if (data->data == MAP_FAILED)
|
||||
{
|
||||
data->data = NULL;
|
||||
|
||||
/* Failed to mmap() file */
|
||||
goto error;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
error:
|
||||
file_archive_free(data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Closes, unmaps and frees. */
|
||||
static void file_archive_free(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
if(data->data)
|
||||
free(data->data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static file_archive_file_data_t* file_archive_open(const char *path)
|
||||
{
|
||||
int64_t ret = -1;
|
||||
bool read_from_file = false;
|
||||
file_archive_file_data_t *data = (file_archive_file_data_t*)
|
||||
calloc(1, sizeof(*data));
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
read_from_file = filestream_read_file(path, &data->data, &ret);
|
||||
|
||||
/* Failed to open archive? */
|
||||
if (!read_from_file || ret < 0)
|
||||
goto error;
|
||||
|
||||
data->size = ret;
|
||||
return data;
|
||||
|
||||
error:
|
||||
file_archive_free(data);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int file_archive_get_file_list_cb(
|
||||
const char *path,
|
||||
const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
unsigned cmode,
|
||||
uint32_t csize,
|
||||
uint32_t size,
|
||||
uint32_t checksum,
|
||||
struct archive_extract_userdata *userdata)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
int ret = 0;
|
||||
struct string_list *ext_list = NULL;
|
||||
size_t path_len = strlen(path);
|
||||
|
||||
(void)cdata;
|
||||
(void)cmode;
|
||||
(void)csize;
|
||||
(void)size;
|
||||
(void)checksum;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (!path_len)
|
||||
return 0;
|
||||
|
||||
if (valid_exts)
|
||||
ext_list = string_split(valid_exts, "|");
|
||||
|
||||
if (ext_list)
|
||||
{
|
||||
const char *file_ext = NULL;
|
||||
/* Checks if this entry is a directory or a file. */
|
||||
char last_char = path[path_len-1];
|
||||
|
||||
/* Skip if directory. */
|
||||
if (last_char == '/' || last_char == '\\' )
|
||||
goto error;
|
||||
|
||||
file_ext = path_get_extension(path);
|
||||
|
||||
if (!file_ext)
|
||||
goto error;
|
||||
|
||||
if (!string_list_find_elem_prefix(ext_list, ".", file_ext))
|
||||
{
|
||||
/* keep iterating */
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;
|
||||
string_list_free(ext_list);
|
||||
}
|
||||
|
||||
return string_list_append(userdata->list, path, attr);
|
||||
|
||||
error:
|
||||
string_list_free(ext_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int file_archive_extract_cb(const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t checksum, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
const char *ext = path_get_extension(name);
|
||||
|
||||
/* Extract first file that matches our list. */
|
||||
if (ext && string_list_find_elem(userdata->ext, ext))
|
||||
{
|
||||
char new_path[PATH_MAX_LENGTH];
|
||||
char wanted_file[PATH_MAX_LENGTH];
|
||||
const char *delim = NULL;
|
||||
|
||||
new_path[0] = wanted_file[0] = '\0';
|
||||
|
||||
if (userdata->extraction_directory)
|
||||
fill_pathname_join(new_path, userdata->extraction_directory,
|
||||
path_basename(name), sizeof(new_path));
|
||||
else
|
||||
fill_pathname_resolve_relative(new_path, userdata->archive_path,
|
||||
path_basename(name), sizeof(new_path));
|
||||
|
||||
userdata->first_extracted_file_path = strdup(new_path);
|
||||
|
||||
delim = path_get_archive_delim(userdata->archive_path);
|
||||
|
||||
if (delim)
|
||||
{
|
||||
strlcpy(wanted_file, delim + 1, sizeof(wanted_file));
|
||||
|
||||
if (!string_is_equal_noncase(userdata->extracted_file_path,
|
||||
wanted_file))
|
||||
return 1; /* keep searching for the right file */
|
||||
}
|
||||
else
|
||||
strlcpy(wanted_file, userdata->archive_path, sizeof(wanted_file));
|
||||
|
||||
if (file_archive_perform_mode(new_path,
|
||||
valid_exts, cdata, cmode, csize, size,
|
||||
0, userdata))
|
||||
userdata->found_file = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int file_archive_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
char path[PATH_MAX_LENGTH];
|
||||
char *last = NULL;
|
||||
|
||||
path[0] = '\0';
|
||||
|
||||
strlcpy(path, file, sizeof(path));
|
||||
|
||||
last = (char*)path_get_archive_delim(path);
|
||||
|
||||
if (last)
|
||||
*last = '\0';
|
||||
|
||||
state->backend = file_archive_get_file_backend(path);
|
||||
if (!state->backend)
|
||||
return -1;
|
||||
|
||||
state->handle = file_archive_open(path);
|
||||
if (!state->handle)
|
||||
return -1;
|
||||
|
||||
state->archive_size = (int32_t)file_archive_size(state->handle);
|
||||
state->data = file_archive_data(state->handle);
|
||||
state->footer = 0;
|
||||
state->directory = 0;
|
||||
|
||||
return state->backend->archive_parse_file_init(state, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_decompress_data_to_file:
|
||||
* @path : filename path of archive.
|
||||
* @valid_exts : Valid extensions of archive to be parsed.
|
||||
* If NULL, allow all.
|
||||
* @cdata : input data.
|
||||
* @csize : size of input data.
|
||||
* @size : output file size
|
||||
* @checksum : CRC32 checksum from input data.
|
||||
*
|
||||
* Decompress data to file.
|
||||
*
|
||||
* Returns: true (1) on success, otherwise false (0).
|
||||
**/
|
||||
static int file_archive_decompress_data_to_file(
|
||||
file_archive_file_handle_t *handle,
|
||||
int ret,
|
||||
const char *path,
|
||||
const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
uint32_t csize,
|
||||
uint32_t size,
|
||||
uint32_t checksum)
|
||||
{
|
||||
if (!handle || ret == -1)
|
||||
{
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if 0
|
||||
handle->real_checksum = handle->backend->stream_crc_calculate(
|
||||
0, handle->data, size);
|
||||
if (handle->real_checksum != checksum)
|
||||
{
|
||||
/* File CRC difers from archive CRC. */
|
||||
printf("File CRC differs from archive CRC. File: 0x%x, Archive: 0x%x.\n",
|
||||
(unsigned)handle->real_checksum, (unsigned)checksum);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!filestream_write_file(path, handle->data, size))
|
||||
{
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (handle)
|
||||
{
|
||||
if (handle->backend)
|
||||
{
|
||||
if (handle->backend->stream_free)
|
||||
{
|
||||
#ifdef HAVE_7ZIP
|
||||
if (handle->backend != &sevenzip_backend)
|
||||
{
|
||||
handle->backend->stream_free(handle->stream);
|
||||
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
}
|
||||
#else
|
||||
handle->backend->stream_free(handle->stream);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
|
||||
{
|
||||
if (!state || !state->handle)
|
||||
return;
|
||||
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT;
|
||||
file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int file_archive_parse_file_iterate(
|
||||
file_archive_transfer_t *state,
|
||||
bool *returnerr,
|
||||
const char *file,
|
||||
const char *valid_exts,
|
||||
file_archive_file_cb file_cb,
|
||||
struct archive_extract_userdata *userdata)
|
||||
{
|
||||
if (!state)
|
||||
return -1;
|
||||
|
||||
switch (state->type)
|
||||
{
|
||||
case ARCHIVE_TRANSFER_NONE:
|
||||
break;
|
||||
case ARCHIVE_TRANSFER_INIT:
|
||||
if (file_archive_parse_file_init(state, file) == 0)
|
||||
{
|
||||
if (userdata)
|
||||
{
|
||||
userdata->context = state->stream;
|
||||
strlcpy(userdata->archive_path, file,
|
||||
sizeof(userdata->archive_path));
|
||||
}
|
||||
state->type = ARCHIVE_TRANSFER_ITERATE;
|
||||
}
|
||||
else
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
|
||||
break;
|
||||
case ARCHIVE_TRANSFER_ITERATE:
|
||||
if (file_archive_get_file_backend(file))
|
||||
{
|
||||
const struct file_archive_file_backend *backend =
|
||||
file_archive_get_file_backend(file);
|
||||
int ret =
|
||||
backend->archive_parse_file_iterate_step(state,
|
||||
valid_exts, userdata, file_cb);
|
||||
|
||||
if (ret != 1)
|
||||
{
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT;
|
||||
}
|
||||
if (ret == -1)
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
|
||||
|
||||
/* early return to prevent deinit from never firing */
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
case ARCHIVE_TRANSFER_DEINIT_ERROR:
|
||||
*returnerr = false;
|
||||
case ARCHIVE_TRANSFER_DEINIT:
|
||||
if (state->handle)
|
||||
{
|
||||
file_archive_free(state->handle);
|
||||
state->handle = NULL;
|
||||
}
|
||||
|
||||
if (state->stream && state->backend)
|
||||
{
|
||||
if (state->backend->stream_free)
|
||||
state->backend->stream_free(state->stream);
|
||||
|
||||
if (state->stream)
|
||||
free(state->stream);
|
||||
|
||||
state->stream = NULL;
|
||||
|
||||
if (userdata)
|
||||
userdata->context = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( state->type == ARCHIVE_TRANSFER_DEINIT ||
|
||||
state->type == ARCHIVE_TRANSFER_DEINIT_ERROR)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_walk:
|
||||
* @file : filename path of archive
|
||||
* @valid_exts : Valid extensions of archive to be parsed.
|
||||
* If NULL, allow all.
|
||||
* @file_cb : file_cb function pointer
|
||||
* @userdata : userdata to pass to file_cb function pointer.
|
||||
*
|
||||
* Low-level file parsing. Enumerates over all files and calls
|
||||
* file_cb with userdata.
|
||||
*
|
||||
* Returns: true (1) on success, otherwise false (0).
|
||||
**/
|
||||
static bool file_archive_walk(const char *file, const char *valid_exts,
|
||||
file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
file_archive_transfer_t state;
|
||||
bool returnerr = true;
|
||||
|
||||
state.type = ARCHIVE_TRANSFER_INIT;
|
||||
state.archive_size = 0;
|
||||
state.handle = NULL;
|
||||
state.stream = NULL;
|
||||
state.footer = NULL;
|
||||
state.directory = NULL;
|
||||
state.data = NULL;
|
||||
state.backend = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (file_archive_parse_file_iterate(&state, &returnerr, file,
|
||||
valid_exts, file_cb, userdata) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return returnerr;
|
||||
}
|
||||
|
||||
int file_archive_parse_file_progress(file_archive_transfer_t *state)
|
||||
{
|
||||
/* FIXME: this estimate is worse than before */
|
||||
ptrdiff_t delta = 0;
|
||||
|
||||
if (!state || state->archive_size == 0)
|
||||
return 0;
|
||||
|
||||
delta = state->directory - state->data;
|
||||
|
||||
return (int)(delta * 100 / state->archive_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_extract_file:
|
||||
* @archive_path : filename path to archive.
|
||||
* @archive_path_size : size of archive.
|
||||
* @valid_exts : valid extensions for the file.
|
||||
* @extraction_directory : the directory to extract temporary
|
||||
* file to.
|
||||
*
|
||||
* Extract file from archive. If no file inside the archive is
|
||||
* specified, the first file found will be used.
|
||||
*
|
||||
* Returns : true (1) on success, otherwise false (0).
|
||||
**/
|
||||
bool file_archive_extract_file(
|
||||
char *archive_path,
|
||||
size_t archive_path_size,
|
||||
const char *valid_exts,
|
||||
const char *extraction_directory,
|
||||
char *out_path, size_t len)
|
||||
{
|
||||
struct archive_extract_userdata userdata;
|
||||
bool ret = true;
|
||||
struct string_list *list = string_split(valid_exts, "|");
|
||||
|
||||
userdata.archive_path[0] = '\0';
|
||||
userdata.first_extracted_file_path = NULL;
|
||||
userdata.extracted_file_path = NULL;
|
||||
userdata.extraction_directory = extraction_directory;
|
||||
userdata.archive_path_size = archive_path_size;
|
||||
userdata.ext = list;
|
||||
userdata.list = NULL;
|
||||
userdata.found_file = false;
|
||||
userdata.list_only = false;
|
||||
userdata.context = NULL;
|
||||
userdata.archive_name[0] = '\0';
|
||||
userdata.crc = 0;
|
||||
userdata.dec = NULL;
|
||||
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.size = 0;
|
||||
userdata.decomp_state.found = false;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!file_archive_walk(archive_path, valid_exts,
|
||||
file_archive_extract_cb, &userdata))
|
||||
{
|
||||
/* Parsing file archive failed. */
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!userdata.found_file)
|
||||
{
|
||||
/* Didn't find any file that matched valid extensions
|
||||
* for libretro implementation. */
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!string_is_empty(userdata.first_extracted_file_path))
|
||||
strlcpy(out_path, userdata.first_extracted_file_path, len);
|
||||
|
||||
end:
|
||||
if (userdata.first_extracted_file_path)
|
||||
free(userdata.first_extracted_file_path);
|
||||
if (list)
|
||||
string_list_free(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_get_file_list:
|
||||
* @path : filename path of archive
|
||||
*
|
||||
* Returns: string listing of files from archive on success, otherwise NULL.
|
||||
**/
|
||||
struct string_list *file_archive_get_file_list(const char *path,
|
||||
const char *valid_exts)
|
||||
{
|
||||
int ret;
|
||||
struct archive_extract_userdata userdata;
|
||||
|
||||
strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
|
||||
userdata.first_extracted_file_path = NULL;
|
||||
userdata.extracted_file_path = NULL;
|
||||
userdata.extraction_directory = NULL;
|
||||
userdata.archive_path_size = 0;
|
||||
userdata.ext = NULL;
|
||||
userdata.list = string_list_new();
|
||||
userdata.found_file = false;
|
||||
userdata.list_only = true;
|
||||
userdata.context = NULL;
|
||||
userdata.archive_name[0] = '\0';
|
||||
userdata.crc = 0;
|
||||
userdata.dec = NULL;
|
||||
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.size = 0;
|
||||
userdata.decomp_state.found = false;
|
||||
|
||||
if (!userdata.list)
|
||||
goto error;
|
||||
|
||||
ret = file_archive_walk(path, valid_exts,
|
||||
file_archive_get_file_list_cb, &userdata);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (ret != -1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return userdata.list;
|
||||
|
||||
error:
|
||||
if (userdata.list)
|
||||
string_list_free(userdata.list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool file_archive_perform_mode(const char *path, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
switch (cmode)
|
||||
{
|
||||
case ARCHIVE_MODE_UNCOMPRESSED:
|
||||
if (!filestream_write_file(path, cdata, size))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
case ARCHIVE_MODE_COMPRESSED:
|
||||
{
|
||||
int ret = 0;
|
||||
file_archive_file_handle_t handle;
|
||||
|
||||
handle.stream = userdata->context;
|
||||
handle.data = NULL;
|
||||
handle.real_checksum = 0;
|
||||
handle.backend = file_archive_get_file_backend(userdata->archive_path);
|
||||
|
||||
if (!handle.backend)
|
||||
goto error;
|
||||
|
||||
if (!handle.backend->stream_decompress_data_to_file_init(&handle,
|
||||
cdata, csize, size))
|
||||
goto error;
|
||||
|
||||
do
|
||||
{
|
||||
ret = handle.backend->stream_decompress_data_to_file_iterate(
|
||||
handle.stream);
|
||||
}while(ret == 0);
|
||||
|
||||
if (!file_archive_decompress_data_to_file(&handle,
|
||||
ret, path, valid_exts,
|
||||
cdata, csize, size, crc32))
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_filename_split:
|
||||
* @str : filename to turn into a string list
|
||||
*
|
||||
* Creates a new string list based on filename @path, delimited by a hash (#).
|
||||
*
|
||||
* Returns: new string list if successful, otherwise NULL.
|
||||
*/
|
||||
static struct string_list *file_archive_filename_split(const char *path)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *list = string_list_new();
|
||||
const char *delim = path_get_archive_delim(path);
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (delim)
|
||||
{
|
||||
/* add archive path to list first */
|
||||
if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))
|
||||
goto error;
|
||||
|
||||
/* now add the path within the archive */
|
||||
delim++;
|
||||
|
||||
if (*delim)
|
||||
{
|
||||
if (!string_list_append(list, delim, attr))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!string_list_append(list, path, attr))
|
||||
goto error;
|
||||
|
||||
return list;
|
||||
|
||||
error:
|
||||
string_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generic compressed file loader.
|
||||
* Extracts to buf, unless optional_filename != 0
|
||||
* Then extracts to optional_filename and leaves buf alone.
|
||||
*/
|
||||
int file_archive_compressed_read(
|
||||
const char * path, void **buf,
|
||||
const char* optional_filename, int64_t *length)
|
||||
{
|
||||
const struct file_archive_file_backend *backend = NULL;
|
||||
int ret = 0;
|
||||
struct string_list *str_list = file_archive_filename_split(path);
|
||||
|
||||
/* Safety check.
|
||||
* If optional_filename and optional_filename
|
||||
* exists, we simply return 0,
|
||||
* hoping that optional_filename is the
|
||||
* same as requested.
|
||||
*/
|
||||
if (optional_filename && filestream_exists(optional_filename))
|
||||
{
|
||||
*length = 0;
|
||||
string_list_free(str_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We assure that there is something after the '#' symbol.
|
||||
*
|
||||
* This error condition happens for example, when
|
||||
* path = /path/to/file.7z, or
|
||||
* path = /path/to/file.7z#
|
||||
*/
|
||||
if (str_list->size <= 1)
|
||||
goto error;
|
||||
|
||||
backend = file_archive_get_file_backend(str_list->elems[0].data);
|
||||
|
||||
*length = backend->compressed_file_read(str_list->elems[0].data,
|
||||
str_list->elems[1].data, buf, optional_filename);
|
||||
|
||||
if (*length != -1)
|
||||
ret = 1;
|
||||
|
||||
string_list_free(str_list);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
/* could not extract string and substring. */
|
||||
string_list_free(str_list);
|
||||
*length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)
|
||||
{
|
||||
#ifdef HAVE_ZLIB
|
||||
return &zlib_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend *file_archive_get_7z_file_backend(void)
|
||||
{
|
||||
#ifdef HAVE_7ZIP
|
||||
return &sevenzip_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend* file_archive_get_file_backend(const char *path)
|
||||
{
|
||||
char newpath[PATH_MAX_LENGTH];
|
||||
const char *file_ext = NULL;
|
||||
char *last = NULL;
|
||||
|
||||
newpath[0] = '\0';
|
||||
|
||||
strlcpy(newpath, path, sizeof(newpath));
|
||||
|
||||
last = (char*)path_get_archive_delim(newpath);
|
||||
|
||||
if (last)
|
||||
*last = '\0';
|
||||
|
||||
file_ext = path_get_extension(newpath);
|
||||
|
||||
#ifdef HAVE_7ZIP
|
||||
if (string_is_equal_noncase(file_ext, "7z"))
|
||||
return &sevenzip_backend;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
if ( string_is_equal_noncase(file_ext, "zip")
|
||||
|| string_is_equal_noncase(file_ext, "apk")
|
||||
)
|
||||
return &zlib_backend;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_get_file_crc32:
|
||||
* @path : filename path of archive
|
||||
*
|
||||
* Returns: CRC32 of the specified file in the archive, otherwise 0.
|
||||
* If no path within the archive is specified, the first
|
||||
* file found inside is used.
|
||||
**/
|
||||
uint32_t file_archive_get_file_crc32(const char *path)
|
||||
{
|
||||
file_archive_transfer_t state;
|
||||
const struct file_archive_file_backend *backend = file_archive_get_file_backend(path);
|
||||
struct archive_extract_userdata userdata = {{0}};
|
||||
bool returnerr = false;
|
||||
bool contains_compressed = false;
|
||||
const char *archive_path = NULL;
|
||||
|
||||
if (!backend)
|
||||
return 0;
|
||||
|
||||
contains_compressed = path_contains_compressed_file(path);
|
||||
|
||||
if (contains_compressed)
|
||||
{
|
||||
archive_path = path_get_archive_delim(path);
|
||||
|
||||
/* move pointer right after the delimiter to give us the path */
|
||||
if (archive_path)
|
||||
archive_path += 1;
|
||||
}
|
||||
|
||||
state.type = ARCHIVE_TRANSFER_INIT;
|
||||
state.archive_size = 0;
|
||||
state.handle = NULL;
|
||||
state.stream = NULL;
|
||||
state.footer = NULL;
|
||||
state.directory = NULL;
|
||||
state.data = NULL;
|
||||
state.backend = NULL;
|
||||
|
||||
/* Initialize and open archive first.
|
||||
Sets next state type to ITERATE. */
|
||||
file_archive_parse_file_iterate(&state,
|
||||
&returnerr, path, NULL, NULL,
|
||||
&userdata);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Now find the first file in the archive. */
|
||||
if (state.type == ARCHIVE_TRANSFER_ITERATE)
|
||||
file_archive_parse_file_iterate(&state,
|
||||
&returnerr, path, NULL, NULL,
|
||||
&userdata);
|
||||
|
||||
/* If no path specified within archive, stop after
|
||||
* finding the first file.
|
||||
*/
|
||||
if (!contains_compressed)
|
||||
break;
|
||||
|
||||
/* Stop when the right file in the archive is found. */
|
||||
if (archive_path)
|
||||
{
|
||||
if (string_is_equal(userdata.extracted_file_path, archive_path))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
file_archive_parse_file_iterate_stop(&state);
|
||||
|
||||
if (userdata.crc)
|
||||
return userdata.crc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file_sevenzip.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <encodings/crc32.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <file/file_path.h>
|
||||
#include <compat/strl.h>
|
||||
#include <7zip/7z.h>
|
||||
#include <7zip/7zCrc.h>
|
||||
#include <7zip/7zFile.h>
|
||||
|
||||
#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C"
|
||||
#define SEVENZIP_MAGIC_LEN 6
|
||||
|
||||
/* Assume W-functions do not work below Win2K and Xbox platforms */
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct sevenzip_context_t {
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead lookStream;
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
CSzArEx db;
|
||||
size_t temp_size;
|
||||
uint32_t block_index;
|
||||
uint32_t index;
|
||||
uint32_t packIndex;
|
||||
uint8_t *output;
|
||||
file_archive_file_handle_t *handle;
|
||||
};
|
||||
|
||||
static void *sevenzip_stream_alloc_impl(void *p, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void sevenzip_stream_free_impl(void *p, void *address)
|
||||
{
|
||||
(void)p;
|
||||
|
||||
if (address)
|
||||
free(address);
|
||||
}
|
||||
|
||||
static void *sevenzip_stream_alloc_tmp_impl(void *p, size_t size)
|
||||
{
|
||||
(void)p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void* sevenzip_stream_new(void)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));
|
||||
|
||||
/* These are the allocation routines - currently using
|
||||
* the non-standard 7zip choices. */
|
||||
sevenzip_context->allocImp.Alloc = sevenzip_stream_alloc_impl;
|
||||
sevenzip_context->allocImp.Free = sevenzip_stream_free_impl;
|
||||
sevenzip_context->allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
|
||||
sevenzip_context->allocTempImp.Free = sevenzip_stream_free_impl;
|
||||
sevenzip_context->block_index = 0xFFFFFFFF;
|
||||
sevenzip_context->output = NULL;
|
||||
sevenzip_context->handle = NULL;
|
||||
|
||||
return sevenzip_context;
|
||||
}
|
||||
|
||||
static void sevenzip_stream_free(void *data)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)data;
|
||||
|
||||
if (!sevenzip_context)
|
||||
return;
|
||||
|
||||
if (sevenzip_context->output)
|
||||
{
|
||||
IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);
|
||||
sevenzip_context->output = NULL;
|
||||
sevenzip_context->handle->data = NULL;
|
||||
}
|
||||
|
||||
SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);
|
||||
File_Close(&sevenzip_context->archiveStream.file);
|
||||
}
|
||||
|
||||
/* Extract the relative path (needle) from a 7z archive
|
||||
* (path) and allocate a buf for it to write it in.
|
||||
* If optional_outfile is set, extract to that instead
|
||||
* and don't allocate buffer.
|
||||
*/
|
||||
static int sevenzip_file_read(
|
||||
const char *path,
|
||||
const char *needle, void **buf,
|
||||
const char *optional_outfile)
|
||||
{
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead lookStream;
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
CSzArEx db;
|
||||
uint8_t *output = 0;
|
||||
long outsize = -1;
|
||||
|
||||
/*These are the allocation routines.
|
||||
* Currently using the non-standard 7zip choices. */
|
||||
allocImp.Alloc = sevenzip_stream_alloc_impl;
|
||||
allocImp.Free = sevenzip_stream_free_impl;
|
||||
allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
|
||||
allocTempImp.Free = sevenzip_stream_free_impl;
|
||||
|
||||
#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
|
||||
if (!string_is_empty(path))
|
||||
{
|
||||
wchar_t *pathW = utf8_to_utf16_string_alloc(path);
|
||||
|
||||
if (pathW)
|
||||
{
|
||||
/* Could not open 7zip archive? */
|
||||
if (InFile_OpenW(&archiveStream.file, pathW))
|
||||
{
|
||||
free(pathW);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(pathW);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Could not open 7zip archive? */
|
||||
if (InFile_Open(&archiveStream.file, path))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
FileInStream_CreateVTable(&archiveStream);
|
||||
LookToRead_CreateVTable(&lookStream, false);
|
||||
lookStream.realStream = &archiveStream.s;
|
||||
LookToRead_Init(&lookStream);
|
||||
CrcGenerateTable();
|
||||
|
||||
db.db.PackSizes = NULL;
|
||||
db.db.PackCRCsDefined = NULL;
|
||||
db.db.PackCRCs = NULL;
|
||||
db.db.Folders = NULL;
|
||||
db.db.Files = NULL;
|
||||
db.db.NumPackStreams = 0;
|
||||
db.db.NumFolders = 0;
|
||||
db.db.NumFiles = 0;
|
||||
db.startPosAfterHeader = 0;
|
||||
db.dataPos = 0;
|
||||
db.FolderStartPackStreamIndex = NULL;
|
||||
db.PackStreamStartPositions = NULL;
|
||||
db.FolderStartFileIndex = NULL;
|
||||
db.FileIndexToFolderIndexMap = NULL;
|
||||
db.FileNameOffsets = NULL;
|
||||
db.FileNames.data = NULL;
|
||||
db.FileNames.size = 0;
|
||||
|
||||
SzArEx_Init(&db);
|
||||
|
||||
if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK)
|
||||
{
|
||||
uint32_t i;
|
||||
bool file_found = false;
|
||||
uint16_t *temp = NULL;
|
||||
size_t temp_size = 0;
|
||||
uint32_t block_index = 0xFFFFFFFF;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
for (i = 0; i < db.db.NumFiles; i++)
|
||||
{
|
||||
size_t len;
|
||||
char infile[PATH_MAX_LENGTH];
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
const CSzFileItem *f = db.db.Files + i;
|
||||
|
||||
/* We skip over everything which is not a directory.
|
||||
* FIXME: Why continue then if f->IsDir is true?*/
|
||||
if (f->IsDir)
|
||||
continue;
|
||||
|
||||
len = SzArEx_GetFileNameUtf16(&db, i, NULL);
|
||||
|
||||
if (len > temp_size)
|
||||
{
|
||||
if (temp)
|
||||
free(temp);
|
||||
temp_size = len;
|
||||
temp = (uint16_t *)malloc(temp_size * sizeof(temp[0]));
|
||||
|
||||
if (temp == 0)
|
||||
{
|
||||
res = SZ_ERROR_MEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SzArEx_GetFileNameUtf16(&db, i, temp);
|
||||
res = SZ_ERROR_FAIL;
|
||||
infile[0] = '\0';
|
||||
|
||||
if (temp)
|
||||
res = utf16_to_char_string(temp, infile, sizeof(infile))
|
||||
? SZ_OK : SZ_ERROR_FAIL;
|
||||
|
||||
if (string_is_equal(infile, needle))
|
||||
{
|
||||
size_t output_size = 0;
|
||||
|
||||
/* C LZMA SDK does not support chunked extraction - see here:
|
||||
* sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/
|
||||
* */
|
||||
file_found = true;
|
||||
res = SzArEx_Extract(&db, &lookStream.s, i, &block_index,
|
||||
&output, &output_size, &offset, &outSizeProcessed,
|
||||
&allocImp, &allocTempImp);
|
||||
|
||||
if (res != SZ_OK)
|
||||
break; /* This goes to the error section. */
|
||||
|
||||
outsize = outSizeProcessed;
|
||||
|
||||
if (optional_outfile != NULL)
|
||||
{
|
||||
const void *ptr = (const void*)(output + offset);
|
||||
|
||||
if (!filestream_write_file(optional_outfile, ptr, outsize))
|
||||
{
|
||||
res = SZ_OK;
|
||||
file_found = true;
|
||||
outsize = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*We could either use the 7Zip allocated buffer,
|
||||
* or create our own and use it.
|
||||
* We would however need to realloc anyways, because RetroArch
|
||||
* expects a \0 at the end, therefore we allocate new,
|
||||
* copy and free the old one. */
|
||||
*buf = malloc(outsize + 1);
|
||||
((char*)(*buf))[outsize] = '\0';
|
||||
memcpy(*buf,output + offset,outsize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp)
|
||||
free(temp);
|
||||
IAlloc_Free(&allocImp, output);
|
||||
|
||||
if (!(file_found && res == SZ_OK))
|
||||
{
|
||||
/* Error handling
|
||||
*
|
||||
* Failed to open compressed file inside 7zip archive.
|
||||
*/
|
||||
|
||||
outsize = -1;
|
||||
}
|
||||
}
|
||||
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
File_Close(&archiveStream.file);
|
||||
|
||||
return (int)outsize;
|
||||
}
|
||||
|
||||
static bool sevenzip_stream_decompress_data_to_file_init(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize, uint32_t size)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)handle->stream;
|
||||
|
||||
if (!sevenzip_context)
|
||||
return false;
|
||||
|
||||
sevenzip_context->handle = handle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)data;
|
||||
|
||||
SRes res = SZ_ERROR_FAIL;
|
||||
size_t output_size = 0;
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
|
||||
res = SzArEx_Extract(&sevenzip_context->db,
|
||||
&sevenzip_context->lookStream.s, sevenzip_context->index,
|
||||
&sevenzip_context->block_index, &sevenzip_context->output,
|
||||
&output_size, &offset, &outSizeProcessed,
|
||||
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp);
|
||||
|
||||
if (res != SZ_OK)
|
||||
return 0;
|
||||
|
||||
if (sevenzip_context->handle)
|
||||
sevenzip_context->handle->data = sevenzip_context->output + offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)sevenzip_stream_new();
|
||||
|
||||
if (state->archive_size < SEVENZIP_MAGIC_LEN)
|
||||
goto error;
|
||||
|
||||
if (string_is_not_equal_fast(state->data, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN))
|
||||
goto error;
|
||||
|
||||
state->stream = sevenzip_context;
|
||||
|
||||
#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
|
||||
if (!string_is_empty(file))
|
||||
{
|
||||
wchar_t *fileW = utf8_to_utf16_string_alloc(file);
|
||||
|
||||
if (fileW)
|
||||
{
|
||||
/* could not open 7zip archive? */
|
||||
if (InFile_OpenW(&sevenzip_context->archiveStream.file, fileW))
|
||||
{
|
||||
free(fileW);
|
||||
goto error;
|
||||
}
|
||||
|
||||
free(fileW);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* could not open 7zip archive? */
|
||||
if (InFile_Open(&sevenzip_context->archiveStream.file, file))
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
FileInStream_CreateVTable(&sevenzip_context->archiveStream);
|
||||
LookToRead_CreateVTable(&sevenzip_context->lookStream, false);
|
||||
sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.s;
|
||||
LookToRead_Init(&sevenzip_context->lookStream);
|
||||
CrcGenerateTable();
|
||||
SzArEx_Init(&sevenzip_context->db);
|
||||
|
||||
if (SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.s,
|
||||
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (sevenzip_context)
|
||||
sevenzip_stream_free(sevenzip_context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_iterate_step_internal(
|
||||
file_archive_transfer_t *state, char *filename,
|
||||
const uint8_t **cdata, unsigned *cmode,
|
||||
uint32_t *size, uint32_t *csize, uint32_t *checksum,
|
||||
unsigned *payback, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)state->stream;
|
||||
const CSzFileItem *file = sevenzip_context->db.db.Files + sevenzip_context->index;
|
||||
|
||||
if (sevenzip_context->index < sevenzip_context->db.db.NumFiles)
|
||||
{
|
||||
size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,
|
||||
sevenzip_context->index, NULL);
|
||||
uint64_t compressed_size = 0;
|
||||
|
||||
if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)
|
||||
{
|
||||
compressed_size = sevenzip_context->db.db.PackSizes[sevenzip_context->packIndex];
|
||||
sevenzip_context->packIndex++;
|
||||
}
|
||||
|
||||
if (len < PATH_MAX_LENGTH && !file->IsDir)
|
||||
{
|
||||
char infile[PATH_MAX_LENGTH];
|
||||
SRes res = SZ_ERROR_FAIL;
|
||||
uint16_t *temp = (uint16_t*)malloc(len * sizeof(uint16_t));
|
||||
|
||||
if (!temp)
|
||||
return -1;
|
||||
|
||||
infile[0] = '\0';
|
||||
|
||||
SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->index,
|
||||
temp);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
res = utf16_to_char_string(temp, infile, sizeof(infile))
|
||||
? SZ_OK : SZ_ERROR_FAIL;
|
||||
free(temp);
|
||||
}
|
||||
|
||||
if (res != SZ_OK)
|
||||
return -1;
|
||||
|
||||
strlcpy(filename, infile, PATH_MAX_LENGTH);
|
||||
|
||||
*cmode = ARCHIVE_MODE_COMPRESSED;
|
||||
*checksum = file->Crc;
|
||||
*size = (uint32_t)file->Size;
|
||||
*csize = (uint32_t)compressed_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
*payback = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_iterate_step(file_archive_transfer_t *state,
|
||||
const char *valid_exts,
|
||||
struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
|
||||
{
|
||||
char filename[PATH_MAX_LENGTH];
|
||||
const uint8_t *cdata = NULL;
|
||||
uint32_t checksum = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t csize = 0;
|
||||
unsigned cmode = 0;
|
||||
unsigned payload = 0;
|
||||
struct sevenzip_context_t *sevenzip_context = NULL;
|
||||
int ret;
|
||||
|
||||
filename[0] = '\0';
|
||||
|
||||
ret = sevenzip_parse_file_iterate_step_internal(state, filename,
|
||||
&cdata, &cmode, &size, &csize,
|
||||
&checksum, &payload, userdata);
|
||||
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
userdata->extracted_file_path = filename;
|
||||
userdata->crc = checksum;
|
||||
|
||||
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
|
||||
csize, size, checksum, userdata))
|
||||
return 0;
|
||||
|
||||
sevenzip_context = (struct sevenzip_context_t*)state->stream;
|
||||
|
||||
sevenzip_context->index += payload;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
return encoding_crc32(crc, data, length);
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend sevenzip_backend = {
|
||||
sevenzip_stream_new,
|
||||
sevenzip_stream_free,
|
||||
sevenzip_stream_decompress_data_to_file_init,
|
||||
sevenzip_stream_decompress_data_to_file_iterate,
|
||||
sevenzip_stream_crc32_calculate,
|
||||
sevenzip_file_read,
|
||||
sevenzip_parse_file_init,
|
||||
sevenzip_parse_file_iterate_step,
|
||||
"7z"
|
||||
};
|
||||
@@ -0,0 +1,384 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file_zlib.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <streams/trans_stream.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/crc32.h>
|
||||
|
||||
/* Only for MAX_WBITS */
|
||||
#include <compat/zlib.h>
|
||||
|
||||
#ifndef CENTRAL_FILE_HEADER_SIGNATURE
|
||||
#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
|
||||
#endif
|
||||
|
||||
#ifndef END_OF_CENTRAL_DIR_SIGNATURE
|
||||
#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
|
||||
#endif
|
||||
|
||||
static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
|
||||
{
|
||||
unsigned i;
|
||||
uint32_t val = 0;
|
||||
|
||||
size *= 8;
|
||||
for (i = 0; i < size; i += 8)
|
||||
val |= (uint32_t)*data++ << i;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void *zlib_stream_new(void)
|
||||
{
|
||||
return zlib_inflate_backend.stream_new();
|
||||
}
|
||||
|
||||
static void zlib_stream_free(void *stream)
|
||||
{
|
||||
zlib_inflate_backend.stream_free(stream);
|
||||
}
|
||||
|
||||
static bool zlib_stream_decompress_data_to_file_init(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize, uint32_t size)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
handle->stream = zlib_inflate_backend.stream_new();
|
||||
|
||||
if (!handle->stream)
|
||||
goto error;
|
||||
|
||||
if (zlib_inflate_backend.define)
|
||||
zlib_inflate_backend.define(handle->stream, "window_bits", (uint32_t)-MAX_WBITS);
|
||||
|
||||
handle->data = (uint8_t*)malloc(size);
|
||||
|
||||
if (!handle->data)
|
||||
goto error;
|
||||
|
||||
zlib_inflate_backend.set_in(handle->stream,
|
||||
(const uint8_t*)cdata, csize);
|
||||
zlib_inflate_backend.set_out(handle->stream,
|
||||
handle->data, size);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
if (handle->stream)
|
||||
zlib_inflate_backend.stream_free(handle->stream);
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int zlib_stream_decompress_data_to_file_iterate(void *stream)
|
||||
{
|
||||
bool zstatus;
|
||||
uint32_t rd, wn;
|
||||
enum trans_stream_error terror;
|
||||
|
||||
if (!stream)
|
||||
return -1;
|
||||
|
||||
zstatus = zlib_inflate_backend.trans(stream, false, &rd, &wn, &terror);
|
||||
|
||||
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
|
||||
return -1;
|
||||
|
||||
if (zstatus && !terror)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
return encoding_crc32(crc, data, length);
|
||||
}
|
||||
|
||||
static bool zip_file_decompressed_handle(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize,
|
||||
uint32_t size, uint32_t crc32)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
handle->backend = &zlib_backend;
|
||||
|
||||
if (!handle->backend->stream_decompress_data_to_file_init(
|
||||
handle, cdata, csize, size))
|
||||
return false;
|
||||
|
||||
do
|
||||
{
|
||||
ret = handle->backend->stream_decompress_data_to_file_iterate(
|
||||
handle->stream);
|
||||
}while(ret == 0);
|
||||
|
||||
#if 0
|
||||
handle->real_checksum = handle->backend->stream_crc_calculate(0,
|
||||
handle->data, size);
|
||||
|
||||
if (handle->real_checksum != crc32)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
if (handle->stream)
|
||||
free(handle->stream);
|
||||
|
||||
return true;
|
||||
#if 0
|
||||
error:
|
||||
if (handle->stream)
|
||||
free(handle->stream);
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
|
||||
handle->stream = NULL;
|
||||
handle->data = NULL;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Extract the relative path (needle) from a
|
||||
* ZIP archive (path) and allocate a buffer for it to write it in.
|
||||
*
|
||||
* optional_outfile if not NULL will be used to extract the file to.
|
||||
* buf will be 0 then.
|
||||
*/
|
||||
|
||||
static int zip_file_decompressed(
|
||||
const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode,
|
||||
uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
/* Ignore directories. */
|
||||
if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\')
|
||||
return 1;
|
||||
|
||||
if (strstr(name, userdata->decomp_state.needle))
|
||||
{
|
||||
bool goto_error = false;
|
||||
file_archive_file_handle_t handle = {0};
|
||||
|
||||
userdata->decomp_state.found = true;
|
||||
|
||||
if (zip_file_decompressed_handle(&handle,
|
||||
cdata, csize, size, crc32))
|
||||
{
|
||||
if (userdata->decomp_state.opt_file != 0)
|
||||
{
|
||||
/* Called in case core has need_fullpath enabled. */
|
||||
char *buf = (char*)malloc(size);
|
||||
|
||||
if (buf)
|
||||
{
|
||||
memcpy(buf, handle.data, size);
|
||||
|
||||
if (!filestream_write_file(userdata->decomp_state.opt_file, buf, size))
|
||||
goto_error = true;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
userdata->decomp_state.size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Called in case core has need_fullpath disabled.
|
||||
* Will copy decompressed content directly into
|
||||
* RetroArch's ROM buffer. */
|
||||
*userdata->decomp_state.buf = malloc(size);
|
||||
memcpy(*userdata->decomp_state.buf, handle.data, size);
|
||||
|
||||
userdata->decomp_state.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle.data)
|
||||
free(handle.data);
|
||||
|
||||
if (goto_error)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zip_file_read(
|
||||
const char *path,
|
||||
const char *needle, void **buf,
|
||||
const char *optional_outfile)
|
||||
{
|
||||
file_archive_transfer_t zlib = {ARCHIVE_TRANSFER_NONE, 0, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
struct archive_extract_userdata userdata = {{0}};
|
||||
bool returnerr = true;
|
||||
int ret = 0;
|
||||
|
||||
zlib.type = ARCHIVE_TRANSFER_INIT;
|
||||
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.found = false;
|
||||
userdata.decomp_state.buf = buf;
|
||||
|
||||
if (needle)
|
||||
userdata.decomp_state.needle = strdup(needle);
|
||||
if (optional_outfile)
|
||||
userdata.decomp_state.opt_file = strdup(optional_outfile);
|
||||
|
||||
do
|
||||
{
|
||||
ret = file_archive_parse_file_iterate(&zlib, &returnerr, path,
|
||||
"", zip_file_decompressed, &userdata);
|
||||
if (!returnerr)
|
||||
break;
|
||||
}while(ret == 0 && !userdata.decomp_state.found);
|
||||
|
||||
file_archive_parse_file_iterate_stop(&zlib);
|
||||
|
||||
if (userdata.decomp_state.opt_file)
|
||||
free(userdata.decomp_state.opt_file);
|
||||
if (userdata.decomp_state.needle)
|
||||
free(userdata.decomp_state.needle);
|
||||
|
||||
if (!userdata.decomp_state.found)
|
||||
return -1;
|
||||
|
||||
return (int)userdata.decomp_state.size;
|
||||
}
|
||||
|
||||
static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
if (state->archive_size < 22)
|
||||
return -1;
|
||||
|
||||
state->footer = state->data + state->archive_size - 22;
|
||||
|
||||
for (;; state->footer--)
|
||||
{
|
||||
if (state->footer <= state->data + 22)
|
||||
return -1;
|
||||
if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
|
||||
{
|
||||
unsigned comment_len = read_le(state->footer + 20, 2);
|
||||
if (state->footer + 22 + comment_len == state->data + state->archive_size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state->directory = state->data + read_le(state->footer + 16, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zip_parse_file_iterate_step_internal(
|
||||
file_archive_transfer_t *state, char *filename,
|
||||
const uint8_t **cdata,
|
||||
unsigned *cmode, uint32_t *size, uint32_t *csize,
|
||||
uint32_t *checksum, unsigned *payback)
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t namelength, extralength, commentlength,
|
||||
offsetNL, offsetEL;
|
||||
uint32_t signature = read_le(state->directory + 0, 4);
|
||||
|
||||
if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
|
||||
return 0;
|
||||
|
||||
*cmode = read_le(state->directory + 10, 2); /* compression mode, 0 = store, 8 = deflate */
|
||||
*checksum = read_le(state->directory + 16, 4); /* CRC32 */
|
||||
*csize = read_le(state->directory + 20, 4); /* compressed size */
|
||||
*size = read_le(state->directory + 24, 4); /* uncompressed size */
|
||||
|
||||
namelength = read_le(state->directory + 28, 2); /* file name length */
|
||||
extralength = read_le(state->directory + 30, 2); /* extra field length */
|
||||
commentlength = read_le(state->directory + 32, 2); /* file comment length */
|
||||
|
||||
if (namelength >= PATH_MAX_LENGTH)
|
||||
return -1;
|
||||
|
||||
memcpy(filename, state->directory + 46, namelength); /* file name */
|
||||
|
||||
offset = read_le(state->directory + 42, 4); /* relative offset of local file header */
|
||||
offsetNL = read_le(state->data + offset + 26, 2); /* file name length */
|
||||
offsetEL = read_le(state->data + offset + 28, 2); /* extra field length */
|
||||
|
||||
*cdata = state->data + offset + 30 + offsetNL + offsetEL;
|
||||
|
||||
*payback = 46 + namelength + extralength + commentlength;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zip_parse_file_iterate_step(file_archive_transfer_t *state,
|
||||
const char *valid_exts, struct archive_extract_userdata *userdata,
|
||||
file_archive_file_cb file_cb)
|
||||
{
|
||||
char filename[PATH_MAX_LENGTH] = {0};
|
||||
const uint8_t *cdata = NULL;
|
||||
uint32_t checksum = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t csize = 0;
|
||||
unsigned cmode = 0;
|
||||
unsigned payload = 0;
|
||||
int ret = zip_parse_file_iterate_step_internal(
|
||||
state, filename, &cdata, &cmode, &size, &csize, &checksum, &payload);
|
||||
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
userdata->extracted_file_path = filename;
|
||||
userdata->crc = checksum;
|
||||
|
||||
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
|
||||
csize, size, checksum, userdata))
|
||||
return 0;
|
||||
|
||||
state->directory += payload;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend zlib_backend = {
|
||||
zlib_stream_new,
|
||||
zlib_stream_free,
|
||||
zlib_stream_decompress_data_to_file_init,
|
||||
zlib_stream_decompress_data_to_file_iterate,
|
||||
zlib_stream_crc32_calculate,
|
||||
zip_file_read,
|
||||
zip_parse_file_init,
|
||||
zip_parse_file_iterate_step,
|
||||
"zlib"
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,149 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (config_file_userdata.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <file/file_path.h>
|
||||
#include <lists/string_list.h>
|
||||
|
||||
#include <file/config_file_userdata.h>
|
||||
|
||||
int config_userdata_get_float(void *userdata, const char *key_str,
|
||||
float *value, float default_value)
|
||||
{
|
||||
bool got;
|
||||
char key[2][256];
|
||||
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||
|
||||
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||
|
||||
got = config_get_float (usr->conf, key[0], value);
|
||||
got = got || config_get_float(usr->conf, key[1], value);
|
||||
|
||||
if (!got)
|
||||
*value = default_value;
|
||||
return got;
|
||||
}
|
||||
|
||||
int config_userdata_get_int(void *userdata, const char *key_str,
|
||||
int *value, int default_value)
|
||||
{
|
||||
bool got;
|
||||
char key[2][256];
|
||||
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||
|
||||
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||
|
||||
got = config_get_int (usr->conf, key[0], value);
|
||||
got = got || config_get_int(usr->conf, key[1], value);
|
||||
|
||||
if (!got)
|
||||
*value = default_value;
|
||||
return got;
|
||||
}
|
||||
|
||||
int config_userdata_get_float_array(void *userdata, const char *key_str,
|
||||
float **values, unsigned *out_num_values,
|
||||
const float *default_values, unsigned num_default_values)
|
||||
{
|
||||
char key[2][256];
|
||||
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||
char *str = NULL;
|
||||
|
||||
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||
|
||||
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||
config_get_string(usr->conf, key[1], &str))
|
||||
{
|
||||
unsigned i;
|
||||
struct string_list *list = string_split(str, " ");
|
||||
*values = (float*)calloc(list->size, sizeof(float));
|
||||
for (i = 0; i < list->size; i++)
|
||||
(*values)[i] = (float)strtod(list->elems[i].data, NULL);
|
||||
*out_num_values = (unsigned)list->size;
|
||||
string_list_free(list);
|
||||
free(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
*values = (float*)calloc(num_default_values, sizeof(float));
|
||||
memcpy(*values, default_values, sizeof(float) * num_default_values);
|
||||
*out_num_values = num_default_values;
|
||||
return false;
|
||||
}
|
||||
|
||||
int config_userdata_get_int_array(void *userdata, const char *key_str,
|
||||
int **values, unsigned *out_num_values,
|
||||
const int *default_values, unsigned num_default_values)
|
||||
{
|
||||
char key[2][256];
|
||||
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||
char *str = NULL;
|
||||
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||
|
||||
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||
config_get_string(usr->conf, key[1], &str))
|
||||
{
|
||||
unsigned i;
|
||||
struct string_list *list = string_split(str, " ");
|
||||
*values = (int*)calloc(list->size, sizeof(int));
|
||||
for (i = 0; i < list->size; i++)
|
||||
(*values)[i] = (int)strtod(list->elems[i].data, NULL);
|
||||
*out_num_values = (unsigned)list->size;
|
||||
string_list_free(list);
|
||||
free(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
*values = (int*)calloc(num_default_values, sizeof(int));
|
||||
memcpy(*values, default_values, sizeof(int) * num_default_values);
|
||||
*out_num_values = num_default_values;
|
||||
return false;
|
||||
}
|
||||
|
||||
int config_userdata_get_string(void *userdata, const char *key_str,
|
||||
char **output, const char *default_output)
|
||||
{
|
||||
char key[2][256];
|
||||
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||
char *str = NULL;
|
||||
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||
|
||||
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||
config_get_string(usr->conf, key[1], &str))
|
||||
{
|
||||
*output = str;
|
||||
return true;
|
||||
}
|
||||
|
||||
*output = strdup(default_output);
|
||||
return false;
|
||||
}
|
||||
|
||||
void config_userdata_free(void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free(ptr);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 354 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user