diff --git a/Frameworks/OpenMPT/OpenMPT/Makefile b/Frameworks/OpenMPT/OpenMPT/Makefile index ade92a694..e8c76f76b 100644 --- a/Frameworks/OpenMPT/OpenMPT/Makefile +++ b/Frameworks/OpenMPT/OpenMPT/Makefile @@ -14,7 +14,7 @@ # # Build configuration (provide on each `make` invocation): # -# CONFIG=[gcc|clang|mingw64-win32|mingw64-win64|emscripten|emscripten-old] (default: CONFIG=) +# CONFIG=[gcc|clang|mingw-w64|emscripten|djgpp] (default: CONFIG=) # # Build configurations can override or change defaults of other build options. # See below and in `build/make/` for details. @@ -42,24 +42,35 @@ # # Build flags (provide on each `make` invocation) (defaults are shown): # -# DYNLINK=1 Dynamically link examples and openmpt123 against libopenmpt -# SHARED_LIB=1 Build shared library -# STATIC_LIB=1 Build static library -# EXAMPLES=1 Build examples -# OPENMPT123=1 Build openmpt123 -# IN_OPENMPT=0 Build in_openmpt (WinAMP 2.x plugin) -# XMP_OPENMPT=0 Build xmp-openmpt (XMPlay plugin) -# SHARED_SONAME=1 Set SONAME of shared library -# DEBUG=0 Build debug binaries without optimization and with symbols -# OPTIMIZE=1 Build optimized binaries -# OPTIMIZE_SIZE=0 Build size-optimized binaries -# OPTIMIZE_LTO=0 Build with link-time-optimizations -# TEST=1 Include test suite in default target. -# ONLY_TEST=0 Only build the test suite. -# STRICT=0 Treat warnings as errors. -# MODERN=0 Pass more modern compiler options. -# STDCXX=c++17 C++ standard version (only for GCC and clang) -# CHECKED=0 Enable run-time assertions. +# DYNLINK=1 Dynamically link examples and openmpt123 against libopenmpt +# SHARED_LIB=1 Build shared library +# STATIC_LIB=1 Build static library +# EXAMPLES=1 Build examples +# OPENMPT123=1 Build openmpt123 +# IN_OPENMPT=0 Build in_openmpt (WinAMP 2.x plugin) +# XMP_OPENMPT=0 Build xmp-openmpt (XMPlay plugin) +# SHARED_SONAME=1 Set SONAME of shared library +# DEBUG=0 Build debug binaries without optimization and with symbols +# OPTIMIZE=vectorize -O3 +# speed -O2 +# size -Os/-Oz +# test -Og +# debug -O0 +# none +# OPTIMIZE_LTO=0 Build with link-time-optimizations +# OPTIMIZE_FASTMATH=0 Use no non-standard-compliant fastmath optimizations +# =1 + use mild non-standard-compliant fastmath optimizations +# =2 + assume no inf/nan +# =3 + set ftz/daz +# TEST=1 Include test suite in default target. +# ONLY_TEST=0 Only build the test suite. +# STRICT=0 Treat warnings as errors. +# MODERN=0 Pass more modern compiler options. +# NATIVE=0 Optimize for system CPU. +# STDCXX=c++17 C++ standard version (default depends on compiler) +# STDC=c17 C standard version (default depends on compiler) +# ANALYZE=0 Enable static analyzer. +# CHECKED=0 Enable run-time assertions. # CHECKED_ADDRESS=0 Enable address sanitizer # CHECKED_UNDEFINED=0 Enable undefined behaviour sanitizer # @@ -83,7 +94,6 @@ # NO_STBVORBIS=1 Do not fallback to stb_vorbis # # USE_ALLEGRO42=1 Use liballegro 4.2 (DJGPP only) -# BUNDLED_ALLEGRO42=1 Use liballegro 4.2 in libopenmpt source tree (DJGPP only) # # Build flags for libopenmpt examples and openmpt123 # (provide on each `make` invocation) @@ -164,9 +174,9 @@ EXAMPLES=1 FUZZ=0 SHARED_SONAME=1 DEBUG=0 -OPTIMIZE=1 -OPTIMIZE_SIZE=0 +OPTIMIZE=vectorize OPTIMIZE_LTO=0 +OPTIMIZE_FASTMATH=0 TEST=1 ONLY_TEST=0 SOSUFFIX=.so @@ -176,8 +186,11 @@ OPENMPT123=1 IN_OPENMPT=0 XMP_OPENMPT=0 MODERN=0 +NATIVE=0 STRICT=0 +FLAVOUR_DIR= + FORCE_UNIX_STYLE_COMMANDS=0 CHECKED=0 @@ -283,6 +296,9 @@ endif ifeq ($(UNAME_S),Linux) HOST_FLAVOUR=LINUX endif +ifeq ($(UNAME_S),NetBSD) +HOST_FLAVOUR=NETBSD +endif ifeq ($(UNAME_S),FreeBSD) HOST_FLAVOUR=FREEBSD endif @@ -312,11 +328,37 @@ BINDIR_MADE:=$(shell $(MKDIR_P) bin) PKG_CONFIG ?= pkg-config ifeq ($(CONFIG)x,x) - include build/make/config-defaults.mk -else +else ifeq ($(CONFIG),mingw64-win32) +$(warning warning: 'CONFIG=mingw64-win32' is deprecated. Use 'CONFIG=mingw-w64 WINDOWS_ARCH=x86' instead.) +WINDOWS_ARCH=x86 +WINDOWS_FAMILY= +WINDOWS_VERSION= +include build/make/config-mingw-w64.mk +else ifeq ($(CONFIG),mingw64-win64) +$(warning warning: 'CONFIG=mingw64-win64' is deprecated. Use 'CONFIG=mingw-w64 WINDOWS_ARCH=amd64' instead.) +WINDOWS_ARCH=amd64 +WINDOWS_FAMILY= +WINDOWS_VERSION= +include build/make/config-mingw-w64.mk + +else ifeq ($(CONFIG),mingw64-winrt-x86) +$(warning warning: 'CONFIG=mingw64-winrt-x86' is deprecated. Use 'CONFIG=mingw-w64 WINDOWS_ARCH=x86 WINDOWS_FAMILY=pc-app WINDOWS_VERSION=win8' instead.) +WINDOWS_ARCH=x86 +WINDOWS_FAMILY=pc-app +WINDOWS_VERSION=win8 +include build/make/config-mingw-w64.mk + +else ifeq ($(CONFIG),mingw64-winrt-amd64) +$(warning warning: 'CONFIG=mingw64-winrt-amd64' is deprecated. Use 'CONFIG=mingw-w64 WINDOWS_ARCH=amd64 WINDOWS_FAMILY=pc-app WINDOWS_VERSION=win8' instead.) +WINDOWS_ARCH=amd64 +WINDOWS_FAMILY=pc-app +WINDOWS_VERSION=win8 +include build/make/config-mingw-w64.mk + +else include build/make/config-$(CONFIG).mk endif @@ -362,7 +404,7 @@ CPPFLAGS += -DMPT_BUILD_DEBUG CXXFLAGS += -g CFLAGS += -g else -ifeq ($(OPTIMIZE),1) +ifneq ($(OPTIMIZE),none) CXXFLAGS += -O CFLAGS += -O endif @@ -392,25 +434,183 @@ ARFLAGS += ifeq ($(DEBUG),1) CPPFLAGS += -DMPT_BUILD_DEBUG -CXXFLAGS += -O0 -g -fno-omit-frame-pointer -CFLAGS += -O0 -g -fno-omit-frame-pointer -else -ifeq ($(OPTIMIZE_SIZE),1) +CXXFLAGS += -g +CFLAGS += -g +else ifeq ($(OPTIMIZE),debug) +CPPFLAGS += +CXXFLAGS += -O0 -fno-omit-frame-pointer +CFLAGS += -O0 -fno-omit-frame-pointer +else ifeq ($(OPTIMIZE),test) +CPPFLAGS += +CXXFLAGS += -Og -fno-omit-frame-pointer +CFLAGS += -Og -fno-omit-frame-pointer +else ifeq ($(OPTIMIZE),size) CXXFLAGS += -Os CFLAGS += -Os -fno-strict-aliasing LDFLAGS += -ifeq ($(MPT_COMPILER_NOGCSECTIONS),1) -else +ifneq ($(MPT_COMPILER_NOSECTIONS),1) CXXFLAGS += -ffunction-sections -fdata-sections CFLAGS += -ffunction-sections -fdata-sections +endif +ifneq ($(MPT_COMPILER_NOGCSECTIONS),1) LDFLAGS += -Wl,--gc-sections endif -else -ifeq ($(OPTIMIZE),1) +else ifeq ($(OPTIMIZE),speed) +CXXFLAGS += -O2 +CFLAGS += -O2 -fno-strict-aliasing +ifneq ($(MPT_COMPILER_NOSECTIONS),1) +CXXFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -ffunction-sections -fdata-sections +endif +ifneq ($(MPT_COMPILER_NOGCSECTIONS),1) +LDFLAGS += -Wl,--gc-sections +endif +else ifeq ($(OPTIMIZE),vectorize) CXXFLAGS += -O3 CFLAGS += -O3 -fno-strict-aliasing +ifneq ($(MPT_COMPILER_NOSECTIONS),1) +CXXFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -ffunction-sections -fdata-sections +endif +ifneq ($(MPT_COMPILER_NOGCSECTIONS),1) +LDFLAGS += -Wl,--gc-sections endif endif + +ifeq ($(FASTMATH_STYLE),gcc) + +ifeq ($(OPTIMIZE_FASTMATH),3) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +else ifeq ($(OPTIMIZE_FASTMATH),2) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -fno-math-errno +CXXFLAGS += -ffinite-math-only +CXXFLAGS += -fno-rounding-math +CXXFLAGS += -fno-signaling-nans +CXXFLAGS += -fexcess-precision=fast +CXXFLAGS += -fcx-limited-range +CXXFLAGS += -fassociative-math +CXXFLAGS += -freciprocal-math +CXXFLAGS += -fno-signed-zeros +CXXFLAGS += -fno-trapping-math +CFLAGS += -fno-math-errno +CFLAGS += -ffinite-math-only +CFLAGS += -fno-rounding-math +CFLAGS += -fno-signaling-nans +CFLAGS += -fexcess-precision=fast +CFLAGS += -fcx-limited-range +CFLAGS += -fassociative-math +CFLAGS += -freciprocal-math +CFLAGS += -fno-signed-zeros +CFLAGS += -fno-trapping-math +else ifeq ($(OPTIMIZE_FASTMATH),1) +CXXFLAGS += -fno-math-errno +CXXFLAGS += -fno-rounding-math +CXXFLAGS += -fno-signaling-nans +CXXFLAGS += -fexcess-precision=fast +CXXFLAGS += -fcx-limited-range +CXXFLAGS += -fassociative-math +CXXFLAGS += -freciprocal-math +CXXFLAGS += -fno-signed-zeros +CXXFLAGS += -fno-trapping-math +CFLAGS += -fno-math-errno +CFLAGS += -fno-rounding-math +CFLAGS += -fno-signaling-nans +CFLAGS += -fexcess-precision=fast +CFLAGS += -fcx-limited-range +CFLAGS += -fassociative-math +CFLAGS += -freciprocal-math +CFLAGS += -fno-signed-zeros +CFLAGS += -fno-trapping-math +endif + +else ifeq ($(FASTMATH_STYLE),clang) + +ifeq ($(OPTIMIZE_FASTMATH),3) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +else ifeq ($(OPTIMIZE_FASTMATH),2) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -fno-math-errno +CXXFLAGS += -ffinite-math-only +CXXFLAGS += -fno-honor-infinities +CXXFLAGS += -fno-honor-nans +CXXFLAGS += -ffp-contract=fast +CXXFLAGS += -fassociative-math +CXXFLAGS += -freciprocal-math +CXXFLAGS += -fno-signed-zeros +CXXFLAGS += -fno-trapping-math +CFLAGS += -fno-math-errno +CFLAGS += -ffinite-math-only +CFLAGS += -fno-honor-infinities +CFLAGS += -fno-honor-nans +CFLAGS += -ffp-contract=fast +CFLAGS += -fassociative-math +CFLAGS += -freciprocal-math +CFLAGS += -fno-signed-zeros +CFLAGS += -fno-trapping-math +else ifeq ($(OPTIMIZE_FASTMATH),1) +CXXFLAGS += -fno-math-errno +CXXFLAGS += -ffp-contract=fast +CXXFLAGS += -fassociative-math +CXXFLAGS += -freciprocal-math +CXXFLAGS += -fno-signed-zeros +CXXFLAGS += -fno-trapping-math +CFLAGS += -fno-math-errno +CFLAGS += -ffp-contract=fast +CFLAGS += -fassociative-math +CFLAGS += -freciprocal-math +CFLAGS += -fno-signed-zeros +CFLAGS += -fno-trapping-math +endif + +else + +ifeq ($(OPTIMIZE_FASTMATH),3) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +else ifeq ($(OPTIMIZE_FASTMATH),2) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +else ifeq ($(OPTIMIZE_FASTMATH),1) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +endif + +endif + +ifeq ($(OPTIMIZE_FASTMATH),2) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FASTMATH -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -ffast-math +CFLAGS += -ffast-math +else ifeq ($(OPTIMIZE_FASTMATH),1) +CPPFLAGS += -DMPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +CXXFLAGS += -fassociative-math +CXXFLAGS += -fcx-limited-range +CXXFLAGS += -fexcess-precision=fast +CXXFLAGS += -ffinite-math-only +CXXFLAGS += -freciprocal-math +CXXFLAGS += -fno-math-errno +CXXFLAGS += -fno-rounding-math +CXXFLAGS += -fno-signaling-nans +CXXFLAGS += -fno-signed-zeros +CXXFLAGS += -fno-trapping-math +CFLAGS += -fassociative-math +CFLAGS += -fcx-limited-range +CFLAGS += -fexcess-precision=fast +CFLAGS += -ffinite-math-only +CFLAGS += -freciprocal-math +CFLAGS += -fno-math-errno +CFLAGS += -fno-rounding-math +CFLAGS += -fno-signaling-nans +CFLAGS += -fno-signed-zeros +CFLAGS += -fno-trapping-math endif ifeq ($(CHECKED),1) @@ -484,8 +684,8 @@ LOCAL_ZLIB_SOURCES += include/zlib/inftrees.c LOCAL_ZLIB_SOURCES += include/zlib/trees.c LOCAL_ZLIB_SOURCES += include/zlib/uncompr.c LOCAL_ZLIB_SOURCES += include/zlib/zutil.c -include/zlib/%.o : CFLAGS+=$(CFLAGS_SILENT) -DSTDC -DZ_HAVE_UNISTD_H -include/zlib/%.test.o : CFLAGS+=$(CFLAGS_SILENT) -DSTDC -DZ_HAVE_UNISTD_H +include/zlib/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DSTDC -DZ_HAVE_UNISTD_H +include/zlib/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DSTDC -DZ_HAVE_UNISTD_H else ifeq ($(NO_ZLIB),1) else @@ -537,10 +737,10 @@ LOCAL_MPG123_SOURCES += include/mpg123/src/libmpg123/synth_8bit.c LOCAL_MPG123_SOURCES += include/mpg123/src/libmpg123/synth_real.c LOCAL_MPG123_SOURCES += include/mpg123/src/libmpg123/synth_s32.c LOCAL_MPG123_SOURCES += include/mpg123/src/libmpg123/tabinit.c -include/mpg123/src/compat/%.o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC -include/mpg123/src/compat/%.test.o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC -include/mpg123/src/libmpg123/%.o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC -include/mpg123/src/libmpg123/%.test.o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC +include/mpg123/src/compat/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC +include/mpg123/src/compat/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC +include/mpg123/src/libmpg123/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC +include/mpg123/src/libmpg123/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) -DOPT_GENERIC else ifeq ($(NO_MPG123),1) else @@ -569,8 +769,8 @@ CPPFLAGS_OGG += -Iinclude/ogg/include/ -Iinclude/ogg/ports/makefile/ LOCAL_OGG_SOURCES := LOCAL_OGG_SOURCES += include/ogg/src/bitwise.c LOCAL_OGG_SOURCES += include/ogg/src/framing.c -include/ogg/src/%.o : CFLAGS+=$(CFLAGS_SILENT) -include/ogg/src/%.test.o : CFLAGS+=$(CFLAGS_SILENT) +include/ogg/src/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) +include/ogg/src/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) else ifeq ($(NO_OGG),1) else @@ -619,8 +819,8 @@ LOCAL_VORBIS_SOURCES += include/vorbis/lib/synthesis.c LOCAL_VORBIS_SOURCES += include/vorbis/lib/vorbisenc.c LOCAL_VORBIS_SOURCES += include/vorbis/lib/vorbisfile.c LOCAL_VORBIS_SOURCES += include/vorbis/lib/window.c -include/vorbis/lib/%.o : CFLAGS+=$(CFLAGS_SILENT) -include/vorbis/lib/%.test.o : CFLAGS+=$(CFLAGS_SILENT) +include/vorbis/lib/%$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) +include/vorbis/lib/%.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) else ifeq ($(NO_VORBIS),1) else @@ -768,18 +968,27 @@ endif endif ifeq ($(USE_ALLEGRO42),1) -CPPFLAGS_ALLEGRO42 ?= -LDFLAGS_ALLEGRO42 ?= -LDLIBS_ALLEGRO42 ?= liballeg.a -CPPFLAGS_ALLEGRO42 += -DMPT_WITH_ALLEGRO42 + +CPPFLAGS_ALLEGRO42 := -Iinclude/allegro42/include -DALLEGRO_HAVE_STDINT_H -DLONG_LONG="long long" -DMPT_WITH_ALLEGRO42 +LDFLAGS_ALLEGRO42 := +LDLIBS_ALLEGRO42 := include/allegro42/lib/djgpp/liballeg.a +DEPS_ALLEGRO42 := include/allegro42/lib/djgpp/liballeg.a + +include/allegro42/lib/djgpp/liballeg.a: + +cd include/allegro42 && ./xmake.sh clean + +cd include/allegro42 && ./xmake.sh lib + +MISC_OUTPUTS += include/allegro42/lib/djgpp/liballeg.a + endif + ifeq ($(HACK_ARCHIVE_SUPPORT),1) CPPFLAGS += -DMPT_BUILD_HACK_ARCHIVE_SUPPORT endif CPPCHECK_FLAGS += -j $(NUMTHREADS) -CPPCHECK_FLAGS += --std=c99 --std=c++17 +CPPCHECK_FLAGS += --std=c11 --std=c++17 CPPCHECK_FLAGS += --quiet CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]' CPPCHECK_FLAGS += --suppress=missingIncludeSystem @@ -795,28 +1004,28 @@ LDFLAGS_OPENMPT123 += $(LDFLAGS_SDL2) $(LDFLAGS_PORTAUDIO) $(LDFLAGS_PULSEAUDIO LDLIBS_OPENMPT123 += $(LDLIBS_SDL2) $(LDLIBS_PORTAUDIO) $(LDLIBS_PULSEAUDIO) $(LDLIBS_FLAC) $(LDLIBS_SNDFILE) $(LDLIBS_ALLEGRO42) -%: %.o +%: %$(FLAVOUR_O).o $(INFO) [LD] $@ $(SILENT)$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@ -%.o: %.cpp +%$(FLAVOUR_O).o: %.cpp $(INFO) [CXX] $< - $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.cc) $(OUTPUT_OPTION) $< -%.o: %.c +%$(FLAVOUR_O).o: %.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(OUTPUT_OPTION) $< -%.test.o: %.cpp +%.test$(FLAVOUR_O).o: %.cpp $(INFO) [CXX-TEST] $< - $(VERYSILENT)$(CXX) -DLIBOPENMPT_BUILD_TEST $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.test.d + $(VERYSILENT)$(CXX) -DLIBOPENMPT_BUILD_TEST $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.test$(FLAVOUR_O).d $(SILENT)$(COMPILE.cc) -DLIBOPENMPT_BUILD_TEST $(OUTPUT_OPTION) $< -%.test.o: %.c +%.test$(FLAVOUR_O).o: %.c $(INFO) [CC-TEST] $< - $(VERYSILENT)$(CC) -DLIBOPENMPT_BUILD_TEST $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.test.d + $(VERYSILENT)$(CC) -DLIBOPENMPT_BUILD_TEST $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.test$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) -DLIBOPENMPT_BUILD_TEST $(OUTPUT_OPTION) $< %.tar.gz: %.tar @@ -826,7 +1035,6 @@ LDLIBS_OPENMPT123 += $(LDLIBS_SDL2) $(LDLIBS_PORTAUDIO) $(LDLIBS_PULSEAUDIO) $ -include build/dist.mk DIST_LIBOPENMPT_VERSION_PURE:=$(LIBOPENMPT_VERSION_MAJOR).$(LIBOPENMPT_VERSION_MINOR).$(LIBOPENMPT_VERSION_PATCH)$(LIBOPENMPT_VERSION_PREREL) -CPPFLAGS += -Ibuild/svn_version ifeq ($(MPT_SVNVERSION),) SVN_INFO:=$(shell svn info . > /dev/null 2>&1 ; echo $$? ) ifeq ($(SVN_INFO),0) @@ -905,13 +1113,10 @@ endif LIBOPENMPT_CXX_SOURCES += \ $(SOUNDLIB_CXX_SOURCES) \ - libopenmpt/libopenmpt_c.cpp \ - libopenmpt/libopenmpt_cxx.cpp \ - libopenmpt/libopenmpt_impl.cpp \ - libopenmpt/libopenmpt_ext_impl.cpp \ + $(sort $(wildcard libopenmpt/*.cpp)) \ -include/miniz/miniz.o : CFLAGS+=$(CFLAGS_SILENT) -include/miniz/miniz.test.o : CFLAGS+=$(CFLAGS_SILENT) +include/miniz/miniz$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) +include/miniz/miniz.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) ifeq ($(LOCAL_ZLIB),1) LIBOPENMPT_C_SOURCES += $(LOCAL_ZLIB_SOURCES) LIBOPENMPTTEST_C_SOURCES += $(LOCAL_ZLIB_SOURCES) @@ -927,8 +1132,8 @@ endif endif endif -include/minimp3/minimp3.o : CFLAGS+=$(CFLAGS_SILENT) -include/minimp3/minimp3.test.o : CFLAGS+=$(CFLAGS_SILENT) +include/minimp3/minimp3$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) +include/minimp3/minimp3.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) ifeq ($(LOCAL_MPG123),1) LIBOPENMPT_C_SOURCES += $(LOCAL_MPG123_SOURCES) LIBOPENMPTTEST_C_SOURCES += $(LOCAL_MPG123_SOURCES) @@ -944,8 +1149,8 @@ endif endif endif -include/stb_vorbis/stb_vorbis.o : CFLAGS+=$(CFLAGS_SILENT) -include/stb_vorbis/stb_vorbis.test.o : CFLAGS+=$(CFLAGS_SILENT) +include/stb_vorbis/stb_vorbis$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) +include/stb_vorbis/stb_vorbis.test$(FLAVOUR_O).o : CFLAGS+=$(CFLAGS_SILENT) ifeq ($(LOCAL_VORBIS),1) ifeq ($(LOCAL_OGG),1) LIBOPENMPT_C_SOURCES += $(LOCAL_OGG_SOURCES) @@ -986,37 +1191,37 @@ endif endif endif -LIBOPENMPT_OBJECTS += $(LIBOPENMPT_CXX_SOURCES:.cpp=.o) $(LIBOPENMPT_C_SOURCES:.c=.o) -LIBOPENMPT_DEPENDS = $(LIBOPENMPT_OBJECTS:.o=.d) +LIBOPENMPT_OBJECTS += $(LIBOPENMPT_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) $(LIBOPENMPT_C_SOURCES:.c=$(FLAVOUR_O).o) +LIBOPENMPT_DEPENDS = $(LIBOPENMPT_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(LIBOPENMPT_OBJECTS) ALL_DEPENDS += $(LIBOPENMPT_DEPENDS) ifeq ($(DYNLINK),1) -OUTPUT_LIBOPENMPT += bin/libopenmpt$(SOSUFFIX) +OUTPUT_LIBOPENMPT += bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) else OBJECTS_LIBOPENMPT += $(LIBOPENMPT_OBJECTS) endif INOPENMPT_CXX_SOURCES += \ - libopenmpt/libopenmpt_plugin_gui.cpp \ - libopenmpt/in_openmpt.cpp \ + libopenmpt/plugin-common/libopenmpt_plugin_gui.cpp \ + libopenmpt/in_openmpt/in_openmpt.cpp \ -INOPENMPT_OBJECTS += $(INOPENMPT_CXX_SOURCES:.cpp=.o) $(INOPENMPT_C_SOURCES:.c=.o) -INOPENMPT_DEPENDS = $(INOPENMPT_OBJECTS:.o=.d) +INOPENMPT_OBJECTS += $(INOPENMPT_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) $(INOPENMPT_C_SOURCES:.c=$(FLAVOUR_O).o) +INOPENMPT_DEPENDS = $(INOPENMPT_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(INOPENMPT_OBJECTS) ALL_DEPENDS += $(INOPENMPT_DEPENDS) XMPOPENMPT_CXX_SOURCES += \ include/pugixml/src/pugixml.cpp \ - libopenmpt/libopenmpt_plugin_gui.cpp \ - libopenmpt/xmp-openmpt.cpp \ + libopenmpt/plugin-common/libopenmpt_plugin_gui.cpp \ + libopenmpt/xmp-openmpt/xmp-openmpt.cpp \ -XMPOPENMPT_OBJECTS += $(XMPOPENMPT_CXX_SOURCES:.cpp=.o) $(XMPOPENMPT_C_SOURCES:.c=.o) -XMPOPENMPT_DEPENDS = $(XMPOPENMPT_OBJECTS:.o=.d) +XMPOPENMPT_OBJECTS += $(XMPOPENMPT_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) $(XMPOPENMPT_C_SOURCES:.c=$(FLAVOUR_O).o) +XMPOPENMPT_DEPENDS = $(XMPOPENMPT_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(XMPOPENMPT_OBJECTS) ALL_DEPENDS += $(XMPOPENMPT_DEPENDS) @@ -1024,14 +1229,17 @@ ALL_DEPENDS += $(XMPOPENMPT_DEPENDS) OPENMPT123_CXX_SOURCES += \ $(sort $(wildcard openmpt123/*.cpp)) \ -OPENMPT123_OBJECTS += $(OPENMPT123_CXX_SOURCES:.cpp=.o) -OPENMPT123_DEPENDS = $(OPENMPT123_OBJECTS:.o=.d) +OPENMPT123_C_SOURCES += \ + $(sort $(wildcard openmpt123/*.c)) \ + +OPENMPT123_OBJECTS += $(OPENMPT123_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) $(OPENMPT123_C_SOURCES:.c=$(FLAVOUR_O).o) +OPENMPT123_DEPENDS = $(OPENMPT123_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(OPENMPT123_OBJECTS) ALL_DEPENDS += $(OPENMPT123_DEPENDS) LIBOPENMPTTEST_CXX_SOURCES += \ - libopenmpt/libopenmpt_test.cpp \ + test/libopenmpt_test.cpp \ $(SOUNDLIB_CXX_SOURCES) \ test/mpt_tests_base.cpp \ test/mpt_tests_binary.cpp \ @@ -1050,8 +1258,10 @@ LIBOPENMPTTEST_CXX_SOURCES += \ # test/mpt_tests_crypto.cpp \ # test/mpt_tests_uuid_namespace.cpp \ -LIBOPENMPTTEST_OBJECTS = $(LIBOPENMPTTEST_CXX_SOURCES:.cpp=.test.o) $(LIBOPENMPTTEST_C_SOURCES:.c=.test.o) -LIBOPENMPTTEST_DEPENDS = $(LIBOPENMPTTEST_CXX_SOURCES:.cpp=.test.d) $(LIBOPENMPTTEST_C_SOURCES:.c=.test.d) +LIBOPENMPTTEST_C_SOURCES += \ + +LIBOPENMPTTEST_OBJECTS = $(LIBOPENMPTTEST_CXX_SOURCES:.cpp=.test$(FLAVOUR_O).o) $(LIBOPENMPTTEST_C_SOURCES:.c=.test$(FLAVOUR_O).o) +LIBOPENMPTTEST_DEPENDS = $(LIBOPENMPTTEST_CXX_SOURCES:.cpp=.test$(FLAVOUR_O).d) $(LIBOPENMPTTEST_C_SOURCES:.c=.test$(FLAVOUR_O).d) ALL_OBJECTS += $(LIBOPENMPTTEST_OBJECTS) ALL_DEPENDS += $(LIBOPENMPTTEST_DEPENDS) @@ -1059,9 +1269,9 @@ ALL_DEPENDS += $(LIBOPENMPTTEST_DEPENDS) EXAMPLES_CXX_SOURCES += $(sort $(wildcard examples/*.cpp)) EXAMPLES_C_SOURCES += $(sort $(wildcard examples/*.c)) -EXAMPLES_OBJECTS += $(EXAMPLES_CXX_SOURCES:.cpp=.o) -EXAMPLES_OBJECTS += $(EXAMPLES_C_SOURCES:.c=.o) -EXAMPLES_DEPENDS = $(EXAMPLES_OBJECTS:.o=.d) +EXAMPLES_OBJECTS += $(EXAMPLES_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) +EXAMPLES_OBJECTS += $(EXAMPLES_C_SOURCES:.c=$(FLAVOUR_O).o) +EXAMPLES_DEPENDS = $(EXAMPLES_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(EXAMPLES_OBJECTS) ALL_DEPENDS += $(EXAMPLES_DEPENDS) @@ -1069,9 +1279,9 @@ ALL_DEPENDS += $(EXAMPLES_DEPENDS) FUZZ_CXX_SOURCES += $(sort $(wildcard contrib/fuzzing/*.cpp)) FUZZ_C_SOURCES += $(sort $(wildcard contrib/fuzzing/*.c)) -FUZZ_OBJECTS += $(FUZZ_CXX_SOURCES:.cpp=.o) -FUZZ_OBJECTS += $(FUZZ_C_SOURCES:.c=.o) -FUZZ_DEPENDS = $(FUZZ_OBJECTS:.o=.d) +FUZZ_OBJECTS += $(FUZZ_CXX_SOURCES:.cpp=$(FLAVOUR_O).o) +FUZZ_OBJECTS += $(FUZZ_C_SOURCES:.c=$(FLAVOUR_O).o) +FUZZ_DEPENDS = $(FUZZ_OBJECTS:$(FLAVOUR_O).o=$(FLAVOUR_O).d) ALL_OBJECTS += $(FUZZ_OBJECTS) ALL_DEPENDS += $(FUZZ_DEPENDS) @@ -1082,139 +1292,139 @@ all: -include $(ALL_DEPENDS) ifeq ($(DYNLINK),1) -OUTPUTS += bin/libopenmpt$(SOSUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) endif ifeq ($(SHARED_LIB),1) -OUTPUTS += bin/libopenmpt$(SOSUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) endif ifeq ($(STATIC_LIB),1) -OUTPUTS += bin/libopenmpt.a +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt.a endif ifeq ($(IN_OPENMPT),1) -OUTPUTS += bin/in_openmpt$(SOSUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)in_openmpt$(SOSUFFIX) endif ifeq ($(XMP_OPENMPT),1) -OUTPUTS += bin/xmp-openmpt$(SOSUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)xmp-openmpt$(SOSUFFIX) endif ifeq ($(OPENMPT123),1) -OUTPUTS += bin/openmpt123$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX) endif ifeq ($(EXAMPLES),1) ifeq ($(NO_PORTAUDIO),1) else -OUTPUTS += bin/libopenmpt_example_c$(EXESUFFIX) -OUTPUTS += bin/libopenmpt_example_c_mem$(EXESUFFIX) -OUTPUTS += bin/libopenmpt_example_c_unsafe$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe$(EXESUFFIX) endif ifeq ($(NO_PORTAUDIOCPP),1) else -OUTPUTS += bin/libopenmpt_example_cxx$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_cxx$(EXESUFFIX) endif -OUTPUTS += bin/libopenmpt_example_c_pipe$(EXESUFFIX) -OUTPUTS += bin/libopenmpt_example_c_stdout$(EXESUFFIX) -OUTPUTS += bin/libopenmpt_example_c_probe$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe$(EXESUFFIX) endif ifeq ($(FUZZ),1) -OUTPUTS += bin/fuzz$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)fuzz$(EXESUFFIX) endif ifeq ($(TEST),1) -OUTPUTS += bin/libopenmpt_test$(EXESUFFIX) +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX) endif ifeq ($(HOST),unix) -OUTPUTS += bin/libopenmpt.pc +OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt.pc endif ifeq ($(OPENMPT123),1) ifeq ($(MPT_WITH_HELP2MAN),1) -OUTPUTS += bin/openmpt123.1 +OUTPUTS += bin/$(FLAVOUR_DIR)openmpt123.1 endif endif ifeq ($(SHARED_SONAME),1) LIBOPENMPT_LDFLAGS += -Wl,-soname,$(LIBOPENMPT_SONAME) endif -MISC_OUTPUTS += bin/empty.cpp -MISC_OUTPUTS += bin/empty.out -MISC_OUTPUTS += bin/openmpt123$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c_mem$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c_probe$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_cxx$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c_pipe$(EXESUFFIX).norpath -MISC_OUTPUTS += bin/libopenmpt_example_c_stdout$(EXESUFFIX).norpath -MISC_OUTPUTS += libopenmpt$(SOSUFFIX) -MISC_OUTPUTS += bin/.docs -MISC_OUTPUTS += bin/libopenmpt_test$(EXESUFFIX) -MISC_OUTPUTS += bin/libopenmpt_test.wasm -MISC_OUTPUTS += bin/libopenmpt_test.wasm.js -MISC_OUTPUTS += bin/libopenmpt_test.js.mem -MISC_OUTPUTS += bin/made.docs -MISC_OUTPUTS += bin/$(LIBOPENMPT_SONAME) -MISC_OUTPUTS += bin/libopenmpt.wasm -MISC_OUTPUTS += bin/libopenmpt.wasm.js -MISC_OUTPUTS += bin/libopenmpt.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c_mem.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c_mem.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c_mem.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c_pipe.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c_pipe.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c_pipe.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c_probe.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c_probe.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c_probe.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c_stdout.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c_stdout.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c_stdout.js.mem -MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe.wasm -MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe.wasm.js -MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe.js.mem -MISC_OUTPUTS += bin/openmpt.a +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)empty.cpp +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)empty.out +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_cxx$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) +MISC_OUTPUTS += bin/$(FLAVOUR_DIR).docs +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX) +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_test.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_test.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_test.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)made.docs +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)$(LIBOPENMPT_SONAME) +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe.wasm +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe.wasm.js +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe.js.mem +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)openmpt.a #old -MISC_OUTPUTS += bin/libopenmpt_example_c_safe$(EXESUFFIX) -MISC_OUTPUTS += bin/libopenmpt_example_c_safe$(EXESUFFIX).norpath +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_safe$(EXESUFFIX) +MISC_OUTPUTS += bin/$(FLAVOUR_DIR)libopenmpt_example_c_safe$(EXESUFFIX).norpath -MISC_OUTPUTDIRS += bin/dest -MISC_OUTPUTDIRS += bin/docs +MISC_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dest +MISC_OUTPUTDIRS += bin/$(FLAVOUR_DIR)docs -DIST_OUTPUTS += bin/dist.mk -DIST_OUTPUTS += bin/svn_version_dist.h -DIST_OUTPUTS += bin/dist.tar -DIST_OUTPUTS += bin/dist-tar.tar -DIST_OUTPUTS += bin/dist-zip.tar -DIST_OUTPUTS += bin/dist-doc.tar -DIST_OUTPUTS += bin/dist-autotools.tar -DIST_OUTPUTS += bin/dist-js.tar -DIST_OUTPUTS += bin/dist-dos.tar -DIST_OUTPUTS += bin/made.docs +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist.mk +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)svn_version_dist.h +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-tar.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-zip.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-doc.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-autotools.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-js.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)dist-dos.tar +DIST_OUTPUTS += bin/$(FLAVOUR_DIR)made.docs -DIST_OUTPUTDIRS += bin/dist -DIST_OUTPUTDIRS += bin/dist-doc -DIST_OUTPUTDIRS += bin/dist-tar -DIST_OUTPUTDIRS += bin/dist-zip -DIST_OUTPUTDIRS += bin/dist-autotools -DIST_OUTPUTDIRS += bin/dist-js -DIST_OUTPUTDIRS += bin/dist-dos -DIST_OUTPUTDIRS += bin/docs +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-doc +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-tar +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-zip +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-autotools +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-js +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)dist-dos +DIST_OUTPUTDIRS += bin/$(FLAVOUR_DIR)docs ifeq ($(ONLY_TEST),1) -all: bin/libopenmpt_test$(EXESUFFIX) +all: bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX) else all: $(OUTPUTS) endif .PHONY: docs -docs: bin/made.docs +docs: bin/$(FLAVOUR_DIR)made.docs .PHONY: doc -doc: bin/made.docs +doc: bin/$(FLAVOUR_DIR)made.docs -bin/made.docs: - $(VERYSILENT)mkdir -p bin/docs +bin/$(FLAVOUR_DIR)made.docs: + $(VERYSILENT)mkdir -p bin/$(FLAVOUR_DIR)docs $(INFO) [DOXYGEN] libopenmpt ifeq ($(SILENT_DOCS),1) $(SILENT) ( cat libopenmpt/Doxyfile ; echo 'PROJECT_NUMBER = "$(DIST_LIBOPENMPT_VERSION)"' ; echo 'WARN_IF_DOC_ERROR = NO' ) | doxygen - @@ -1227,18 +1437,18 @@ endif check: test .PHONY: test -test: bin/libopenmpt_test$(EXESUFFIX) +test: bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX) ifeq ($(REQUIRES_RUNPREFIX),1) - cd bin && $(RUNPREFIX) libopenmpt_test$(EXESUFFIX) + cd bin/$(FLAVOUR_DIR) && $(RUNPREFIX) libopenmpt_test$(EXESUFFIX) else - bin/libopenmpt_test$(EXESUFFIX) + bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX) endif -bin/libopenmpt_test$(EXESUFFIX): $(LIBOPENMPTTEST_OBJECTS) +bin/$(FLAVOUR_DIR)libopenmpt_test$(EXESUFFIX): $(LIBOPENMPTTEST_OBJECTS) $(INFO) [LD-TEST] $@ - $(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(TEST_LDFLAGS) $(LIBOPENMPTTEST_OBJECTS) $(LOADLIBES) $(LDLIBS) -o $@ + $(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(TEST_LDFLAGS) $(LIBOPENMPTTEST_OBJECTS) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPTTEST) -o $@ -bin/libopenmpt.pc: +bin/$(FLAVOUR_DIR)libopenmpt.pc: $(INFO) [GEN] $@ $(VERYSILENT)rm -rf $@ $(VERYSILENT)echo > $@.tmp @@ -1265,36 +1475,40 @@ install: $(OUTPUTS) $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_buffer.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_buffer.h $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_fd.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_fd.h $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_file.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_file.h + $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_file_mingw.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_file_mingw.h + $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h + $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_file_posix.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_file_posix.h + $(INSTALL_DATA) libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h $(INSTALL_DATA) libopenmpt/libopenmpt.hpp $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt.hpp $(INSTALL_DATA) libopenmpt/libopenmpt_ext.h $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_ext.h $(INSTALL_DATA) libopenmpt/libopenmpt_ext.hpp $(DESTDIR)$(PREFIX)/include/libopenmpt/libopenmpt_ext.hpp $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/lib/pkgconfig - $(INSTALL_DATA) bin/libopenmpt.pc $(DESTDIR)$(PREFIX)/lib/pkgconfig/libopenmpt.pc + $(INSTALL_DATA) bin/$(FLAVOUR_DIR)libopenmpt.pc $(DESTDIR)$(PREFIX)/lib/pkgconfig/libopenmpt.pc ifeq ($(SHARED_LIB),1) ifeq ($(SHARED_SONAME),1) $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/lib - $(INSTALL_LIB) bin/$(LIBOPENMPT_SONAME) $(DESTDIR)$(PREFIX)/lib/$(LIBOPENMPT_SONAME) + $(INSTALL_LIB) bin/$(FLAVOUR_DIR)$(LIBOPENMPT_SONAME) $(DESTDIR)$(PREFIX)/lib/$(LIBOPENMPT_SONAME) ln -sf $(LIBOPENMPT_SONAME) $(DESTDIR)$(PREFIX)/lib/libopenmpt$(SOSUFFIX) else $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/lib - $(INSTALL_LIB) bin/libopenmpt$(SOSUFFIX) $(DESTDIR)$(PREFIX)/lib/libopenmpt$(SOSUFFIX) + $(INSTALL_LIB) bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) $(DESTDIR)$(PREFIX)/lib/libopenmpt$(SOSUFFIX) endif $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/lib endif ifeq ($(STATIC_LIB),1) $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/lib - $(INSTALL_DATA) bin/libopenmpt.a $(DESTDIR)$(PREFIX)/lib/libopenmpt.a + $(INSTALL_DATA) bin/$(FLAVOUR_DIR)libopenmpt.a $(DESTDIR)$(PREFIX)/lib/libopenmpt.a endif ifeq ($(OPENMPT123),1) $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/bin ifeq ($(SHARED_LIB),1) - $(INSTALL_PROGRAM) bin/openmpt123$(EXESUFFIX).norpath $(DESTDIR)$(PREFIX)/bin/openmpt123$(EXESUFFIX) + $(INSTALL_PROGRAM) bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX).norpath $(DESTDIR)$(PREFIX)/bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX) else - $(INSTALL_PROGRAM) bin/openmpt123$(EXESUFFIX) $(DESTDIR)$(PREFIX)/bin/openmpt123$(EXESUFFIX) + $(INSTALL_PROGRAM) bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX) $(DESTDIR)$(PREFIX)/bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX) endif ifeq ($(MPT_WITH_HELP2MAN),1) $(INSTALL_MAKE_DIR) $(DESTDIR)$(MANDIR)/man1 - $(INSTALL_DATA) bin/openmpt123.1 $(DESTDIR)$(MANDIR)/man1/openmpt123.1 + $(INSTALL_DATA) bin/$(FLAVOUR_DIR)openmpt123.1 $(DESTDIR)$(MANDIR)/man1/openmpt123.1 endif endif $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/share/doc/libopenmpt @@ -1310,77 +1524,87 @@ endif $(INSTALL_DATA) examples/libopenmpt_example_cxx.cpp $(DESTDIR)$(PREFIX)/share/doc/libopenmpt/examples/libopenmpt_example_cxx.cpp .PHONY: install-doc -install-doc: bin/made.docs +install-doc: bin/$(FLAVOUR_DIR)made.docs ifeq ($(MPT_WITH_DOXYGEN),1) $(INSTALL_MAKE_DIR) $(DESTDIR)$(PREFIX)/share/doc/libopenmpt/html/ - $(INSTALL_DATA_DIR) bin/docs/html $(DESTDIR)$(PREFIX)/share/doc/libopenmpt/html + $(INSTALL_DATA_DIR) bin/$(FLAVOUR_DIR)docs/html $(DESTDIR)$(PREFIX)/share/doc/libopenmpt/html endif .PHONY: dist -dist: bin/dist-tar.tar bin/dist-zip.tar bin/dist-doc.tar +dist: bin/$(FLAVOUR_DIR)dist-tar.tar bin/$(FLAVOUR_DIR)dist-zip.tar bin/$(FLAVOUR_DIR)dist-doc.tar .PHONY: dist-tar -dist-tar: bin/dist-tar.tar +dist-tar: bin/$(FLAVOUR_DIR)dist-tar.tar -bin/dist-tar.tar: bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar.gz - rm -rf bin/dist-tar.tar - cd bin/dist-tar/ && rm -rf libopenmpt - cd bin/dist-tar/ && mkdir -p libopenmpt/src.makefile/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-tar/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar.gz libopenmpt/src.makefile/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-tar/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-tar.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-tar.tar: bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar.gz + rm -rf bin/$(FLAVOUR_DIR)dist-tar.tar + cd bin/$(FLAVOUR_DIR)dist-tar/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-tar/ && mkdir -p libopenmpt/src.makefile/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-tar/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar.gz libopenmpt/src.makefile/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-tar/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-tar.tar libopenmpt .PHONY: dist-zip -dist-zip: bin/dist-zip.tar +dist-zip: bin/$(FLAVOUR_DIR)dist-zip.tar -bin/dist-zip.tar: bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip - rm -rf bin/dist-zip.tar - cd bin/dist-zip/ && rm -rf libopenmpt - cd bin/dist-zip/ && mkdir -p libopenmpt/src.msvc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-zip/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip libopenmpt/src.msvc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-zip/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-zip.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-zip.tar: bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip + rm -rf bin/$(FLAVOUR_DIR)dist-zip.tar + cd bin/$(FLAVOUR_DIR)dist-zip/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-zip/ && mkdir -p libopenmpt/src.msvc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-zip/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip libopenmpt/src.msvc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-zip/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-zip.tar libopenmpt .PHONY: dist-doc -dist-doc: bin/dist-doc.tar +dist-doc: bin/$(FLAVOUR_DIR)dist-doc.tar -bin/dist-doc.tar: bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar.gz - rm -rf bin/dist-doc.tar - cd bin/dist-doc/ && rm -rf libopenmpt - cd bin/dist-doc/ && mkdir -p libopenmpt/doc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-doc/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar.gz libopenmpt/doc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-doc/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-doc.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-doc.tar: bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar.gz + rm -rf bin/$(FLAVOUR_DIR)dist-doc.tar + cd bin/$(FLAVOUR_DIR)dist-doc/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-doc/ && mkdir -p libopenmpt/doc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-doc/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar.gz libopenmpt/doc/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-doc/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-doc.tar libopenmpt .PHONY: dist-js -dist-js: bin/dist-js.tar +dist-js: bin/$(FLAVOUR_DIR)dist-js.tar -bin/dist-js.tar: bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz - rm -rf bin/dist-js.tar - cd bin/dist-js/ && rm -rf libopenmpt - cd bin/dist-js/ && mkdir -p libopenmpt/dev.js/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-js/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz libopenmpt/dev.js/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-js/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-js.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-js.tar: bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz + rm -rf bin/$(FLAVOUR_DIR)dist-js.tar + cd bin/$(FLAVOUR_DIR)dist-js/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-js/ && mkdir -p libopenmpt/dev.js/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-js/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz libopenmpt/dev.js/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-js/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-js.tar libopenmpt .PHONY: dist-dos -dist-dos: bin/dist-dos.tar +dist-dos: bin/$(FLAVOUR_DIR)dist-dos.tar -bin/dist-dos.tar: bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip - rm -rf bin/dist-dos.tar - cd bin/dist-dos/ && rm -rf libopenmpt - cd bin/dist-dos/ && mkdir -p libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-dos/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-dos/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-dos.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-dos.tar: bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip + rm -rf bin/$(FLAVOUR_DIR)dist-dos.tar + cd bin/$(FLAVOUR_DIR)dist-dos/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-dos/ && mkdir -p libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-dos/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-dos/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-dos.tar libopenmpt -.PHONY: dist-retro-win9x -dist-retro-win9x: bin/dist-retro-win9x.tar +.PHONY: dist-retro-win98 +dist-retro-win98: bin/$(FLAVOUR_DIR)dist-retro-win98.tar -bin/dist-retro-win9x.tar: bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win9x.zip - rm -rf bin/dist-retro-win9x.tar - cd bin/dist-retro-win9x/ && rm -rf libopenmpt - cd bin/dist-retro-win9x/ && mkdir -p libopenmpt/bin.retro.win9x/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-retro-win9x/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win9x.zip libopenmpt/bin.retro.win9x/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ - cd bin/dist-retro-win9x/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-retro-win9x.tar libopenmpt +bin/$(FLAVOUR_DIR)dist-retro-win98.tar: bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win98.zip + rm -rf bin/$(FLAVOUR_DIR)dist-retro-win98.tar + cd bin/$(FLAVOUR_DIR)dist-retro-win98/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-retro-win98/ && mkdir -p libopenmpt/bin.retro.win98/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-retro-win98/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win98.zip libopenmpt/bin.retro.win98/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-retro-win98/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-retro-win98.tar libopenmpt -.PHONY: bin/dist.mk -bin/dist.mk: +.PHONY: dist-retro-win95 +dist-retro-win95: bin/$(FLAVOUR_DIR)dist-retro-win95.tar + +bin/$(FLAVOUR_DIR)dist-retro-win95.tar: bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win95.zip + rm -rf bin/$(FLAVOUR_DIR)dist-retro-win95.tar + cd bin/$(FLAVOUR_DIR)dist-retro-win95/ && rm -rf libopenmpt + cd bin/$(FLAVOUR_DIR)dist-retro-win95/ && mkdir -p libopenmpt/bin.retro.win95/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-retro-win95/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win95.zip libopenmpt/bin.retro.win95/$(DIST_LIBOPENMPT_TARBALL_VERSION)/ + cd bin/$(FLAVOUR_DIR)dist-retro-win95/ && tar cv --numeric-owner --owner=0 --group=0 -f ../dist-retro-win95.tar libopenmpt + +.PHONY: bin/$(FLAVOUR_DIR)dist.mk +bin/$(FLAVOUR_DIR)dist.mk: rm -rf $@ echo > $@.tmp echo 'MPT_SVNVERSION=$(MPT_SVNVERSION)' >> $@.tmp @@ -1388,8 +1612,8 @@ bin/dist.mk: echo 'MPT_SVNDATE=$(MPT_SVNDATE)' >> $@.tmp mv $@.tmp $@ -.PHONY: bin/svn_version_dist.h -bin/svn_version_dist.h: +.PHONY: bin/$(FLAVOUR_DIR)svn_version_dist.h +bin/$(FLAVOUR_DIR)svn_version_dist.h: rm -rf $@ echo > $@.tmp echo '#pragma once' >> $@.tmp @@ -1403,298 +1627,338 @@ bin/svn_version_dist.h: echo >> $@.tmp mv $@.tmp $@ -.PHONY: bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar -bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar: docs - mkdir -p bin/dist-doc - rm -rf bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc - mkdir -p bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc - cp -Rv bin/docs/html bin/dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc/docs - cd bin/dist-doc/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc > libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar +.PHONY: bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar +bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar: docs + mkdir -p bin/$(FLAVOUR_DIR)dist-doc + rm -rf bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc + mkdir -p bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc + cp -Rv bin/$(FLAVOUR_DIR)docs/html bin/$(FLAVOUR_DIR)dist-doc/libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc/docs + cd bin/$(FLAVOUR_DIR)dist-doc/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc > libopenmpt-$(DIST_LIBOPENMPT_VERSION).doc.tar -.PHONY: bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar -bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar: bin/dist.mk bin/svn_version_dist.h - mkdir -p bin/dist-tar - rm -rf bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt - mkdir -p bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt - svn export ./LICENSE bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE - svn export ./README.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md - svn export ./Makefile bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Makefile - svn export ./.clang-format bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/.clang-format - svn export ./bin bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin - svn export ./build/android_ndk bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/android_ndk - svn export ./build/make bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/make - svn export ./build/svn_version bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version - svn export ./common bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common - svn export ./doc/contributing.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md - svn export ./doc/libopenmpt_styleguide.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md - svn export ./doc/module_formats.md bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md - svn export ./soundlib bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib - svn export ./sounddsp bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp - svn export ./src/mpt/.clang-format bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/.clang-format - svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSD-3-Clause.txt - svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSL-1.0.txt - svn export ./src/mpt/audio bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/audio - svn export ./src/mpt/base bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/base - svn export ./src/mpt/binary bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/binary - svn export ./src/mpt/check bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/check - svn export ./src/mpt/crc bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crc - #svn export ./src/mpt/crypto bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crypto - svn export ./src/mpt/detect bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/detect - svn export ./src/mpt/endian bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/endian - svn export ./src/mpt/environment bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/environment - svn export ./src/mpt/exception_text bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/exception_text - svn export ./src/mpt/format bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/format - svn export ./src/mpt/io bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io - svn export ./src/mpt/io_read bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_read - svn export ./src/mpt/io_write bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_write - #svn export ./src/mpt/json bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/json - #svn export ./src/mpt/library bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/library - svn export ./src/mpt/mutex bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/mutex - svn export ./src/mpt/out_of_memory bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/out_of_memory - svn export ./src/mpt/osinfo bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/osinfo - svn export ./src/mpt/parse bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/parse - #svn export ./src/mpt/path bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/path - svn export ./src/mpt/random bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/random - svn export ./src/mpt/string bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string - svn export ./src/mpt/string_transcode bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string_transcode - svn export ./src/mpt/system_error bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/system_error - svn export ./src/mpt/test bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/test - svn export ./src/mpt/uuid bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid - #svn export ./src/mpt/uuid_namespace bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid_namespace - svn export ./src/openmpt/all bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/all - svn export ./src/openmpt/base bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/base - svn export ./src/openmpt/logging bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/logging - svn export ./src/openmpt/random bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/random - svn export ./src/openmpt/soundbase bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/soundbase - svn export ./test bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test - rm bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_crypto.cpp - rm bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_uuid_namespace.cpp - svn export ./libopenmpt bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt - svn export ./examples bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/examples - svn export ./openmpt123 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 - svn export ./contrib bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/contrib - svn export ./include/allegro42 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/allegro42 - svn export ./include/cwsdpmi bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/cwsdpmi - svn export ./include/minimp3 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/minimp3 - svn export ./include/miniz bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/miniz - svn export ./include/stb_vorbis bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/stb_vorbis - cp bin/dist.mk bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/dist.mk - cp bin/svn_version_dist.h bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version/svn_version.h - cd bin/dist-tar/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION) > libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar +.PHONY: bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar +bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar: bin/$(FLAVOUR_DIR)dist.mk bin/$(FLAVOUR_DIR)svn_version_dist.h + mkdir -p bin/$(FLAVOUR_DIR)dist-tar + rm -rf bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt + mkdir -p bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE + svn export ./README.md bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md + svn export ./Makefile bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Makefile + svn export ./.clang-format bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/.clang-format + svn export ./bin bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin + svn export ./build/download_externals.sh bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/download_externals.sh + svn export ./build/android_ndk bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/android_ndk + svn export ./build/make bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/make + svn export ./build/svn_version bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version + svn export ./build/xcode-ios bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/xcode-ios + svn export ./build/xcode-macosx bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/xcode-macosx + svn export ./common bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common + svn export ./doc/contributing.md bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md + svn export ./doc/libopenmpt_styleguide.md bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md + svn export ./doc/module_formats.md bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md + svn export ./soundlib bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib + svn export ./sounddsp bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp + svn export ./src/mpt/.clang-format bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/.clang-format + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSD-3-Clause.txt + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSL-1.0.txt + svn export ./src/mpt/arch bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/arch + svn export ./src/mpt/audio bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/audio + svn export ./src/mpt/base bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/base + svn export ./src/mpt/binary bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/binary + svn export ./src/mpt/check bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/check + svn export ./src/mpt/crc bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crc + #svn export ./src/mpt/crypto bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crypto + svn export ./src/mpt/detect bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/detect + svn export ./src/mpt/endian bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/endian + svn export ./src/mpt/environment bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/environment + svn export ./src/mpt/exception bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/exception + svn export ./src/mpt/format bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/format + #svn export ./src/mpt/fs bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/fs + svn export ./src/mpt/io bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io + svn export ./src/mpt/io_file bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file + svn export ./src/mpt/io_file_adapter bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_adapter + svn export ./src/mpt/io_file_read bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_read + svn export ./src/mpt/io_file_unique bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_unique + svn export ./src/mpt/io_read bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_read + svn export ./src/mpt/io_write bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_write + #svn export ./src/mpt/json bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/json + #svn export ./src/mpt/library bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/library + svn export ./src/mpt/mutex bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/mutex + svn export ./src/mpt/out_of_memory bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/out_of_memory + svn export ./src/mpt/osinfo bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/osinfo + svn export ./src/mpt/parse bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/parse + svn export ./src/mpt/path bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/path + svn export ./src/mpt/random bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/random + svn export ./src/mpt/string bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string + svn export ./src/mpt/string_transcode bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string_transcode + svn export ./src/mpt/system_error bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/system_error + svn export ./src/mpt/test bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/test + svn export ./src/mpt/uuid bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid + #svn export ./src/mpt/uuid_namespace bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid_namespace + svn export ./src/openmpt/all bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/all + svn export ./src/openmpt/base bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/base + svn export ./src/openmpt/logging bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/logging + svn export ./src/openmpt/random bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/random + svn export ./src/openmpt/soundbase bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/soundbase + svn export ./test bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test + rm bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_crypto.cpp + rm bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_uuid_namespace.cpp + svn export ./libopenmpt bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt + svn export ./examples bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/examples + svn export ./openmpt123 bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 + svn export ./contrib bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/contrib + svn export ./include/allegro42 bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/allegro42 + svn export ./include/cwsdpmi bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/cwsdpmi + svn export ./include/minimp3 bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/minimp3 + svn export ./include/miniz bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/miniz + svn export ./include/stb_vorbis bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/stb_vorbis + cp bin/$(FLAVOUR_DIR)dist.mk bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/dist.mk + cp bin/$(FLAVOUR_DIR)svn_version_dist.h bin/$(FLAVOUR_DIR)dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version/svn_version.h + cd bin/$(FLAVOUR_DIR)dist-tar/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION) > libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar -.PHONY: bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip -bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/dist.mk bin/svn_version_dist.h - mkdir -p bin/dist-zip - rm -rf bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt - mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt - svn export ./LICENSE bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE --native-eol CRLF - svn export ./README.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md --native-eol CRLF - svn export ./Makefile bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Makefile --native-eol CRLF - svn export ./.clang-format bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/.clang-format --native-eol CRLF - svn export ./bin bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin --native-eol CRLF - svn export ./build/genie/def bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie/def --native-eol CRLF - svn export ./build/premake/def bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/def --native-eol CRLF - svn export ./build/premake/inc bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/inc --native-eol CRLF - svn export ./build/premake/lnk bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/lnk --native-eol CRLF - svn export ./build/scriptlib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/scriptlib --native-eol CRLF - svn export ./build/svn_version bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version --native-eol CRLF - svn export ./build/vs bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs --native-eol CRLF - svn export ./build/vs2017winxp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017winxp --native-eol CRLF - svn export ./build/vs2017win7 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017win7 --native-eol CRLF - svn export ./build/vs2017win10 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017win10 --native-eol CRLF - svn export ./build/vs2017uwp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017uwp --native-eol CRLF - svn export ./build/vs2019win7 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win7 --native-eol CRLF - svn export ./build/vs2019win81 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win81 --native-eol CRLF - svn export ./build/vs2019win10 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win10 --native-eol CRLF - svn export ./build/vs2019uwp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019uwp --native-eol CRLF - svn export ./build/vs2022win7 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win7 --native-eol CRLF - svn export ./build/vs2022win81 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win81 --native-eol CRLF - svn export ./build/vs2022win10 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win10 --native-eol CRLF - svn export ./build/vs2022uwp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022uwp --native-eol CRLF - svn export ./build/vs2022win10clang bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win10clang --native-eol CRLF - svn export ./build/download_externals.cmd bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/download_externals.cmd --native-eol CRLF - svn export ./common bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common --native-eol CRLF - svn export ./doc/contributing.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md --native-eol CRLF - svn export ./doc/libopenmpt_styleguide.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md --native-eol CRLF - svn export ./doc/module_formats.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md --native-eol CRLF - svn export ./soundlib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib --native-eol CRLF - svn export ./sounddsp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp --native-eol CRLF - svn export ./src/mpt/.clang-format bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/.clang-format --native-eol CRLF - svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSD-3-Clause.txt --native-eol CRLF - svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSL-1.0.txt --native-eol CRLF - svn export ./src/mpt/audio bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/audio --native-eol CRLF - svn export ./src/mpt/base bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/base --native-eol CRLF - svn export ./src/mpt/binary bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/binary --native-eol CRLF - svn export ./src/mpt/check bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/check --native-eol CRLF - svn export ./src/mpt/crc bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crc --native-eol CRLF - #svn export ./src/mpt/crypto bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crypto --native-eol CRLF - svn export ./src/mpt/detect bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/detect --native-eol CRLF - svn export ./src/mpt/endian bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/endian --native-eol CRLF - svn export ./src/mpt/environment bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/environment --native-eol CRLF - svn export ./src/mpt/exception_text bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/exception_text --native-eol CRLF - svn export ./src/mpt/format bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/format --native-eol CRLF - svn export ./src/mpt/io bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io --native-eol CRLF - svn export ./src/mpt/io_read bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_read --native-eol CRLF - svn export ./src/mpt/io_write bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_write --native-eol CRLF - #svn export ./src/mpt/json bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/json --native-eol CRLF - #svn export ./src/mpt/library bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/library --native-eol CRLF - svn export ./src/mpt/mutex bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/mutex --native-eol CRLF - svn export ./src/mpt/out_of_memory bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/out_of_memory --native-eol CRLF - svn export ./src/mpt/osinfo bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/osinfo --native-eol CRLF - svn export ./src/mpt/parse bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/parse --native-eol CRLF - #svn export ./src/mpt/path bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/path --native-eol CRLF - svn export ./src/mpt/random bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/random --native-eol CRLF - svn export ./src/mpt/string bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string --native-eol CRLF - svn export ./src/mpt/string_transcode bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string_transcode --native-eol CRLF - svn export ./src/mpt/system_error bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/system_error --native-eol CRLF - svn export ./src/mpt/test bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/test --native-eol CRLF - svn export ./src/mpt/uuid bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid --native-eol CRLF - #svn export ./src/mpt/uuid_namespace bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid_namespace --native-eol CRLF - svn export ./src/openmpt/all bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/all --native-eol CRLF - svn export ./src/openmpt/base bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/base --native-eol CRLF - svn export ./src/openmpt/logging bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/logging --native-eol CRLF - svn export ./src/openmpt/random bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/random --native-eol CRLF - svn export ./src/openmpt/soundbase bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/soundbase --native-eol CRLF - svn export ./test bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test --native-eol CRLF - rm bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_crypto.cpp - rm bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_uuid_namespace.cpp - svn export ./libopenmpt bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt --native-eol CRLF - svn export ./examples bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/examples --native-eol CRLF - svn export ./openmpt123 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 --native-eol CRLF - svn export ./contrib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/contrib --native-eol CRLF - svn export ./include/minimp3 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/minimp3 --native-eol CRLF - svn export ./include/miniz bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/miniz --native-eol CRLF - svn export ./include/mpg123 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/mpg123 --native-eol CRLF - svn export ./include/flac bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/flac --native-eol CRLF - svn export ./include/portaudio bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/portaudio --native-eol CRLF - svn export ./include/ogg bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/ogg --native-eol CRLF - svn export ./include/pugixml bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/pugixml --native-eol CRLF - svn export ./include/stb_vorbis bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/stb_vorbis --native-eol CRLF - svn export ./include/vorbis bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/vorbis --native-eol CRLF - svn export ./include/winamp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/winamp --native-eol CRLF - svn export ./include/xmplay bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/xmplay --native-eol CRLF - svn export ./include/zlib bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/zlib --native-eol CRLF - cp bin/dist.mk bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/dist.mk - cp bin/svn_version_dist.h bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version/svn_version.h - cd bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && zip -r ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip --compression-method deflate -9 * +.PHONY: bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip +bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/$(FLAVOUR_DIR)dist.mk bin/$(FLAVOUR_DIR)svn_version_dist.h + mkdir -p bin/$(FLAVOUR_DIR)dist-zip + rm -rf bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt + mkdir -p bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE --native-eol CRLF + svn export ./README.md bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md --native-eol CRLF + svn export ./Makefile bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Makefile --native-eol CRLF + svn export ./.clang-format bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/.clang-format --native-eol CRLF + svn export ./bin bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin --native-eol CRLF + svn export ./build/premake/def bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/def --native-eol CRLF + svn export ./build/premake/inc bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/inc --native-eol CRLF + svn export ./build/premake/lnk bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/lnk --native-eol CRLF + svn export ./build/scriptlib bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/scriptlib --native-eol CRLF + svn export ./build/svn_version bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version --native-eol CRLF + svn export ./build/vs bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs --native-eol CRLF + svn export ./build/vs2017winxp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017winxp --native-eol CRLF + svn export ./build/vs2019win7 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win7 --native-eol CRLF + svn export ./build/vs2019win81 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win81 --native-eol CRLF + svn export ./build/vs2019win10 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win10 --native-eol CRLF + svn export ./build/vs2019win10uwp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2019win10uwp --native-eol CRLF + svn export ./build/vs2022win7 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win7 --native-eol CRLF + svn export ./build/vs2022win81 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win81 --native-eol CRLF + svn export ./build/vs2022win10 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win10 --native-eol CRLF + svn export ./build/vs2022win10uwp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win10uwp --native-eol CRLF + svn export ./build/vs2022win10clang bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2022win10clang --native-eol CRLF + svn export ./build/download_externals.cmd bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/download_externals.cmd --native-eol CRLF + svn export ./common bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/common --native-eol CRLF + svn export ./doc/contributing.md bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/contributing.md --native-eol CRLF + svn export ./doc/libopenmpt_styleguide.md bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/libopenmpt_styleguide.md --native-eol CRLF + svn export ./doc/module_formats.md bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/doc/module_formats.md --native-eol CRLF + svn export ./soundlib bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/soundlib --native-eol CRLF + svn export ./sounddsp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/sounddsp --native-eol CRLF + svn export ./src/mpt/.clang-format bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/.clang-format --native-eol CRLF + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSD-3-Clause.txt --native-eol CRLF + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/LICENSE.BSL-1.0.txt --native-eol CRLF + svn export ./src/mpt/arch bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/arch --native-eol CRLF + svn export ./src/mpt/audio bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/audio --native-eol CRLF + svn export ./src/mpt/base bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/base --native-eol CRLF + svn export ./src/mpt/binary bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/binary --native-eol CRLF + svn export ./src/mpt/check bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/check --native-eol CRLF + svn export ./src/mpt/crc bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crc --native-eol CRLF + #svn export ./src/mpt/crypto bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/crypto --native-eol CRLF + svn export ./src/mpt/detect bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/detect --native-eol CRLF + svn export ./src/mpt/endian bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/endian --native-eol CRLF + svn export ./src/mpt/environment bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/environment --native-eol CRLF + svn export ./src/mpt/exception bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/exception --native-eol CRLF + svn export ./src/mpt/format bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/format --native-eol CRLF + #svn export ./src/mpt/fs bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/fs --native-eol CRLF + svn export ./src/mpt/io bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io --native-eol CRLF + svn export ./src/mpt/io_file bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file --native-eol CRLF + svn export ./src/mpt/io_file_adapter bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_adapter --native-eol CRLF + svn export ./src/mpt/io_file_read bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_read --native-eol CRLF + svn export ./src/mpt/io_file_unique bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_file_unique --native-eol CRLF + svn export ./src/mpt/io_read bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_read --native-eol CRLF + svn export ./src/mpt/io_write bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/io_write --native-eol CRLF + #svn export ./src/mpt/json bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/json --native-eol CRLF + #svn export ./src/mpt/library bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/library --native-eol CRLF + svn export ./src/mpt/mutex bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/mutex --native-eol CRLF + svn export ./src/mpt/out_of_memory bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/out_of_memory --native-eol CRLF + svn export ./src/mpt/osinfo bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/osinfo --native-eol CRLF + svn export ./src/mpt/parse bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/parse --native-eol CRLF + svn export ./src/mpt/path bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/path --native-eol CRLF + svn export ./src/mpt/random bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/random --native-eol CRLF + svn export ./src/mpt/string bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string --native-eol CRLF + svn export ./src/mpt/string_transcode bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/string_transcode --native-eol CRLF + svn export ./src/mpt/system_error bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/system_error --native-eol CRLF + svn export ./src/mpt/test bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/test --native-eol CRLF + svn export ./src/mpt/uuid bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid --native-eol CRLF + #svn export ./src/mpt/uuid_namespace bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/mpt/uuid_namespace --native-eol CRLF + svn export ./src/openmpt/all bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/all --native-eol CRLF + svn export ./src/openmpt/base bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/base --native-eol CRLF + svn export ./src/openmpt/logging bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/logging --native-eol CRLF + svn export ./src/openmpt/random bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/random --native-eol CRLF + svn export ./src/openmpt/soundbase bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/src/openmpt/soundbase --native-eol CRLF + svn export ./test bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test --native-eol CRLF + rm bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_crypto.cpp + rm bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/test/mpt_tests_uuid_namespace.cpp + svn export ./libopenmpt bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt --native-eol CRLF + svn export ./examples bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/examples --native-eol CRLF + svn export ./openmpt123 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 --native-eol CRLF + svn export ./contrib bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/contrib --native-eol CRLF + svn export ./include/minimp3 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/minimp3 --native-eol CRLF + svn export ./include/miniz bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/miniz --native-eol CRLF + svn export ./include/mpg123 bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/mpg123 --native-eol CRLF + svn export ./include/flac bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/flac --native-eol CRLF + svn export ./include/portaudio bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/portaudio --native-eol CRLF + svn export ./include/ogg bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/ogg --native-eol CRLF + svn export ./include/pugixml bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/pugixml --native-eol CRLF + svn export ./include/stb_vorbis bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/stb_vorbis --native-eol CRLF + svn export ./include/vorbis bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/vorbis --native-eol CRLF + svn export ./include/winamp bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/winamp --native-eol CRLF + svn export ./include/xmplay bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/xmplay --native-eol CRLF + svn export ./include/zlib bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/zlib --native-eol CRLF + cp bin/$(FLAVOUR_DIR)dist.mk bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/dist.mk + cp bin/$(FLAVOUR_DIR)svn_version_dist.h bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version/svn_version.h + cd bin/$(FLAVOUR_DIR)dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && zip -r ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip --compression-method deflate -9 * -.PHONY: bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION).zip -bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION).zip: bin/svn_version_dist.h - mkdir -p bin/dist-zip - rm -rf bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION) - svn export ./ bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/ --native-eol CRLF - cp bin/svn_version_dist.h bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/common/svn_version_default/svn_version.h - cd bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/ && zip -r ../OpenMPT-src-$(DIST_OPENMPT_VERSION).zip --compression-method deflate -9 * +.PHONY: bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION).zip +bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION).zip: bin/$(FLAVOUR_DIR)svn_version_dist.h + mkdir -p bin/$(FLAVOUR_DIR)dist-zip + rm -rf bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION) + svn export ./ bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/ --native-eol CRLF + cp bin/$(FLAVOUR_DIR)svn_version_dist.h bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/common/svn_version_default/svn_version.h + cd bin/$(FLAVOUR_DIR)dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/ && zip -r ../OpenMPT-src-$(DIST_OPENMPT_VERSION).zip --compression-method deflate -9 * -.PHONY: bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar -bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar: - mkdir -p bin/dist-js - rm -rf bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses - svn export ./LICENSE bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/license.txt - svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.mpt.BSD-3-Clause.txt - svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.mpt.BSL-1.0.txt - svn export ./include/minimp3/LICENSE bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.minimp3.txt - svn export ./include/miniz/miniz.c bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.miniz.txt - svn export ./include/stb_vorbis/stb_vorbis.c bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.stb_vorbis.txt - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/all - cp bin/stage/all/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/all/libopenmpt.js - cp bin/stage/all/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/all/libopenmpt.js.mem - cp bin/stage/all/libopenmpt.wasm bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/all/libopenmpt.wasm - cp bin/stage/all/libopenmpt.wasm.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/all/libopenmpt.wasm.js - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm - cp bin/stage/wasm/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm/libopenmpt.js - cp bin/stage/wasm/libopenmpt.wasm bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm/libopenmpt.wasm - mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js - cp bin/stage/js/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js/libopenmpt.js - cp bin/stage/js/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js/libopenmpt.js.mem - cd bin/dist-js/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION) > libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar +.PHONY: bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar +bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar: + mkdir -p bin/$(FLAVOUR_DIR)dist-js + rm -rf bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/license.txt + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.mpt.BSD-3-Clause.txt + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.mpt.BSL-1.0.txt + svn export ./include/minimp3/LICENSE bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.minimp3.txt + svn export ./include/miniz/miniz.c bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.miniz.txt + svn export ./include/stb_vorbis/stb_vorbis.c bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.stb_vorbis.txt + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)all + cp bin/$(FLAVOUR_DIR)stage/all/libopenmpt.js bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)all/libopenmpt.js + cp bin/$(FLAVOUR_DIR)stage/all/libopenmpt.js.mem bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)all/libopenmpt.js.mem + cp bin/$(FLAVOUR_DIR)stage/all/libopenmpt.wasm bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)all/libopenmpt.wasm + cp bin/$(FLAVOUR_DIR)stage/all/libopenmpt.wasm.js bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)all/libopenmpt.wasm.js + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)wasm + cp bin/$(FLAVOUR_DIR)stage/wasm/libopenmpt.js bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)wasm/libopenmpt.js + cp bin/$(FLAVOUR_DIR)stage/wasm/libopenmpt.wasm bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)wasm/libopenmpt.wasm + mkdir -p bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)js + cp bin/$(FLAVOUR_DIR)stage/js/libopenmpt.js bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)js/libopenmpt.js + cp bin/$(FLAVOUR_DIR)stage/js/libopenmpt.js.mem bin/$(FLAVOUR_DIR)dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/$(FLAVOUR_DIR)js/libopenmpt.js.mem + cd bin/$(FLAVOUR_DIR)dist-js/ && tar cv --numeric-owner --owner=0 --group=0 libopenmpt-$(DIST_LIBOPENMPT_VERSION) > libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar -.PHONY: bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip -bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip: - mkdir -p bin/dist-dos - rm -rf bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES - svn export ./LICENSE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF - svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPT_BSD3.TXT --native-eol CRLF - svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPT_BSL1.TXT --native-eol CRLF - cp include/allegro42/readme.txt bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/ALLEGRO.TXT - cp include/cwsdpmi/bin/cwsdpmi.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/CWSDPMI.TXT +.PHONY: bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip +bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip: + mkdir -p bin/$(FLAVOUR_DIR)dist-dos + rm -rf bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPT_BSD3.TXT --native-eol CRLF + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPT_BSL1.TXT --native-eol CRLF + cp include/allegro42/readme.txt bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/ALLEGRO.TXT + cp include/cwsdpmi/bin/$(FLAVOUR_DIR)cwsdpmi.doc bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/CWSDPMI.TXT ifeq ($(ALLOW_LGPL),1) - svn export ./include/mpg123/COPYING bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPG123.TXT --native-eol CRLF - svn export ./include/mpg123/AUTHORS bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPG123_A.TXT --native-eol CRLF - svn export ./include/vorbis/COPYING bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/VORBIS.TXT --native-eol CRLF - svn export ./include/zlib/README bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/ZLIB.TXT --native-eol CRLF + svn export ./include/mpg123/COPYING bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPG123.TXT --native-eol CRLF + svn export ./include/mpg123/AUTHORS bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MPG123_A.TXT --native-eol CRLF + svn export ./include/vorbis/COPYING bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/VORBIS.TXT --native-eol CRLF + svn export ./include/zlib/README bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/ZLIB.TXT --native-eol CRLF else - svn export ./include/minimp3/LICENSE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIMP3.TXT --native-eol CRLF - svn export ./include/miniz/miniz.c bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIZ.TXT --native-eol CRLF - svn export ./include/stb_vorbis/stb_vorbis.c bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/STBVORB.TXT --native-eol CRLF + svn export ./include/minimp3/LICENSE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIMP3.TXT --native-eol CRLF + svn export ./include/miniz/miniz.c bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIZ.TXT --native-eol CRLF + svn export ./include/stb_vorbis/stb_vorbis.c bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/STBVORB.TXT --native-eol CRLF endif - mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC - cp build/externals/csdpmi7s.zip bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC/CSDPMI7S.ZIP - mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN - cp bin/openmpt123.exe bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/OMPT123.EXE - cp include/cwsdpmi/bin/cwsdpmi.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.DOC - cp include/cwsdpmi/bin/CWSDPMI.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.EXE - cp include/cwsdpmi/bin/CWSDPR0.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPR0.EXE - cp include/cwsdpmi/bin/cwsparam.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.DOC - cp include/cwsdpmi/bin/CWSPARAM.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.EXE - cp include/cwsdpmi/bin/CWSDSTUB.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTUB.EXE - cp include/cwsdpmi/bin/CWSDSTR0.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTR0.EXE - cd bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && zip -r ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip --compression-method deflate -9 * + mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC + cp build/externals/csdpmi7s.zip bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC/CSDPMI7S.ZIP + mkdir -p bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN + cp bin/$(FLAVOUR_DIR)openmpt123.exe bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/OMPT123.EXE + cp include/cwsdpmi/bin/cwsdpmi.doc bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.DOC + cp include/cwsdpmi/bin/CWSDPMI.EXE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.EXE + cp include/cwsdpmi/bin/CWSDPR0.EXE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPR0.EXE + cp include/cwsdpmi/bin/cwsparam.doc bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.DOC + cp include/cwsdpmi/bin/CWSPARAM.EXE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.EXE + cp include/cwsdpmi/bin/CWSDSTUB.EXE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTUB.EXE + cp include/cwsdpmi/bin/CWSDSTR0.EXE bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTR0.EXE + cd bin/$(FLAVOUR_DIR)dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && zip -r ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip --compression-method deflate -9 * -.PHONY: bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win9x.zip -bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win9x.zip: - mkdir -p bin/dist-retro-win9x - rm -rf bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION) - mkdir -p bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses - svn export ./LICENSE bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF - svn export ./libopenmpt/dox/changelog.md bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Changelog.txt --native-eol CRLF - svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSD-3-Clause.txt --native-eol CRLF - svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSL-1.0.txt --native-eol CRLF +.PHONY: bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win98.zip +bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win98.zip: + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98 + rm -rf bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF + svn export ./doc/libopenmpt/changelog.md bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Changelog.txt --native-eol CRLF + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSD-3-Clause.txt --native-eol CRLF + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSL-1.0.txt --native-eol CRLF ifeq ($(ALLOW_LGPL),1) - svn export ./include/mpg123/COPYING bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.mpg123.txt --native-eol CRLF - svn export ./include/mpg123/AUTHORS bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Authors.txt --native-eol CRLF - svn export ./include/vorbis/COPYING bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Vorbis.txt --native-eol CRLF - svn export ./include/zlib/README bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.zlib.txt --native-eol CRLF + svn export ./include/mpg123/COPYING bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.mpg123.txt --native-eol CRLF + svn export ./include/mpg123/AUTHORS bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Authors.txt --native-eol CRLF + svn export ./include/vorbis/COPYING bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Vorbis.txt --native-eol CRLF + svn export ./include/zlib/README bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.zlib.txt --native-eol CRLF else - svn export ./include/minimp3/LICENSE bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.minimp3.txt --native-eol CRLF - svn export ./include/miniz/miniz.c bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.miniz.txt --native-eol CRLF - svn export ./include/stb_vorbis/stb_vorbis.c bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.stb_vorbis.txt --native-eol CRLF + svn export ./include/minimp3/LICENSE bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.minimp3.txt --native-eol CRLF + svn export ./include/miniz/miniz.c bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.miniz.txt --native-eol CRLF + svn export ./include/stb_vorbis/stb_vorbis.c bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.stb_vorbis.txt --native-eol CRLF endif - mkdir -p bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 - cp bin/openmpt123.exe bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123/openmpt123.exe - mkdir -p bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay - svn export ./libopenmpt/doc/xmp-openmpt.txt bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.txt --native-eol CRLF - cp bin/xmp-openmpt.dll bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.dll - mkdir -p bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp - svn export ./libopenmpt/doc/in_openmpt.txt bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.txt --native-eol CRLF - cp bin/in_openmpt.dll bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.dll - cd bin/dist-retro-win9x/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && ../../../build/tools/7zip/7z a -tzip -mx=9 ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win9x.zip * + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 + cp bin/$(FLAVOUR_DIR)openmpt123.exe bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123/openmpt123.exe + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay + svn export ./libopenmpt/xmp-openmpt/xmp-openmpt.txt bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.txt --native-eol CRLF + cp bin/$(FLAVOUR_DIR)xmp-openmpt.dll bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.dll + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp + svn export ./libopenmpt/in_openmpt/in_openmpt.txt bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.txt --native-eol CRLF + cp bin/$(FLAVOUR_DIR)in_openmpt.dll bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.dll + cd bin/$(FLAVOUR_DIR)dist-retro-win98/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && ../../../build/tools/7zip/7z a -tzip -mx=9 ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win98.zip * -bin/libopenmpt.a: $(LIBOPENMPT_OBJECTS) +.PHONY: bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win95.zip +bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win95.zip: + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95 + rm -rf bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION) + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses + svn export ./LICENSE bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF + svn export ./doc/libopenmpt/changelog.md bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Changelog.txt --native-eol CRLF + svn export ./src/mpt/LICENSE.BSD-3-Clause.txt bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSD-3-Clause.txt --native-eol CRLF + svn export ./src/mpt/LICENSE.BSL-1.0.txt bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/license.mpt.BSL-1.0.txt --native-eol CRLF +ifeq ($(ALLOW_LGPL),1) + svn export ./include/mpg123/COPYING bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.mpg123.txt --native-eol CRLF + svn export ./include/mpg123/AUTHORS bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Authors.txt --native-eol CRLF + svn export ./include/vorbis/COPYING bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.Vorbis.txt --native-eol CRLF + svn export ./include/zlib/README bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.zlib.txt --native-eol CRLF +else + svn export ./include/minimp3/LICENSE bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.minimp3.txt --native-eol CRLF + svn export ./include/miniz/miniz.c bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.miniz.txt --native-eol CRLF + svn export ./include/stb_vorbis/stb_vorbis.c bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Licenses/License.stb_vorbis.txt --native-eol CRLF +endif + mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123 + cp bin/$(FLAVOUR_DIR)openmpt123.exe bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123/openmpt123.exe + #mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay + #svn export ./libopenmpt/xmp-openmpt/xmp-openmpt.txt bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.txt --native-eol CRLF + #cp bin/$(FLAVOUR_DIR)xmp-openmpt.dll bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/XMPlay/xmp-openmpt.dll + #mkdir -p bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp + #svn export ./libopenmpt/in_openmpt/in_openmpt.txt bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.txt --native-eol CRLF + #cp bin/$(FLAVOUR_DIR)in_openmpt.dll bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Winamp/in_openmpt.dll + cd bin/$(FLAVOUR_DIR)dist-retro-win95/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && 7z a -tzip -mx=9 ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.retro.win95.zip * + +bin/$(FLAVOUR_DIR)libopenmpt.a: $(LIBOPENMPT_OBJECTS) $(INFO) [AR] $@ $(SILENT)$(AR) $(ARFLAGS) $@ $^ -bin/libopenmpt$(SOSUFFIX): $(LIBOPENMPT_OBJECTS) +bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX): $(LIBOPENMPT_OBJECTS) $(INFO) [LD] $@ ifeq ($(NO_SHARED_LINKER_FLAG),1) $(SILENT)$(LINK.cc) $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ @@ -1702,15 +1966,15 @@ else $(SILENT)$(LINK.cc) -shared $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ endif ifeq ($(SHARED_SONAME),1) - $(SILENT)mv bin/libopenmpt$(SOSUFFIX) bin/$(LIBOPENMPT_SONAME) - $(SILENT)ln -sf $(LIBOPENMPT_SONAME) bin/libopenmpt$(SOSUFFIX) + $(SILENT)mv bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) bin/$(FLAVOUR_DIR)$(LIBOPENMPT_SONAME) + $(SILENT)ln -sf $(LIBOPENMPT_SONAME) bin/$(FLAVOUR_DIR)libopenmpt$(SOSUFFIX) endif -bin/openmpt123.1: bin/openmpt123$(EXESUFFIX) openmpt123/openmpt123.h2m +bin/$(FLAVOUR_DIR)openmpt123.1: bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX) openmpt123/openmpt123.h2m $(INFO) [HELP2MAN] $@ $(SILENT)help2man --no-discard-stderr --no-info --version-option=--man-version --help-option=--man-help --include=openmpt123/openmpt123.h2m $< > $@ -bin/in_openmpt$(SOSUFFIX): $(INOPENMPT_OBJECTS) $(LIBOPENMPT_OBJECTS) +bin/$(FLAVOUR_DIR)in_openmpt$(SOSUFFIX): $(INOPENMPT_OBJECTS) $(LIBOPENMPT_OBJECTS) $(INFO) [LD] $@ ifeq ($(NO_SHARED_LINKER_FLAG),1) $(SILENT)$(LINK.cc) $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ @@ -1718,7 +1982,7 @@ else $(SILENT)$(LINK.cc) -shared $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ endif -bin/xmp-openmpt$(SOSUFFIX): $(XMPOPENMPT_OBJECTS) $(LIBOPENMPT_OBJECTS) +bin/$(FLAVOUR_DIR)xmp-openmpt$(SOSUFFIX): $(XMPOPENMPT_OBJECTS) $(LIBOPENMPT_OBJECTS) $(INFO) [LD] $@ ifeq ($(NO_SHARED_LINKER_FLAG),1) $(SILENT)$(LINK.cc) $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -lgdi32 -o $@ @@ -1726,11 +1990,11 @@ else $(SILENT)$(LINK.cc) -shared $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -lgdi32 -o $@ endif -openmpt123/openmpt123.o: openmpt123/openmpt123.cpp +openmpt123/openmpt123$(FLAVOUR_O).o: openmpt123/openmpt123.cpp $(INFO) [CXX] $< - $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CXXFLAGS_OPENMPT123) $(CPPFLAGS) $(CPPFLAGS_OPENMPT123) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CXXFLAGS_OPENMPT123) $(CPPFLAGS) $(CPPFLAGS_OPENMPT123) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.cc) $(CXXFLAGS_OPENMPT123) $(CPPFLAGS_OPENMPT123) $(OUTPUT_OPTION) $< -bin/openmpt123$(EXESUFFIX): $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)openmpt123$(EXESUFFIX): $(OPENMPT123_OBJECTS) $(DEPS_ALLEGRO42) $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_OPENMPT123) $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_OPENMPT123) -o $@ ifeq ($(HOST),unix) @@ -1741,117 +2005,117 @@ ifeq ($(SHARED_LIB),1) endif endif -contrib/fuzzing/fuzz.o: contrib/fuzzing/fuzz.c +contrib/fuzzing/fuzz$(FLAVOUR_O).o: contrib/fuzzing/fuzz.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(OUTPUT_OPTION) $< -bin/fuzz$(EXESUFFIX): contrib/fuzzing/fuzz.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)fuzz$(EXESUFFIX): contrib/fuzzing/fuzz$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) contrib/fuzzing/fuzz.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) contrib/fuzzing/fuzz$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) contrib/fuzzing/fuzz.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) contrib/fuzzing/fuzz$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ endif endif -examples/libopenmpt_example_c.o: examples/libopenmpt_example_c.c +examples/libopenmpt_example_c$(FLAVOUR_O).o: examples/libopenmpt_example_c.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(CFLAGS_PORTAUDIO) $(CPPFLAGS_PORTAUDIO) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_c_mem.o: examples/libopenmpt_example_c_mem.c +examples/libopenmpt_example_c_mem$(FLAVOUR_O).o: examples/libopenmpt_example_c_mem.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(CFLAGS_PORTAUDIO) $(CPPFLAGS_PORTAUDIO) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_c_unsafe.o: examples/libopenmpt_example_c_unsafe.c +examples/libopenmpt_example_c_unsafe$(FLAVOUR_O).o: examples/libopenmpt_example_c_unsafe.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CFLAGS_PORTAUDIO) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIO) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(CFLAGS_PORTAUDIO) $(CPPFLAGS_PORTAUDIO) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_c_pipe.o: examples/libopenmpt_example_c_pipe.c +examples/libopenmpt_example_c_pipe$(FLAVOUR_O).o: examples/libopenmpt_example_c_pipe.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_c_stdout.o: examples/libopenmpt_example_c_stdout.c +examples/libopenmpt_example_c_stdout$(FLAVOUR_O).o: examples/libopenmpt_example_c_stdout.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_c_probe.o: examples/libopenmpt_example_c_probe.c +examples/libopenmpt_example_c_probe$(FLAVOUR_O).o: examples/libopenmpt_example_c_probe.c $(INFO) [CC] $< - $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.c) $(OUTPUT_OPTION) $< -examples/libopenmpt_example_cxx.o: examples/libopenmpt_example_cxx.cpp +examples/libopenmpt_example_cxx$(FLAVOUR_O).o: examples/libopenmpt_example_cxx.cpp $(INFO) [CXX] $< - $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CXXFLAGS_PORTAUDIOCPP) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIOCPP) $(TARGET_ARCH) -M -MT$@ $< > $*.d + $(VERYSILENT)$(CXX) $(CXXFLAGS) $(CXXFLAGS_PORTAUDIOCPP) $(CPPFLAGS) $(CPPFLAGS_PORTAUDIOCPP) $(TARGET_ARCH) -M -MT$@ $< > $*$(FLAVOUR_O).d $(SILENT)$(COMPILE.cc) $(CXXFLAGS_PORTAUDIOCPP) $(CPPFLAGS_PORTAUDIOCPP) $(OUTPUT_OPTION) $< -bin/libopenmpt_example_c$(EXESUFFIX): examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c$(EXESUFFIX): examples/libopenmpt_example_c$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(BIN_LDFLAGS)$(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(BIN_LDFLAGS)$(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ endif endif -bin/libopenmpt_example_c_mem$(EXESUFFIX): examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c_mem$(EXESUFFIX): examples/libopenmpt_example_c_mem$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ endif endif -bin/libopenmpt_example_c_unsafe$(EXESUFFIX): examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c_unsafe$(EXESUFFIX): examples/libopenmpt_example_c_unsafe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@ endif endif -bin/libopenmpt_example_c_pipe$(EXESUFFIX): examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c_pipe$(EXESUFFIX): examples/libopenmpt_example_c_pipe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ endif endif -bin/libopenmpt_example_c_stdout$(EXESUFFIX): examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c_stdout$(EXESUFFIX): examples/libopenmpt_example_c_stdout$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ endif endif -bin/libopenmpt_example_c_probe$(EXESUFFIX): examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_c_probe$(EXESUFFIX): examples/libopenmpt_example_c_probe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@ endif endif -bin/libopenmpt_example_cxx$(EXESUFFIX): examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) +bin/$(FLAVOUR_DIR)libopenmpt_example_cxx$(EXESUFFIX): examples/libopenmpt_example_cxx$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT) $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@ ifeq ($(HOST),unix) ifeq ($(SHARED_LIB),1) $(SILENT)mv $@ $@.norpath $(INFO) [LD] $@ - $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@ + $(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx$(FLAVOUR_O).o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@ endif endif diff --git a/Frameworks/OpenMPT/OpenMPT/README.md b/Frameworks/OpenMPT/OpenMPT/README.md index c360b99a4..6a6fcc1a0 100644 --- a/Frameworks/OpenMPT/OpenMPT/README.md +++ b/Frameworks/OpenMPT/OpenMPT/README.md @@ -35,12 +35,11 @@ How to compile - Supported Visual Studio versions: - - Visual Studio 2017, 2019, and 2022 Community/Professional/Enterprise + - Visual Studio 2019, and 2022 Community/Professional/Enterprise To compile the project, open `build/vsVERSIONwin7/OpenMPT.sln` (VERSION - being 2017, 2019, or 2022) and hit the compile button. Other target - systems can be found in the `vs2017*`, `vs2019*`, and `vs2022*` sibling - folders. + being 2019, or 2022) and hit the compile button. Other target systems + can be found in the `vs2019*`, and `vs2022*` sibling folders. Note that you have to build the `PluginBridge` and `PluginBridgeLegacy` projects manually for architectures other than the one you are building @@ -55,11 +54,13 @@ How to compile headers and implementation, which significantly increases the matrix of possible configurations to test. + - Visual Studio 2017 XP targeting toolset + - OpenMPT requires the compile host system to be Windows 8.1 (or later) amd64, or Windows 11 (or later) ARM64. - In order to build OpenMPT for Windows XP, the Visual Studio 2017 XP - targetting toolset as well as the Windows 8.1 SDK need to be installed. The + targeting toolset as well as the Windows 8.1 SDK need to be installed. The SDK is optionally included with Visual Studio 2017, but must be separately installed with later Visual Studio versions. @@ -74,8 +75,8 @@ How to compile ### libopenmpt and openmpt123 -See [Dependencies](libopenmpt/dox/dependencies.md) and -[Getting Started](libopenmpt/dox/gettingstarted.md). +See [Dependencies](doc/libopenmpt/dependencies.md) and +[Getting Started](doc/libopenmpt/gettingstarted.md). Contributing to OpenMPT/libopenmpt diff --git a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk index d427b624c..debfb4a53 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk @@ -6,12 +6,12 @@ include $(CLEAR_VARS) LOCAL_MODULE := openmpt -LOCAL_CFLAGS +=#-std=c99 +LOCAL_CFLAGS += -std=c17 LOCAL_CPPFLAGS += -std=c++17 -fexceptions -frtti LOCAL_CPP_FEATURES += exceptions rtti -LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/src $(LOCAL_PATH)/common $(LOCAL_PATH)/build/svn_version +LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/src $(LOCAL_PATH)/common LOCAL_CFLAGS += -fvisibility=hidden -Wall -DLIBOPENMPT_BUILD -DMPT_WITH_ZLIB LOCAL_CPPFLAGS +=#-fvisibility=hidden -Wall -DLIBOPENMPT_BUILD -DMPT_WITH_ZLIB @@ -88,12 +88,11 @@ LOCAL_SRC_FILES += \ common/ComponentManager.cpp \ common/Logging.cpp \ common/mptFileIO.cpp \ + common/mptFileTemporary.cpp \ + common/mptFileType.cpp \ common/mptPathString.cpp \ common/mptRandom.cpp \ - common/mptString.cpp \ common/mptStringBuffer.cpp \ - common/mptStringFormat.cpp \ - common/mptStringParse.cpp \ common/mptTime.cpp \ common/Profiler.cpp \ common/serialization_utils.cpp \ @@ -112,6 +111,7 @@ LOCAL_SRC_FILES += \ soundlib/InstrumentExtensions.cpp \ soundlib/ITCompression.cpp \ soundlib/ITTools.cpp \ + soundlib/Load_667.cpp \ soundlib/Load_669.cpp \ soundlib/Load_amf.cpp \ soundlib/Load_ams.cpp \ @@ -125,6 +125,7 @@ LOCAL_SRC_FILES += \ soundlib/Load_far.cpp \ soundlib/Load_fmt.cpp \ soundlib/Load_gdm.cpp \ + soundlib/Load_gt2.cpp \ soundlib/Load_imf.cpp \ soundlib/Load_it.cpp \ soundlib/Load_itp.cpp \ @@ -150,6 +151,7 @@ LOCAL_SRC_FILES += \ soundlib/Load_uax.cpp \ soundlib/Load_wav.cpp \ soundlib/Load_xm.cpp \ + soundlib/Load_xmf.cpp \ soundlib/Message.cpp \ soundlib/MIDIEvents.cpp \ soundlib/MIDIMacros.cpp \ diff --git a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk index 6b0c65285..e04305eb4 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/android_ndk/Application.mk @@ -1,5 +1,5 @@ -APP_CFLAGS :=#-std=c99 +APP_CFLAGS := -std=c17 APP_CPPFLAGS := -std=c++17 -fexceptions -frtti APP_LDFLAGS := APP_STL := c++_shared diff --git a/Frameworks/OpenMPT/OpenMPT/build/dist.mk b/Frameworks/OpenMPT/OpenMPT/build/dist.mk index 096919d4a..7abe2215c 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/dist.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/dist.mk @@ -1,4 +1,4 @@ -MPT_SVNVERSION=18680 -MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.8 -MPT_SVNDATE=2023-01-29T12:13:49.877060Z +MPT_SVNVERSION=19147 +MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.0 +MPT_SVNDATE=2023-04-30T12:58:58.547157Z diff --git a/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh b/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh new file mode 100644 index 000000000..28c50f053 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/download_externals.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash + +# stop on error +set -e + +# normalize current directory to project root +cd build 2>&1 > /dev/null || true +cd .. + +function download_and_unpack_tar () { + set -e + MPT_GET_DESTDIR="$1" + MPT_GET_URL="$2" + MPT_GET_FILE="$3" + MPT_GET_SUBDIR="$4" + if [ ! -f "$3" ]; then + wget "$2" -O "$3" + fi + cd include + if [ -d "$1" ]; then + rm -rf "$1" + fi + if [ "$4" = "." ]; then + mkdir "$1" + cd "$1" + tar xvaf "../../$3" + cd .. + else + tar xvaf "../$3" + if [ ! "$4" = "$1" ]; then + mv "$4" "$1" + fi + fi + cd .. + return 0 +} + +function download_and_unpack_zip () { + set -e + MPT_GET_DESTDIR="$1" + MPT_GET_URL="$2" + MPT_GET_FILE="$3" + MPT_GET_SUBDIR="$4" + if [ ! -f "$3" ]; then + wget "$2" -O "$3" + fi + cd include + if [ -d "$1" ]; then + rm -rf "$1" + fi + if [ "$4" = "." ]; then + mkdir "$1" + cd "$1" + unzip "../../$3" + cd .. + else + unzip "../$3" + if [ ! "$4" = "$1" ]; then + mv "$4" "$1" + fi + fi + cd .. + return 0 +} + +function download_and_unpack_7z () { + set -e + MPT_GET_DESTDIR="$1" + MPT_GET_URL="$2" + MPT_GET_FILE="$3" + MPT_GET_SUBDIR="$4" + if [ ! -f "$3" ]; then + wget "$2" -O "$3" + fi + cd include + if [ -d "$1" ]; then + rm -rf "$1" + fi + if [ "$4" = "." ]; then + mkdir "$1" + cd "$1" + 7z x "../../$3" + cd .. + else + 7z x "../$3" + if [ ! "$4" = "$1" ]; then + mv "$4" "$1" + fi + fi + cd .. + return 0 +} + +function download () { + set -e + MPT_GET_URL="$1" + MPT_GET_FILE="$2" + if [ ! -f "$2" ]; then + wget "$1" -O "$2" + fi + return 0 +} + +if [ ! -d "build/externals" ]; then + mkdir build/externals +fi +if [ ! -d "build/tools" ]; then + mkdir build/tools +fi + + + +download_and_unpack_zip "allegro42" "https://lib.openmpt.org/files/libopenmpt/contrib/allegro/allegro-4.2.3.1-hg.8+r8500.zip" "build/externals/allegro-4.2.3.1-hg.8+r8500.zip" "." +download_and_unpack_zip "cwsdpmi" "https://lib.openmpt.org/files/libopenmpt/contrib/djgpp/cwsdpmi/csdpmi7b.zip" "build/externals/csdpmi7b.zip" "." +download "https://lib.openmpt.org/files/libopenmpt/contrib/djgpp/cwsdpmi/csdpmi7s.zip" "build/externals/csdpmi7s.zip" +#download_and_unpack_zip "cwsdpmi" "https://djgpp.mirror.garr.it/current/v2misc/csdpmi7b.zip" "build/externals/csdpmi7b.zip" "." +#download "https://djgpp.mirror.garr.it/current/v2misc/csdpmi7s.zip" "build/externals/csdpmi7s.zip" +download_and_unpack_7z "winamp" "https://web.archive.org/web/20131217072017if_/http://download.nullsoft.com/winamp/plugin-dev/WA5.55_SDK.exe" "build/externals/WA5.55_SDK.exe" "." +ln -s OUT.H include/winamp/Winamp/out.h +download_and_unpack_zip "xmplay" "https://www.un4seen.com/files/xmp-sdk.zip" "build/externals/xmp-sdk.zip" "." diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk index 575215a8b..69938ec5c 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk @@ -13,15 +13,25 @@ AR = ar endif ifneq ($(STDCXX),) -CXXFLAGS_STDCXX = -std=$(STDCXX) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +# We do not enable C++20 for fuzzer builds, because it prevents detecting +# shifting of signed values which changed from undefined to defined behaviour +# in C++20. As we still support C+ü+17, we need to catch these problem cases. +#else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +#CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread else -ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17) -CXXFLAGS_STDCXX = -std=c++17 +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread endif -CFLAGS_STDC = -std=c99 CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread DYNLINK=0 SHARED_LIB=0 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-aocc.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-aocc.mk new file mode 100644 index 000000000..ac5697b84 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-aocc.mk @@ -0,0 +1,68 @@ + +ifeq ($(origin CC),default) +CC = $(TOOLCHAIN_PREFIX)clang$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin CXX),default) +CXX = $(TOOLCHAIN_PREFIX)clang++$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX) +endif + +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread +else +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread + +CPPFLAGS += +CXXFLAGS += -fPIC +CFLAGS += -fPIC +LDFLAGS += +LDLIBS += -lm +ARFLAGS := rcs + +MODERN=1 +NATIVE=1 +OPTIMIZE=vectorize +OPTIMIZE_LTO=1 + +ifeq ($(NATIVE),1) +CXXFLAGS += -march=native +CFLAGS += -march=native +endif + +ifeq ($(OPTIMIZE_LTO),1) +CXXFLAGS += -flto +CFLAGS += -flto +LDFLAGS += -flto +endif + +ifeq ($(CHECKED_ADDRESS),1) +CXXFLAGS += -fsanitize=address +CFLAGS += -fsanitize=address +endif + +ifeq ($(CHECKED_UNDEFINED),1) +CXXFLAGS += -fsanitize=undefined +CFLAGS += -fsanitize=undefined +endif + +include build/make/warnings-clang.mk + +EXESUFFIX= diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk index e0455e501..cb5d8b314 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk @@ -13,15 +13,22 @@ AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX) endif ifneq ($(STDCXX),) -CXXFLAGS_STDCXX = -std=$(STDCXX) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread else -ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17) -CXXFLAGS_STDCXX = -std=c++17 +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread endif -CFLAGS_STDC = -std=c99 CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread CPPFLAGS += CXXFLAGS += -fPIC @@ -30,9 +37,19 @@ LDFLAGS += LDLIBS += -lm ARFLAGS := rcs +ifeq ($(NATIVE),1) +CXXFLAGS += -march=native +CFLAGS += -march=native +endif + +ifeq ($(MODERN),1) +LDFLAGS += -fuse-ld=lld +endif + ifeq ($(OPTIMIZE_LTO),1) CXXFLAGS += -flto=thin CFLAGS += -flto=thin +LDFLAGS += -Wl,--thinlto-jobs=all endif ifeq ($(CHECKED_ADDRESS),1) diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk index 63af1f984..fde700185 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk @@ -8,6 +8,8 @@ include build/make/config-clang.mk # Mac OS X overrides DYNLINK=0 SHARED_SONAME=0 +MPT_COMPILER_NOSECTIONS=1 +MPT_COMPILER_NOGCSECTIONS=1 else ifeq ($(HOST_FLAVOUR),MSYS2) @@ -33,6 +35,11 @@ else ifeq ($(HOST_FLAVOUR),LINUX) include build/make/config-gcc.mk +else ifeq ($(HOST_FLAVOUR),NETBSD) + +include build/make/config-gcc.mk +NO_PORTAUDIOCPP?=1 + else ifeq ($(HOST_FLAVOUR),FREEBSD) include build/make/config-clang.mk @@ -56,13 +63,13 @@ include build/make/config-gcc.mk else -include build/make/config-generic.mk +include build/make/config-unknown.mk endif else -include build/make/config-generic.mk +include build/make/config-unknown.mk endif diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk index 8d545cf00..403c1d9a9 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk @@ -14,21 +14,369 @@ endif # Note that we are using GNU extensions instead of 100% standards-compliant # mode, because otherwise DJGPP-specific headers/functions are unavailable. -CXXFLAGS_STDCXX = -std=gnu++17 -CFLAGS_STDC = -std=gnu99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -fpermissive +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=gnu++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=gnu++20 -fexceptions -frtti -fpermissive +else +CXXFLAGS_STDCXX = -std=gnu++17 -fexceptions -frtti -fpermissive +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=gnu17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=gnu17 +else +CFLAGS_STDC = -std=gnu11 +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) -fallow-store-data-races -fno-threadsafe-statics +CFLAGS += $(CFLAGS_STDC) -fallow-store-data-races -CPPFLAGS += -CXXFLAGS += -march=i386 -m80387 -mtune=pentium -ffast-math -CFLAGS += -march=i386 -m80387 -mtune=pentium -ffast-math -LDFLAGS += -LDLIBS += -lm -ARFLAGS := rcs +CPU?=generic/common -include build/make/warnings-gcc.mk +# Enable 128bit SSE registers. +# This requires pure DOS with only CWSDPMI as DOS extender. +# It will not work in a Win9x DOS window, or in WinNT NTVDM. +# It will also not work with almost all other VCPI or DPMI hosts (e.g. EMM386.EXE). +SSE?=0 + +ifneq ($(SSE),0) + FPU_NONE := -mno-80387 + FPU_287 := -m80387 -mfpmath=387 -mno-fancy-math-387 + FPU_387 := -m80387 -mfpmath=387 + FPU_MMX := -m80387 -mmmx -mfpmath=387 + FPU_3DNOW := -m80387 -mmmx -m3dnow -mfpmath=387 + FPU_3DNOWA := -m80387 -mmmx -m3dnow -m3dnowa -mfpmath=387 + FPU_3DASSE := -m80387 -mmmx -m3dnow -m3dnowa -mfxsr -msse -mfpmath=sse,387 + FPU_SSE := -m80387 -mmmx -mfxsr -msse -mfpmath=sse,387 + FPU_SSE2 := -m80387 -mmmx -mfxsr -msse -msse2 -mfpmath=sse + FPU_SSE3 := -m80387 -mmmx -mfxsr -msse -msse2 -msse3 -mfpmath=sse + FPU_SSSE3 := -m80387 -mmmx -mfxsr -msse -msse2 -msse3 -mssse3 -mfpmath=sse + FPU_SSE4_1 := -m80387 -mmmx -mfxsr -msse -msse2 -msse3 -mssse3 -msse4.1 -mfpmath=sse + FPU_SSE4_2 := -m80387 -mmmx -mfxsr -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mfpmath=sse + FPU_SSE4A := -m80387 -mmmx -mfxsr -msse -msse2 -msse3 -mssse3 -msse4a -mfpmath=sse +else + FPU_NONE := -mno-80387 + FPU_287 := -m80387 -mfpmath=387 -mno-fancy-math-387 + FPU_387 := -m80387 -mfpmath=387 + FPU_MMX := -m80387 -mmmx -mfpmath=387 + FPU_3DNOW := -m80387 -mmmx -m3dnow -mfpmath=387 + FPU_3DNOWA := -m80387 -mmmx -m3dnow -m3dnowa -mfpmath=387 + FPU_3DASSE := -mno-sse -mno-fxsr -m80387 -mmmx -m3dnow -m3dnowa -mfpmath=387 + FPU_SSE := -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSE2 := -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSE3 := -mno-sse3 -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSSE3 := -mno-ssse3 -mno-sse3 -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSE4_1 := -mno-sse4.1 -mno-ssse3 -mno-sse3 -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSE4_2 := -mno-sse4.2 -mno-sse4.1 -mno-ssse3 -mno-sse3 -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 + FPU_SSE4A := -mno-sse4a -mno-ssse3 -mno-sse3 -mno-sse2 -mno-sse -mno-fxsr -m80387 -mmmx -mfpmath=387 +endif + +OPT_DEF := -Os +OPT_SIMD := -O3 + + + +CACHE_386 :=64 # 0/64/128 +CACHE_486 :=128 # 0/64/128/256 +CACHE_S7 :=256 # 128/256/512 +CACHE_SS7 :=512 # 256/512/1024 + + +CACHE_PENTIUMPRO :=512 # 256/512/1024 +CACHE_PENTIUM2 :=512 # 256/512 +CACHE_PENTIUM3 :=256 # 256/512 +CACHE_PENTIUM4 :=256 # 256/512 +CACHE_PENTIUM41 :=512 # 512/1024 +CACHE_CORE :=2048 # 512/1024/2048 +CACHE_CORE2 :=2048 # 1024/2048/3072/4096/6144 + +CACHE_CELERON :=0 # 0/128/256 +CACHE_PENTIUMM :=1024 # 1024/2048 +CACHE_ATOM :=512 # 512 + + +CACHE_K63 :=256 # 128/256 +CACHE_ATHLON :=512 # 512 +CACHE_ATHLONXP :=256 # 256/512 +CACHE_ATHLON64 :=512 # 256/512/1024 + +CACHE_DURON :=64 # 64 +CACHE_DURONXP :=64 # 64 +CACHE_SEMPRON64 :=128 # 128/256/512 + + + +TUNE_586 :=-mtune=pentium +TUNE_586MMX :=-mtune=pentium-mmx +TUNE_686 :=-mtune=pentiumpro +TUNE_686MMX :=-mtune=pentium2 +TUNE_686SSE :=-mtune=pentium3 +TUNE_686SSE2:=-mtune=pentium-m +TUNE_686SSE3:=-mtune=pentium-m + + + +generic/early := $(XXX) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) + +generic/common := $(XXX) -march=i386 $(FPU_387) -mtune=pentium $(OPT_DEF) +generic/late := $(XXX) -march=i686 $(FPU_SSSE3) -mtune=generic $(OPT_SIMD) + + + +generic/nofpu := $(X__) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) # 386SX, 386DX, 486SX, Cyrix Cx486SLC..Cx486S, NexGen Nx586 + +generic/386 := $(X__) -march=i386 $(FPU_387) -mtune=i386 $(OPT_DEF) # 386+387 + +generic/486 := $(XX_) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) # 486DX, AMD Am5x86, Cyrix Cx4x86DX..6x86L, NexGen Nx586-PF +generic/486-mmx := $(___) -march=i486 $(FPU_MMX) -mtune=winchip-c6 $(OPT_SIMD) # IDT WinChip-C6, Rise mP6 +generic/486-3dnow := $(___) -march=i486 $(FPU_3DNOW) -mtune=winchip2 $(OPT_SIMD) # IDT WinChip-2 + +generic/586 := $(XX_) -march=i586 $(FPU_387) -mtune=pentium $(OPT_DEF) # Intel Pentium, AMD K5 +generic/586-mmx := $(XX_) -march=pentium-mmx $(FPU_MMX) -mtune=pentium-mmx $(OPT_SIMD) # Intel Pentium-MMX, AMD K6 +generic/586-3dnow := $(XX_) -march=k6-2 $(FPU_3DNOW) -mtune=k6-2 $(OPT_SIMD) # AMD K6-2..K6-3 + +generic/686 := $(___) -march=pentiumpro $(FPU_387) -mtune=pentiumpro $(OPT_DEF) # Intel Pentium-Pro +generic/686-mmx := $(XXX) -march=i686 $(FPU_MMX) -mtune=pentium2 $(OPT_SIMD) # Intel Pentium-2.., AMD Bulldozer.., VIA C3-Nehemiah.., Cyrix 6x86MX.., Transmeta Crusoe.., NSC Geode-GX1.. +generic/686-3dnow := $(___) -march=i686 $(FPU_3DNOW) -mtune=c3 $(OPT_SIMD) # VIA Cyrix-3..C3-Ezra +generic/686-3dnowa:= $(XX_) -march=athlon $(FPU_3DNOWA) -mtune=athlon $(OPT_SIMD) # AMD Athlon..K10 + + +generic/sse := $(X__) -march=i686 $(FPU_SSE) -mtune=pentium3 $(OPT_SIMD) # Intel Pentium-3.., AMD Athlon-XP.., VIA C3-Nehemiah.., Transmeta Efficeon.., DM&P Vortex86DX3.. +generic/sse2 := $(XX_) -march=i686 $(FPU_SSE2) -mtune=generic $(OPT_SIMD) # Intel Pentium-4.., AMD Athlon-64.., VIA C7-Esther.., Transmeta Efficeon.. +generic/sse3 := $(___) -march=i686 $(FPU_SSE3) -mtune=generic $(OPT_SIMD) # Intel Core.., AMD Athlon-64-X2.., VIA C7-Esther.., Transmeta Efficeon-88xx.. +generic/ssse3 := $(___) -march=i686 $(FPU_SSSE3) -mtune=generic $(OPT_SIMD) # Intel Core-2.., AMD Bobcat.., Via Nano-1000.. +generic/sse4_1 := $(___) -march=i686 $(FPU_SSE4_1) -mtune=generic $(OPT_SIMD) # Intel Core-1st, AMD Bulldozer.., Via Nano-3000.. +generic/sse4_2 := $(___) -march=i686 $(FPU_SSE4_2) -mtune=generic $(OPT_SIMD) # Intel Core-1st, AMD Bulldozer.., Via Nano-C.. + + + +intel/i386 := $(XX_) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) +intel/i486sx := $(___) -march=i486 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) +intel/i386+80287 := $(___) -march=i386 $(FPU_287) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) + +intel/i386+80387 := $(XX_) -march=i386 $(FPU_387) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) +intel/i486dx := $(XXX) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) +intel/pentium := $(XXX) -march=pentium $(FPU_387) -mtune=pentium $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +intel/pentium-mmx := $(XXX) -march=pentium-mmx $(FPU_MMX) -mtune=pentium-mmx $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_S7) +intel/pentium-pro := $(___) -march=pentiumpro $(FPU_387) -mtune=pentiumpro $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_PENTIUMPRO) +intel/pentium2 := $(___) -march=pentium2 $(FPU_MMX) -mtune=pentium2 $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_PENTIUM2) +intel/pentium3 := $(___) -march=pentium3 $(FPU_SSE) -mtune=pentium3 $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_PENTIUM3) +intel/pentium4 := $(___) -march=pentium4 $(FPU_SSE2) -mtune=pentium4 $(OPT_SIMD) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_PENTIUM4) +intel/pentium4.1 := $(___) -march=prescott $(FPU_SSE3) -mtune=prescott $(OPT_SIMD) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_PENTIUM41) +intel/core2 := $(___) -march=core2 $(FPU_SSSE3) -mtune=core2 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_CORE2) + +intel/celeron := $(___) -march=pentium2 $(FPU_MMX) -mtune=pentium2 $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_CELERON) +intel/pentium-m := $(___) -march=pentium-m $(FPU_SSE2) -mtune=pentium-m $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_PENTIUMM) +intel/core := $(___) -march=pentium-m $(FPU_SSE3) -mtune=core2 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_CORE) +intel/atom := $(___) -march=bonnell $(FPU_SSSE3) -mtune=bonnell $(OPT_SIMD) --param l1-cache-size=24 --param l2-cache-size=$(CACHE_ATOM) + +intel/late := $(XX_) -march=i686 $(FPU_SSSE3) -mtune=intel $(OPT_SIMD) + + + +amd/am386 := $(___) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) +amd/am486sx := $(___) -march=i486 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) + +amd/am386+80387 := $(___) -march=i386 $(FPU_387) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) +amd/am486dx := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) +amd/am486dxe := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_486) +amd/am5x86 := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_486) +amd/k5 := $(XXX) -march=i586 $(FPU_387) -mtune=i586 $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +amd/k5-pentium := $(XXX) -march=i586 $(FPU_387) -mtune=pentium $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +amd/k5-pentiumpro := $(XXX) -march=i586 $(FPU_387) -mtune=pentiumpro $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +amd/k5-pentium2 := $(XXX) -march=i586 $(FPU_387) -mtune=pentium2 $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +amd/k5-k6 := $(XXX) -march=i586 $(FPU_387) -mtune=k6 $(OPT_DEF) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_S7) +amd/k6 := $(XXX) -march=k6 $(FPU_MMX) -mtune=k6 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_S7) +amd/k6-2 := $(XXX) -march=k6-2 $(FPU_3DNOW) -mtune=k6-2 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_SS7) +amd/k6-3 := $(___) -march=k6-3 $(FPU_3DNOW) -mtune=k6-3 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_K63) +amd/athlon := $(XX_) -march=athlon $(FPU_3DNOWA) -mtune=athlon $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_ATHLON) +amd/athlon-xp := $(XX_) -march=athlon-xp $(FPU_3DASSE) -mtune=athlon-xp $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_ATHLONXP) +amd/athlon64 := $(X__) -march=k8 $(FPU_SSE2) -mtune=k8 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_ATHLON64) +amd/athlon64-sse3 := $(___) -march=k8-sse3 $(FPU_SSE3) -mtune=k8-sse3 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_ATHLON64) +amd/k10 := $(___) -march=amdfam10 $(FPU_SSE4A) -mtune=amdfam10 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=512 + +amd/duron := $(XX_) -march=athlon $(FPU_3DNOWA) -mtune=athlon $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_DURON) +amd/duron-xp := $(___) -march=athlon-xp $(FPU_3DASSE) -mtune=athlon-xp $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_DURONXP) +amd/sempron64 := $(___) -march=k8 $(FPU_SSE2) -mtune=k8 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=$(CACHE_SEMPRON64) + +amd/geode-gx := $(___) -march=geode $(FPU_3DNOW) -mtune=geode $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=0 +amd/geode-lx := $(___) -march=geode $(FPU_3DNOW) -mtune=geode $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=128 +amd/geode-nx := $(___) -march=athlon-xp $(FPU_3DASSE) -mtune=athlon-xp $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=256 +amd/bobcat := $(___) -march=btver1 $(FPU_SSE4A) -mtune=btver1 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=512 +amd/jaguar := $(___) -march=btver2 $(FPU_SSE4A) -mtune=btver2 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=1024 + +amd/late-3dnow := $(XX_) -march=athlon-xp $(FPU_3DASSE) -mtune=athlon-xp $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=512 +amd/late := $(XX_) -march=i686 $(FPU_SSE4A) -mtune=generic $(OPT_SIMD) + + + +nexgen/nx586 := $(___) -march=i486 $(FPU_NONE) $(TUNE_586) $(OPT_DEF) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_486) + +nexgen/nx586pf := $(___) -march=i486 $(FPU_387) $(TUNE_586) $(OPT_DEF) --param l1-cache-size=16 --param l2-cache-size=$(CACHE_486) + + + +ibm/386slc := $(___) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_386) +ibm/486slc := $(___) -march=i486 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_386) +ibm/486bl := $(___) -march=i486 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_486) + + + +cyrix/cx486slc := $(___) -march=i386 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=1 --param l2-cache-size=$(CACHE_386) +cyrix/cx486dlc := $(___) -march=i386 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=1 --param l2-cache-size=$(CACHE_386) +cyrix/cx4x86s := $(___) -march=i486 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=2 --param l2-cache-size=$(CACHE_486) + +cyrix/cx4x86dx := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) +cyrix/cx5x86 := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_486) +cyrix/6x86 := $(XXX) -march=i486 $(FPU_387) $(TUNE_586) $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_S7) +cyrix/6x86l := $(___) -march=i486 $(FPU_387) $(TUNE_586) $(OPT_DEF) --param l1-cache-size=12 --param l2-cache-size=$(CACHE_S7) +cyrix/6x86mx := $(___) -march=i686 $(FPU_MMX) $(TUNE_686MMX) $(OPT_SIMD) --param l1-cache-size=48 --param l2-cache-size=$(CACHE_SS7) + +cyrix/mediagx-gx := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=9 --param l2-cache-size=0 +cyrix/mediagx-gxm := $(___) -march=i686 $(FPU_MMX) $(TUNE_686MMX) $(OPT_SIMD) --param l1-cache-size=9 --param l2-cache-size=0 + + + +nsc/geode-gx1 := $(___) -march=i686 $(FPU_MMX) $(TUNE_686MMX) $(OPT_SIMD) --param l1-cache-size=9 --param l2-cache-size=0 +nsc/geode-gx2 := $(___) -march=geode $(FPU_3DNOW) -mtune=geode $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=0 + + + +idt/winchip-c6 := $(XX_) -march=winchip-c6 $(FPU_MMX) -mtune=winchip-c6 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_S7) +idt/winchip2 := $(XX_) -march=winchip2 $(FPU_3DNOW) -mtune=winchip2 $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=$(CACHE_SS7) + + + +via/cyrix3-joshua := $(XX_) -march=i686 $(FPU_3DNOW) $(TUNE_686MMX) $(OPT_SIMD) --param l1-cache-size=48 --param l2-cache-size=256 +via/cyrix3-samuel := $(___) -march=c3 $(FPU_3DNOW) -mtune=c3 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=0 +via/c3-samuel2 := $(___) -march=samuel-2 $(FPU_3DNOW) -mtune=samuel-2 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=64 +via/c3-ezra := $(___) -march=samuel-2 $(FPU_3DNOW) -mtune=samuel-2 $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=64 +via/c3-nehemiah := $(XX_) -march=nehemiah $(FPU_SSE) -mtune=nehemiah $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=64 +via/c7-esther := $(XX_) -march=esther $(FPU_SSE3) -mtune=esther $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=128 + +via/late := $(XX_) -march=i686 $(FPU_SSE3) -mtune=esther $(OPT_SIMD) + + + +umc/u5s := $(___) -march=i486 $(FPU_NONE) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) +umc/u5d := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=6 --param l2-cache-size=$(CACHE_486) + + + +transmeta/crusoe := $(___) -march=i686 $(FPU_MMX) $(TUNE_686MMX) $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=256 +transmeta/efficeon:= $(___) -march=i686 $(FPU_SSE2) $(TUNE_686SSE2) $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=1024 +transmeta/tm8800 := $(___) -march=i686 $(FPU_SSE3) $(TUNE_686SSE3) $(OPT_SIMD) --param l1-cache-size=64 --param l2-cache-size=1024 + + + +uli/m6117c := $(___) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) + + + +rise/mp6 := $(XX_) -march=i586 $(FPU_MMX) $(TUNE_586MMX) $(OPT_SIMD) --param l1-cache-size=8 --param l2-cache-size=$(CACHE_SS7) + + + +sis/55x := $(___) -march=i586 $(FPU_MMX) $(TUNE_586MMX) $(OPT_SIMD) --param l1-cache-size=8 --param l2-cache-size=0 + + + +dmnp/m6117d := $(___) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=0 --param l2-cache-size=$(CACHE_386) +dmnp/vortex86sx := $(___) -march=i386 $(FPU_NONE) -mtune=i386 $(OPT_DEF) --param l1-cache-size=16 --param l2-cache-size=0 + +dmnp/vortex86dx := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=16 --param l2-cache-size=256 +dmnp/vortex86mx := $(___) -march=i486 $(FPU_387) -mtune=i486 $(OPT_DEF) --param l1-cache-size=16 --param l2-cache-size=256 +dmnp/vortex86 := $(___) -march=i586 $(FPU_MMX) $(TUNE_586MMX) $(OPT_SIMD) --param l1-cache-size=8 --param l2-cache-size=0 +dmnp/vortex86dx2 := $(___) -march=i586 $(FPU_MMX) $(TUNE_586MMX) $(OPT_SIMD) --param l1-cache-size=16 --param l2-cache-size=256 +dmnp/vortex86dx3 := $(___) -march=i686 $(FPU_SSE) $(TUNE_686SSE) $(OPT_SIMD) --param l1-cache-size=32 --param l2-cache-size=512 + + + +ifeq ($($(CPU)),) +$(error unknown CPU) +endif +CPUFLAGS := $($(CPU)) + +# parse CPU optimization options +ifeq ($(findstring -O3,$(CPUFLAGS)),-O3) +OPTIMIZE=vectorize +CPUFLAGS := $(filter-out -O3,$(CPUFLAGS)) +endif +ifeq ($(findstring -Os,$(CPUFLAGS)),-Os) +OPTIMIZE=size +CPUFLAGS := $(filter-out -Os,$(CPUFLAGS)) +endif + +# Handle the no-FPU case by linking DJGPP's own emulator. +# DJGPP does not provide a suitable soft-float library for -mno-80397. +ifeq ($(findstring -mno-80387,$(CPUFLAGS)),-mno-80387) +CPU_CFLAGS := $(filter-out -mno-80387,$(CPUFLAGS)) -m80387 +CPU_LDFLAGS := +CPU_LDLIBS := -lemu +else ifeq ($(findstring -mno-fancy-math-387,$(CPUFLAGS)),-mno-fancy-math-387) +CPU_CFLAGS := $(filter-out -mno-fancy-math-387,$(CPUFLAGS)) +CPU_LDFLAGS := +CPU_LDLIBS := -lemu +else +CPU_CFLAGS := $(CPUFLAGS) +CPU_LDFLAGS := +CPU_LDLIBS := +endif + +ifeq ($(FLAVOURED_DIR),1) EXESUFFIX=.exe +ifeq ($(findstring -msse,$(CPUFLAGS)),-msse) +FLAVOUR_DIR=$(CPU)-sse/ +FLAVOUR_O=.$(subst /,-,$(CPU)-sse) +else +FLAVOUR_DIR=$(CPU)/ +FLAVOUR_O=.$(subst /,-,$(CPU)) +endif +FLAVOUR_DIR_MADE:=$(shell $(MKDIR_P) bin/$(FLAVOUR_DIR)) + +else ifeq ($(FLAVOURED_EXE),1) + +ifeq ($(CPU),generic/common) +EXESUFFIX=.exe +else +EXESUFFIX:=.exe +ifeq ($(findstring -msse,$(CPUFLAGS)),-msse) +EXESUFFIX:=-SSE$(EXESUFFIX) +endif +ifeq ($(OPTIMIZE),size) +EXESUFFIX:=-Os$(EXESUFFIX) +else ifeq ($(OPTIMIZE),speed) +EXESUFFIX:=-O2$(EXESUFFIX) +else ifeq ($(OPTIMIZE),vectorize) +EXESUFFIX:=-O3$(EXESUFFIX) +endif +EXESUFFIX:=-$(subst /,-,$(CPU))$(EXESUFFIX) +endif +ifeq ($(findstring -msse,$(CPUFLAGS)),-msse) +FLAVOUR_O=.$(subst /,-,$(CPU)-sse) +else +FLAVOUR_O=.$(subst /,-,$(CPU)) +endif + +else + +EXESUFFIX=.exe +FLAVOUR_DIR= +FLAVOUR_O= + +endif + +CPPFLAGS += +CXXFLAGS += $(CPU_CFLAGS) +CFLAGS += $(CPU_CFLAGS) +LDFLAGS += $(CPU_LDFLAGS) +LDLIBS += -lm $(CPU_LDLIBS) +ARFLAGS := rcs + +OPTIMIZE_FASTMATH=1 + +include build/make/warnings-gcc.mk DYNLINK=0 SHARED_LIB=0 @@ -36,18 +384,24 @@ STATIC_LIB=1 SHARED_SONAME=0 DEBUG=0 -OPTIMIZE=0 -OPTIMIZE_SIZE=1 IS_CROSS=1 # generates warnings MPT_COMPILER_NOVISIBILITY=1 -# causes crashes on process shutdown, -# makes memory locking difficult +# causes crashes on process shutdown with liballegro MPT_COMPILER_NOGCSECTIONS=1 +ifeq ($(OPTIMIZE_LTO),1) +CXXFLAGS += -flto=auto -Wno-attributes +CFLAGS += -flto=auto -Wno-attributes +endif + +ifneq ($(DEBUG),1) +LDFLAGS += -s +endif + ifeq ($(ALLOW_LGPL),1) LOCAL_ZLIB=1 LOCAL_MPG123=1 @@ -68,18 +422,4 @@ NO_SDL2=1 NO_SNDFILE=1 NO_FLAC=1 -ifeq ($(BUNDLED_ALLEGRO42),1) - -CPPFLAGS_ALLEGRO42 := -Iinclude/allegro42/include -DALLEGRO_HAVE_STDINT_H -DLONG_LONG="long long" -LDFLAGS_ALLEGRO42 := -LDLIBS_ALLEGRO42 := include/allegro42/lib/djgpp/liballeg.a - -include/allegro42/lib/djgpp/liballeg.a: - +cd include/allegro42 && ./xmake.sh clean - +cd include/allegro42 && ./xmake.sh lib - -bin/openmpt123$(EXESUFFIX): include/allegro42/lib/djgpp/liballeg.a - -MISC_OUTPUTS += include/allegro42/lib/djgpp/liballeg.a - -endif +USE_ALLEGRO42=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk index 02ee0d916..b5571872c 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk @@ -19,12 +19,18 @@ EMSCRIPTEN_PORTS?=0 ifneq ($(STDCXX),) CXXFLAGS_STDCXX = -std=$(STDCXX) +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 else -ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17) CXXFLAGS_STDCXX = -std=c++17 endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 +else +CFLAGS_STDC = -std=c11 endif -CFLAGS_STDC = -std=c99 CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) @@ -149,8 +155,7 @@ NO_SHARED_LINKER_FLAG=1 # Disable the generic compiler optimization flags as emscripten is sufficiently different. # Optimization flags are hard-coded for emscripten in this file. DEBUG=0 -OPTIMIZE=0 -OPTIMIZE_SIZE=0 +OPTIMIZE=none IS_CROSS=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk index 4ed19fb22..8130a6fdd 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk @@ -13,28 +13,49 @@ AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX) endif ifneq ($(STDCXX),) -CXXFLAGS_STDCXX = -std=$(STDCXX) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread else -ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17) -CXXFLAGS_STDCXX = -std=c++17 +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread endif -CFLAGS_STDC = -std=c99 CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread CPPFLAGS += -CXXFLAGS += -fPIC -CFLAGS += -fPIC +CXXFLAGS += -fPIC +CFLAGS += -fPIC LDFLAGS += LDLIBS += -lm ARFLAGS := rcs +ifeq ($(NATIVE),1) +CXXFLAGS += -march=native +CFLAGS += -march=native +endif + +ifeq ($(MODERN),1) +LDFLAGS += -fuse-ld=gold +endif + ifeq ($(OPTIMIZE_LTO),1) CXXFLAGS += -flto CFLAGS += -flto endif +ifeq ($(ANALYZE),1) +CXXFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference +CFLAGS += -fanalyzer -Wno-analyzer-malloc-leak -Wno-analyzer-null-dereference -Wno-analyzer-possible-null-argument -Wno-analyzer-possible-null-dereference +endif + ifeq ($(CHECKED_ADDRESS),1) CXXFLAGS += -fsanitize=address CFLAGS += -fsanitize=address diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk index d299664ef..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk @@ -1,34 +0,0 @@ - -$(warning warning: CONFIG=generic is deprecated. Use CONFIG=standard instead.) - -ifeq ($(origin CC),default) -CC = cc -endif -ifeq ($(origin CXX),default) -CXX = c++ -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = ar -endif - -CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -CXXFLAGS += -CFLAGS += -LDFLAGS += -LDLIBS += -ARFLAGS := rcs - -MPT_COMPILER_GENERIC=1 -SHARED_LIB=0 -DYNLINK=0 - -EXESUFFIX= - diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk index 191dbb39e..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk @@ -1,4 +0,0 @@ - -$(warning warning: CONFIG=haiku is deprecated. The OS is auto-detected.) - -include config-defaults.mk diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-icx.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-icx.mk new file mode 100644 index 000000000..cd7cd3967 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-icx.mk @@ -0,0 +1,69 @@ + +ifeq ($(origin CC),default) +CC = $(TOOLCHAIN_PREFIX)icx$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin CXX),default) +CXX = $(TOOLCHAIN_PREFIX)icpx$(TOOLCHAIN_SUFFIX) +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX) +endif + +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti -pthread +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti -pthread +else +CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -pthread +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) -pthread +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 -pthread +else +CFLAGS_STDC = -std=c11 -pthread +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) +LDFLAGS += -pthread + +CPPFLAGS += +CXXFLAGS += -fPIC +CFLAGS += -fPIC +LDFLAGS += +LDLIBS += +ARFLAGS := rcs + +MODERN=0 +NATIVE=0 +OPTIMIZE=vectorize +OPTIMIZE_FASTMATH=0 +OPTIMIZE_LTO=1 + +FASTMATH_STYLE= + +CXXFLAGS += -fp-model=precise +CFLAGS += -fp-model=precise + +ifeq ($(OPTIMIZE_LTO),1) +CXXFLAGS += -ipo +CFLAGS += -ipo +LDFLAGS += -ipo +endif + +ifeq ($(CHECKED_ADDRESS),1) +CXXFLAGS += -fsanitize=address +CFLAGS += -fsanitize=address +endif + +ifeq ($(CHECKED_UNDEFINED),1) +CXXFLAGS += -fsanitize=undefined +CFLAGS += -fsanitize=undefined +endif + +include build/make/warnings-clang.mk + +EXESUFFIX= diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk index 278b395eb..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk @@ -1,4 +0,0 @@ - -$(warning warning: CONFIG=macosx is deprecated. The OS is auto-detected.) - -include config-defaults.mk diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk index fd655435a..840c73d2a 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk @@ -26,12 +26,24 @@ ifeq ($(origin AR),default) AR = $(MINGW_ARCH)-w64-mingw32-ar$(MINGW_FLAVOUR) endif +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=c++20 -fexceptions -frtti +else CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti -CFLAGS_STDC = -std=c99 +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=c17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=c17 +else +CFLAGS_STDC = -std=c11 +endif CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) -CPPFLAGS += +CPPFLAGS += -DNOMINMAX ifeq ($(MINGW_COMPILER),clang) CXXFLAGS += -municode CFLAGS += -municode @@ -41,9 +53,12 @@ CXXFLAGS += -municode -mthreads CFLAGS += -municode -mthreads LDFLAGS += -mconsole endif -LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm +LDLIBS += -lm ARFLAGS := rcs +LDLIBS_LIBOPENMPTTEST += -lole32 -lrpcrt4 +LDLIBS_OPENMPT123 += -lwinmm + PC_LIBS_PRIVATE += -lole32 -lrpcrt4 ifeq ($(WINDOWS_FAMILY),) @@ -52,13 +67,10 @@ else ifeq ($(WINDOWS_FAMILY),desktop-app) # nothing else ifeq ($(WINDOWS_FAMILY),app) CPPFLAGS += -DWINAPI_FAMILY=2 -OPENMPT123=0 else ifeq ($(WINDOWS_FAMILY),phone-app) CPPFLAGS += -DWINAPI_FAMILY=3 -OPENMPT123=0 else ifeq ($(WINDOWS_FAMILY),pc-app) CPPFLAGS += -DWINAPI_FAMILY=2 -OPENMPT123=0 else $(error unknown WINDOWS_FAMILY) endif @@ -74,11 +86,11 @@ CPPFLAGS += -D_WIN32_WINDOWS=0x0490 else ifeq ($(WINDOWS_VERSION),winnt4) CPPFLAGS += -D_WIN32_WINNT=0x0400 else ifeq ($(WINDOWS_VERSION),win2000) -CPPFLAGS += -D_WIN32_WINNT=0x0500 +CPPFLAGS += -DNTDDI_VERSION=0x05000000 -D_WIN32_WINNT=0x0500 else ifeq ($(WINDOWS_VERSION),winxp) -CPPFLAGS += -D_WIN32_WINNT=0x0501 +CPPFLAGS += -DNTDDI_VERSION=0x05010000 -D_WIN32_WINNT=0x0501 else ifeq ($(WINDOWS_VERSION),winxp64) -CPPFLAGS += -D_WIN32_WINNT=0x0502 +CPPFLAGS += -DNTDDI_VERSION=0x05020100 -D_WIN32_WINNT=0x0502 else ifeq ($(WINDOWS_VERSION),winvista) CPPFLAGS += -DNTDDI_VERSION=0x06000000 -D_WIN32_WINNT=0x0600 else ifeq ($(WINDOWS_VERSION),win7) @@ -89,6 +101,8 @@ else ifeq ($(WINDOWS_VERSION),win8.1) CPPFLAGS += -DNTDDI_VERSION=0x06030000 -D_WIN32_WINNT=0x0603 else ifeq ($(WINDOWS_VERSION),win10) CPPFLAGS += -DNTDDI_VERSION=0x0A000000 -D_WIN32_WINNT=0x0A00 +else ifeq ($(WINDOWS_VERSION),win11) +CPPFLAGS += -DNTDDI_VERSION=0x0A00000B -D_WIN32_WINNT=0x0A00 else $(error unknown WINDOWS_VERSION) endif diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk index 2b45529b3..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk @@ -1,66 +0,0 @@ - -ifeq ($(origin CC),default) -CC = mingw32-gcc$(MINGW_FLAVOUR) -endif -ifeq ($(origin CXX),default) -CXX = mingw32-g++$(MINGW_FLAVOUR) -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = mingw32-gcc-ar$(MINGW_FLAVOUR) -endif - -CXXFLAGS_STDCXX = -std=gnu++17 -CFLAGS_STDC = -std=gnu99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -DWIN32 -D_WIN32 -DWINVER=0x0410 -D_WIN32_WINDOWS=0x0410 -DMPT_BUILD_RETRO -CXXFLAGS += -mconsole -mthreads -CFLAGS += -mconsole -mthreads -LDFLAGS += -LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm -ARFLAGS := rcs - -LDFLAGS += -static -static-libgcc -static-libstdc++ - -#CXXFLAGS += -ffunction-sections -fdata-sections -#CFLAGS += -ffunction-sections -fdata-sections -#LDFLAGS += -Wl,--gc-sections - -CXXFLAGS += -march=i486 -m80387 -mtune=pentium -CFLAGS += -march=i486 -m80387 -mtune=pentium - -PC_LIBS_PRIVATE += -lole32 -lrpcrt4 - -include build/make/warnings-gcc.mk - -EXESUFFIX=.exe -SOSUFFIX=.dll -SOSUFFIXWINDOWS=1 - -DYNLINK=0 -SHARED_LIB=1 -STATIC_LIB=0 -SHARED_SONAME=0 - -FORCE_UNIX_STYLE_COMMANDS=1 - -IN_OPENMPT=1 -XMP_OPENMPT=1 - -IS_CROSS=1 - -NO_ZLIB=1 -NO_MPG123=1 -NO_OGG=1 -NO_VORBIS=1 -NO_VORBISFILE=1 -NO_PORTAUDIO=1 -NO_PORTAUDIOCPP=1 -NO_PULSEAUDIO=1 -NO_SDL2=1 -NO_SNDFILE=1 -NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw.mk new file mode 100644 index 000000000..e7cef8e3a --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw.mk @@ -0,0 +1,106 @@ + +ifeq ($(origin CC),default) +CC = mingw32-gcc$(MINGW_FLAVOUR) +endif +ifeq ($(origin CXX),default) +CXX = mingw32-g++$(MINGW_FLAVOUR) +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = mingw32-gcc-ar$(MINGW_FLAVOUR) +endif + +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=gnu++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=gnu++20 -fexceptions -frtti +else +CXXFLAGS_STDCXX = -std=gnu++17 -fexceptions -frtti +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=gnu17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=gnu17 +else +CFLAGS_STDC = -std=gnu11 +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) + +CPPFLAGS += -DNOMINMAX +CPPFLAGS += -DMPT_BUILD_RETRO +CXXFLAGS += -mconsole -mthreads +CFLAGS += -mconsole -mthreads +LDFLAGS += +LDLIBS += -lm +ARFLAGS := rcs + +ifeq ($(WINDOWS_VERSION),) +# nothing +else ifeq ($(WINDOWS_VERSION),win95) +CPPFLAGS += -DWINVER=0x0400 -D_WIN32_WINDOWS=0x0400 +else ifeq ($(WINDOWS_VERSION),win98) +CPPFLAGS += -DWINVER=0x0410 -D_WIN32_WINDOWS=0x0410 +else ifeq ($(WINDOWS_VERSION),winme) +CPPFLAGS += -DWINVER=0x0490 -D_WIN32_WINDOWS=0x0490 +else ifeq ($(WINDOWS_VERSION),winnt4) +CPPFLAGS += -D_WIN32_WINNT=0x0400 +else ifeq ($(WINDOWS_VERSION),win2000) +CPPFLAGS += -D_WIN32_WINNT=0x0500 +else ifeq ($(WINDOWS_VERSION),winxp) +CPPFLAGS += -D_WIN32_WINNT=0x0501 +else +$(error unknown WINDOWS_VERSION) +endif + +LDLIBS_LIBOPENMPTTEST += -lole32 -lrpcrt4 +LDLIBS_OPENMPT123 += -lwinmm + +LDFLAGS += -static -static-libgcc -static-libstdc++ + +# enable gc-sections for all configurations in order to remove as much of the +# stdlib as possible +MPT_COMPILER_NOSECTIONS=1 +MPT_COMPILER_NOGCSECTIONS=1 +CXXFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS += -Wl,--gc-sections + +CXXFLAGS += -march=i586 -m80387 -mtune=pentium +CFLAGS += -march=i586 -m80387 -mtune=pentium + +PC_LIBS_PRIVATE += -lole32 -lrpcrt4 + +include build/make/warnings-gcc.mk + +EXESUFFIX=.exe +SOSUFFIX=.dll +SOSUFFIXWINDOWS=1 + +DYNLINK=0 +SHARED_LIB=1 +STATIC_LIB=0 +SHARED_SONAME=0 + +OPTIMIZE=size + +FORCE_UNIX_STYLE_COMMANDS=1 + +IN_OPENMPT=1 +XMP_OPENMPT=1 + +IS_CROSS=1 + +NO_ZLIB=1 +NO_MPG123=1 +NO_OGG=1 +NO_VORBIS=1 +NO_VORBISFILE=1 +NO_PORTAUDIO=1 +NO_PORTAUDIOCPP=1 +NO_PULSEAUDIO=1 +NO_SDL2=1 +NO_SNDFILE=1 +NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw32crt.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw32crt.mk new file mode 100644 index 000000000..284896f2b --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw32crt.mk @@ -0,0 +1,107 @@ + +ifeq ($(origin CC),default) +CC = i386-mingw32crt-gcc$(MINGW_FLAVOUR) +endif +ifeq ($(origin CXX),default) +CXX = i386-mingw32crt-g++$(MINGW_FLAVOUR) +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = i386-mingw32crt-gcc-ar$(MINGW_FLAVOUR) +endif + +ifneq ($(STDCXX),) +CXXFLAGS_STDCXX = -std=$(STDCXX) -fexceptions -frtti +else ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=gnu++20 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++20' ; fi ), c++20) +CXXFLAGS_STDCXX = -std=gnu++20 -fexceptions -frtti +else +CXXFLAGS_STDCXX = -std=gnu++17 -fexceptions -frtti +endif +ifneq ($(STDC),) +CFLAGS_STDC = -std=$(STDC) +else ifeq ($(shell printf '\n' > bin/empty.c ; if $(CC) -std=gnu17 -c bin/empty.c -o bin/empty.out > /dev/null 2>&1 ; then echo 'c17' ; fi ), c17) +CFLAGS_STDC = -std=gnu17 +else +CFLAGS_STDC = -std=gnu11 +endif +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) + +CPPFLAGS += -DNOMINMAX +CPPFLAGS += -DMPT_BUILD_RETRO +CXXFLAGS += -mconsole -mthreads +CFLAGS += -mconsole -mthreads +LDFLAGS += +LDLIBS += -lm +ARFLAGS := rcs + +ifeq ($(WINDOWS_VERSION),) +# nothing +else ifeq ($(WINDOWS_VERSION),win95) +CPPFLAGS += -DWINVER=0x0400 -D_WIN32_WINDOWS=0x0400 +else ifeq ($(WINDOWS_VERSION),win98) +CPPFLAGS += -DWINVER=0x0410 -D_WIN32_WINDOWS=0x0410 +else ifeq ($(WINDOWS_VERSION),winme) +CPPFLAGS += -DWINVER=0x0490 -D_WIN32_WINDOWS=0x0490 +else ifeq ($(WINDOWS_VERSION),winnt4) +CPPFLAGS += -D_WIN32_WINNT=0x0400 +else ifeq ($(WINDOWS_VERSION),win2000) +CPPFLAGS += -D_WIN32_WINNT=0x0500 +else ifeq ($(WINDOWS_VERSION),winxp) +CPPFLAGS += -D_WIN32_WINNT=0x0501 +else +$(error unknown WINDOWS_VERSION) +endif + +LDLIBS_LIBOPENMPTTEST += -lole32 -lrpcrt4 +LDLIBS_OPENMPT123 += -lwinmm + +LDFLAGS += -static -static-libgcc -static-libstdc++ + +# enable gc-sections for all configurations in order to remove as much of the +# stdlib as possible +MPT_COMPILER_NOSECTIONS=1 +MPT_COMPILER_NOGCSECTIONS=1 +CXXFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS += -Wl,--gc-sections + +CXXFLAGS += -march=i386 -m80387 -mtune=i486 +CFLAGS += -march=i386 -m80387 -mtune=i486 + +PC_LIBS_PRIVATE += -lole32 -lrpcrt4 + +include build/make/warnings-gcc.mk + +EXESUFFIX=.exe +SOSUFFIX=.dll +SOSUFFIXWINDOWS=1 + +DYNLINK=0 +SHARED_LIB=1 +STATIC_LIB=0 +SHARED_SONAME=0 + +OPTIMIZE=size + +FORCE_UNIX_STYLE_COMMANDS=1 + +EXAMPLES=0 +IN_OPENMPT=0 +XMP_OPENMPT=0 + +IS_CROSS=1 + +NO_ZLIB=1 +NO_MPG123=1 +NO_OGG=1 +NO_VORBIS=1 +NO_VORBISFILE=1 +NO_PORTAUDIO=1 +NO_PORTAUDIOCPP=1 +NO_PULSEAUDIO=1 +NO_SDL2=1 +NO_SNDFILE=1 +NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win32.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win32.mk index 007559c36..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win32.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win32.mk @@ -1,65 +0,0 @@ - -ifeq ($(origin CC),default) -CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR) -endif -ifeq ($(origin CXX),default) -CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR) -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR) -endif - -CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -DWIN32 -D_WIN32 -ifeq ($(MINGW_COMPILER),clang) -CXXFLAGS += -municode -CFLAGS += -municode -LDFLAGS += -mconsole -mthreads -else -CXXFLAGS += -municode -mthreads -CFLAGS += -municode -mthreads -LDFLAGS += -mconsole -endif -LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm -ARFLAGS := rcs - -PC_LIBS_PRIVATE += -lole32 -lrpcrt4 - -ifeq ($(MINGW_COMPILER),clang) -include build/make/warnings-clang.mk -else -include build/make/warnings-gcc.mk -endif - -EXESUFFIX=.exe -SOSUFFIX=.dll -SOSUFFIXWINDOWS=1 - -DYNLINK=0 -SHARED_LIB=1 -STATIC_LIB=0 -SHARED_SONAME=0 - -IS_CROSS=1 - -NO_ZLIB=1 -NO_LTDL=1 -NO_DL=1 -NO_MPG123=1 -NO_OGG=1 -NO_VORBIS=1 -NO_VORBISFILE=1 -NO_PORTAUDIO=1 -NO_PORTAUDIOCPP=1 -NO_PULSEAUDIO=1 -NO_SDL=1 -NO_SDL2=1 -NO_SNDFILE=1 -NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win64.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win64.mk index 44d31a143..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win64.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-win64.mk @@ -1,65 +0,0 @@ - -ifeq ($(origin CC),default) -CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR) -endif -ifeq ($(origin CXX),default) -CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR) -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR) -endif - -CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -DWIN32 -D_WIN32 -DWIN64 -D_WIN64 -ifeq ($(MINGW_COMPILER),clang) -CXXFLAGS += -municode -CFLAGS += -municode -LDFLAGS += -mconsole -mthreads -else -CXXFLAGS += -municode -mthreads -CFLAGS += -municode -mthreads -LDFLAGS += -mconsole -endif -LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm -ARFLAGS := rcs - -PC_LIBS_PRIVATE += -lole32 -lrpcrt4 - -ifeq ($(MINGW_COMPILER),clang) -include build/make/warnings-clang.mk -else -include build/make/warnings-gcc.mk -endif - -EXESUFFIX=.exe -SOSUFFIX=.dll -SOSUFFIXWINDOWS=1 - -DYNLINK=0 -SHARED_LIB=1 -STATIC_LIB=0 -SHARED_SONAME=0 - -IS_CROSS=1 - -NO_ZLIB=1 -NO_LTDL=1 -NO_DL=1 -NO_MPG123=1 -NO_OGG=1 -NO_VORBIS=1 -NO_VORBISFILE=1 -NO_PORTAUDIO=1 -NO_PORTAUDIOCPP=1 -NO_PULSEAUDIO=1 -NO_SDL=1 -NO_SDL2=1 -NO_SNDFILE=1 -NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-amd64.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-amd64.mk index a48472302..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-amd64.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-amd64.mk @@ -1,67 +0,0 @@ - -ifeq ($(origin CC),default) -CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR) -endif -ifeq ($(origin CXX),default) -CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR) -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR) -endif - -CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -DWIN32 -D_WIN32 -DWIN64 -D_WIN64 -DWINAPI_FAMILY=0x2 -D_WIN32_WINNT=0x0602 -ifeq ($(MINGW_COMPILER),clang) -CXXFLAGS += -municode -CFLAGS += -municode -LDFLAGS += -mconsole -mthreads -else -CXXFLAGS += -municode -mthreads -CFLAGS += -municode -mthreads -LDFLAGS += -mconsole -endif -LDLIBS += -lm -lole32 -lwinmm -ARFLAGS := rcs - -PC_LIBS_PRIVATE += -lole32 -lrpcrt4 - -ifeq ($(MINGW_COMPILER),clang) -include build/make/warnings-clang.mk -else -include build/make/warnings-gcc.mk -endif - -EXESUFFIX=.exe -SOSUFFIX=.dll -SOSUFFIXWINDOWS=1 - -DYNLINK=0 -SHARED_LIB=1 -STATIC_LIB=0 -SHARED_SONAME=0 - -IS_CROSS=1 - -OPENMPT123=0 - -NO_ZLIB=1 -NO_LTDL=1 -NO_DL=1 -NO_MPG123=1 -NO_OGG=1 -NO_VORBIS=1 -NO_VORBISFILE=1 -NO_PORTAUDIO=1 -NO_PORTAUDIOCPP=1 -NO_PULSEAUDIO=1 -NO_SDL=1 -NO_SDL2=1 -NO_SNDFILE=1 -NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-x86.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-x86.mk index 782d937e7..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-x86.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-mingw64-winrt-x86.mk @@ -1,67 +0,0 @@ - -ifeq ($(origin CC),default) -CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR) -endif -ifeq ($(origin CXX),default) -CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR) -endif -ifeq ($(origin LD),default) -LD = $(CXX) -endif -ifeq ($(origin AR),default) -AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR) -endif - -CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 -CXXFLAGS += $(CXXFLAGS_STDCXX) -CFLAGS += $(CFLAGS_STDC) - -CPPFLAGS += -DWIN32 -D_WIN32 -DWINAPI_FAMILY=0x2 -D_WIN32_WINNT=0x0602 -ifeq ($(MINGW_COMPILER),clang) -CXXFLAGS += -municode -CFLAGS += -municode -LDFLAGS += -mconsole -mthreads -else -CXXFLAGS += -municode -mthreads -CFLAGS += -municode -mthreads -LDFLAGS += -mconsole -endif -LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm -ARFLAGS := rcs - -PC_LIBS_PRIVATE += -lole32 -lrpcrt4 - -ifeq ($(MINGW_COMPILER),clang) -include build/make/warnings-clang.mk -else -include build/make/warnings-gcc.mk -endif - -EXESUFFIX=.exe -SOSUFFIX=.dll -SOSUFFIXWINDOWS=1 - -DYNLINK=0 -SHARED_LIB=1 -STATIC_LIB=0 -SHARED_SONAME=0 - -IS_CROSS=1 - -OPENMPT123=0 - -NO_ZLIB=1 -NO_LTDL=1 -NO_DL=1 -NO_MPG123=1 -NO_OGG=1 -NO_VORBIS=1 -NO_VORBISFILE=1 -NO_PORTAUDIO=1 -NO_PORTAUDIOCPP=1 -NO_PULSEAUDIO=1 -NO_SDL=1 -NO_SDL2=1 -NO_SNDFILE=1 -NO_FLAC=1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk index 0a4a04b38..05f4f2949 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk @@ -13,7 +13,7 @@ AR = ar endif CXXFLAGS_STDCXX = -std=c++17 -CFLAGS_STDC = -std=c99 +CFLAGS_STDC = -std=c17 CXXFLAGS += $(CXXFLAGS_STDCXX) CFLAGS += $(CFLAGS_STDC) diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/config-unknown.mk b/Frameworks/OpenMPT/OpenMPT/build/make/config-unknown.mk new file mode 100644 index 000000000..f8e61e149 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/make/config-unknown.mk @@ -0,0 +1,32 @@ + +ifeq ($(origin CC),default) +CC = cc +endif +ifeq ($(origin CXX),default) +CXX = c++ +endif +ifeq ($(origin LD),default) +LD = $(CXX) +endif +ifeq ($(origin AR),default) +AR = ar +endif + +CXXFLAGS_STDCXX = -std=c++17 +CFLAGS_STDC = -std=c11 +CXXFLAGS += $(CXXFLAGS_STDCXX) +CFLAGS += $(CFLAGS_STDC) + +CPPFLAGS += +CXXFLAGS += +CFLAGS += +LDFLAGS += +LDLIBS += +ARFLAGS := rcs + +MPT_COMPILER_GENERIC=1 +SHARED_LIB=0 +DYNLINK=0 + +EXESUFFIX= + diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk index 80cfbd080..a51c4a6fb 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk @@ -1,8 +1,9 @@ -CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef -CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef +CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef +CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wframe-larger-than=16000 -Wglobal-constructors -Wimplicit-fallthrough -Wmissing-declarations -Wnon-virtual-dtor -Wreserved-id-macro +CFLAGS_WARNINGS += -Wframe-larger-than=4000 #CXXFLAGS_WARNINGS += -Wfloat-equal #CXXFLAGS_WARNINGS += -Wdocumentation @@ -10,23 +11,21 @@ CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wframe-larger-than=16000 -Wgloba #CXXFLAGS_WARNINGS += -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++98-c++11-c++14-compat -Wno-padded -Wno-weak-vtables -Wno-sign-conversion -Wno-shadow-field-in-constructor -Wno-conversion -Wno-switch-enum -Wno-old-style-cast ifeq ($(MODERN),1) -LDFLAGS += -fuse-ld=lld -ifeq ($(OPTIMIZE_LTO),1) -LDFLAGS += -Wl,--thinlto-jobs=all -endif CXXFLAGS_WARNINGS += -CFLAGS_WARNINGS += -Wframe-larger-than=4000 +CFLAGS_WARNINGS += LDFLAGS_WARNINGS += -Wl,-no-undefined -Wl,--detect-odr-violations -# re-renable after 1.29 branch -#CXXFLAGS_WARNINGS += -Wdouble-promotion -#CFLAGS_WARNINGS += -Wdouble-promotion endif CFLAGS_SILENT += -Wno-\#warnings CFLAGS_SILENT += -Wno-cast-align CFLAGS_SILENT += -Wno-cast-qual +CFLAGS_SILENT += -Wno-double-promotion +CFLAGS_SILENT += -Wno-float-conversion +CFLAGS_SILENT += -Wno-frame-larger-than CFLAGS_SILENT += -Wno-missing-prototypes CFLAGS_SILENT += -Wno-sign-compare CFLAGS_SILENT += -Wno-unused-function CFLAGS_SILENT += -Wno-unused-parameter CFLAGS_SILENT += -Wno-unused-variable + +FASTMATH_STYLE=clang diff --git a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk index 99d755c25..d7470e6dd 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk +++ b/Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk @@ -1,21 +1,21 @@ -CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wfloat-conversion -Wframe-larger-than=16000 -Winit-self -Wlogical-op -Wmissing-declarations -Wpointer-arith -Wstrict-aliasing -Wsuggest-override -Wundef -CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wfloat-conversion -Wlogical-op -Wundef +CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wframe-larger-than=16000 -Winit-self -Wlogical-op -Wmissing-declarations -Wpointer-arith -Wstrict-aliasing -Wsuggest-override -Wundef +CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wdouble-promotion -Wfloat-conversion -Wlogical-op -Wstrict-prototypes -Wundef CXXFLAGS_WARNINGS += -Wno-psabi ifeq ($(MODERN),1) -LDFLAGS += -fuse-ld=gold -CXXFLAGS_WARNINGS += -CFLAGS_WARNINGS += -Wframe-larger-than=4000 -#CXXFLAGS_WARNINGS += -Wstrict-aliasing -Wpointer-arith -Winit-self -Wshadow -Wswitch-enum -Wstrict-prototypes +CFLAGS_WARNINGS += -Wframe-larger-than=4000 +#CXXFLAGS_WARNINGS += -Wshadow -Wswitch-enum +# gold LDFLAGS_WARNINGS += -Wl,-no-undefined -Wl,--detect-odr-violations -# re-renable after 1.29 branch -#CXXFLAGS_WARNINGS += -Wdouble-promotion -#CFLAGS_WARNINGS += -Wdouble-promotion +# GCC 8 +CXXFLAGS_WARNINGS += -Wcast-align=strict +CFLAGS_WARNINGS += -Wcast-align=strict endif CFLAGS_SILENT += -Wno-cast-qual +CFLAGS_SILENT += -Wno-double-promotion CFLAGS_SILENT += -Wno-empty-body CFLAGS_SILENT += -Wno-float-conversion CFLAGS_SILENT += -Wno-implicit-fallthrough @@ -26,3 +26,5 @@ CFLAGS_SILENT += -Wno-type-limits CFLAGS_SILENT += -Wno-unused-but-set-variable CFLAGS_SILENT += -Wno-unused-function CFLAGS_SILENT += -Wno-unused-parameter + +FASTMATH_STYLE=gcc diff --git a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h index 576a1950f..b11baa64b 100644 --- a/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h +++ b/Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h @@ -1,10 +1,10 @@ #pragma once -#define OPENMPT_VERSION_SVNVERSION "18680" -#define OPENMPT_VERSION_REVISION 18680 +#define OPENMPT_VERSION_SVNVERSION "19147" +#define OPENMPT_VERSION_REVISION 19147 #define OPENMPT_VERSION_DIRTY 0 #define OPENMPT_VERSION_MIXEDREVISIONS 0 -#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.6.8" -#define OPENMPT_VERSION_DATE "2023-01-29T12:13:49.877060Z" +#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.7.0" +#define OPENMPT_VERSION_DATE "2023-04-30T12:58:58.547157Z" #define OPENMPT_VERSION_IS_PACKAGE 1 diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj new file mode 100644 index 000000000..326bef0df --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/mpg123.xcodeproj/project.pbxproj @@ -0,0 +1,341 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 022CF042734F913429163E82 /* layer3.c in Sources */ = {isa = PBXBuildFile; fileRef = BAACDA4AE2E792FCCA83208A /* layer3.c */; }; + 022FC83459953B260BA35674 /* synth_real.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */; }; + 0DDEA7A4A06C7196094515E4 /* optimize.c in Sources */ = {isa = PBXBuildFile; fileRef = 1B61528CDECD143E1D70B8CC /* optimize.c */; }; + 142B46E0854DE7D23B149520 /* layer2.c in Sources */ = {isa = PBXBuildFile; fileRef = 9796B208BFD16ABAA76CF848 /* layer2.c */; }; + 21B328E68EDB3758906E2726 /* equalizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */; }; + 242DF798687C9D0AAAA3D5D8 /* tabinit.c in Sources */ = {isa = PBXBuildFile; fileRef = 6B2790408CF33D72C9A86680 /* tabinit.c */; }; + 26299D7E974C3E704D12EBBE /* layer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 748089C69CBB42788456D006 /* layer1.c */; }; + 2CE230149E04D10653CB7E54 /* format.c in Sources */ = {isa = PBXBuildFile; fileRef = AD3049FCD56B02AEBD06903C /* format.c */; }; + 2F06D05D7C69C68FF288C69D /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = A7ABBCE59297E2D7DA7DAB25 /* compat.c */; }; + 5BC0EB1CC8E8F98ECA7BE95C /* synth_s32.c in Sources */ = {isa = PBXBuildFile; fileRef = 739C6384C0FF59B6371E59C4 /* synth_s32.c */; }; + 64A7B16E5E696DE098686FAE /* synth.c in Sources */ = {isa = PBXBuildFile; fileRef = 907B4FB6D8EC33E81D8B05F6 /* synth.c */; }; + 6C03B21AB052578CF279905A /* feature.c in Sources */ = {isa = PBXBuildFile; fileRef = A60D55A2C7D902D4048E2BE2 /* feature.c */; }; + 82DB3C387C9CF8AAB69BFA78 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 440E80E08C7F6512D11E3720 /* parse.c */; }; + 8ADD039E1D6ACD90864371DE /* icy2utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = C3752BE686E0ED98C5849226 /* icy2utf8.c */; }; + 9CA288B296644524D06346F2 /* index.c in Sources */ = {isa = PBXBuildFile; fileRef = 754AC0BABDBBA4EC025A76FA /* index.c */; }; + BCB343AA29DB521C2B6E41EA /* stringbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 0BDCDC32593FD264CF5ED272 /* stringbuf.c */; }; + C2065F0E06550480487C3D4E /* readers.c in Sources */ = {isa = PBXBuildFile; fileRef = 489101566A5CAE88A711D796 /* readers.c */; }; + C39C716430C47FD632576FA4 /* libmpg123.c in Sources */ = {isa = PBXBuildFile; fileRef = 54E0A14CA243977E1862978C /* libmpg123.c */; }; + C3D66B021F17BE74F2720942 /* id3.c in Sources */ = {isa = PBXBuildFile; fileRef = F56A100A0C7CAB3CFC98A64A /* id3.c */; }; + D1E3070CCBA4C37E05A3C54C /* dct64.c in Sources */ = {isa = PBXBuildFile; fileRef = F4F6A4743D6788A682065AB4 /* dct64.c */; }; + D618207A2D7D936CDF8BAEBA /* synth_8bit.c in Sources */ = {isa = PBXBuildFile; fileRef = A1E03F02D3D989B44DB8C542 /* synth_8bit.c */; }; + E236244C3D7777BE10D1C28C /* icy.c in Sources */ = {isa = PBXBuildFile; fileRef = E598BBB4FCAB56E6ECC751F4 /* icy.c */; }; + EAB0691E1B9461102EAC975E /* ntom.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B10DD6681370D18E83E03A6 /* ntom.c */; }; + EE6448D8E826054A22250718 /* frame.c in Sources */ = {isa = PBXBuildFile; fileRef = 78DBF380C14CD7B205EBA9C0 /* frame.c */; }; + F155B58DD59CBDBF5989EBCD /* compat_str.c in Sources */ = {isa = PBXBuildFile; fileRef = CDD5DB15FEB9D30711D20955 /* compat_str.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0BDCDC32593FD264CF5ED272 /* stringbuf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = stringbuf.c; path = ../../../include/mpg123/src/libmpg123/stringbuf.c; sourceTree = ""; }; + 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = equalizer.c; path = ../../../include/mpg123/src/libmpg123/equalizer.c; sourceTree = ""; }; + 1B61528CDECD143E1D70B8CC /* optimize.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = optimize.c; path = ../../../include/mpg123/src/libmpg123/optimize.c; sourceTree = ""; }; + 440E80E08C7F6512D11E3720 /* parse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = parse.c; path = ../../../include/mpg123/src/libmpg123/parse.c; sourceTree = ""; }; + 489101566A5CAE88A711D796 /* readers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = readers.c; path = ../../../include/mpg123/src/libmpg123/readers.c; sourceTree = ""; }; + 54E0A14CA243977E1862978C /* libmpg123.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = libmpg123.c; path = ../../../include/mpg123/src/libmpg123/libmpg123.c; sourceTree = ""; }; + 5B10DD6681370D18E83E03A6 /* ntom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = ntom.c; path = ../../../include/mpg123/src/libmpg123/ntom.c; sourceTree = ""; }; + 6B2790408CF33D72C9A86680 /* tabinit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tabinit.c; path = ../../../include/mpg123/src/libmpg123/tabinit.c; sourceTree = ""; }; + 739C6384C0FF59B6371E59C4 /* synth_s32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_s32.c; path = ../../../include/mpg123/src/libmpg123/synth_s32.c; sourceTree = ""; }; + 748089C69CBB42788456D006 /* layer1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer1.c; path = ../../../include/mpg123/src/libmpg123/layer1.c; sourceTree = ""; }; + 754AC0BABDBBA4EC025A76FA /* index.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = index.c; path = ../../../include/mpg123/src/libmpg123/index.c; sourceTree = ""; }; + 78DBF380C14CD7B205EBA9C0 /* frame.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = frame.c; path = ../../../include/mpg123/src/libmpg123/frame.c; sourceTree = ""; }; + 907B4FB6D8EC33E81D8B05F6 /* synth.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth.c; path = ../../../include/mpg123/src/libmpg123/synth.c; sourceTree = ""; }; + 9796B208BFD16ABAA76CF848 /* layer2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer2.c; path = ../../../include/mpg123/src/libmpg123/layer2.c; sourceTree = ""; }; + A1E03F02D3D989B44DB8C542 /* synth_8bit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_8bit.c; path = ../../../include/mpg123/src/libmpg123/synth_8bit.c; sourceTree = ""; }; + A60D55A2C7D902D4048E2BE2 /* feature.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = feature.c; path = ../../../include/mpg123/src/libmpg123/feature.c; sourceTree = ""; }; + A7ABBCE59297E2D7DA7DAB25 /* compat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = compat.c; path = ../../../include/mpg123/src/compat/compat.c; sourceTree = ""; }; + AD3049FCD56B02AEBD06903C /* format.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = format.c; path = ../../../include/mpg123/src/libmpg123/format.c; sourceTree = ""; }; + BAACDA4AE2E792FCCA83208A /* layer3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer3.c; path = ../../../include/mpg123/src/libmpg123/layer3.c; sourceTree = ""; }; + C3752BE686E0ED98C5849226 /* icy2utf8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = icy2utf8.c; path = ../../../include/mpg123/src/libmpg123/icy2utf8.c; sourceTree = ""; }; + C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_real.c; path = ../../../include/mpg123/src/libmpg123/synth_real.c; sourceTree = ""; }; + C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-mpg123.dll"; path = "openmpt-mpg123.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + CDD5DB15FEB9D30711D20955 /* compat_str.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = compat_str.c; path = ../../../include/mpg123/src/compat/compat_str.c; sourceTree = ""; }; + E598BBB4FCAB56E6ECC751F4 /* icy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = icy.c; path = ../../../include/mpg123/src/libmpg123/icy.c; sourceTree = ""; }; + F4F6A4743D6788A682065AB4 /* dct64.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dct64.c; path = ../../../include/mpg123/src/libmpg123/dct64.c; sourceTree = ""; }; + F56A100A0C7CAB3CFC98A64A /* id3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = id3.c; path = ../../../include/mpg123/src/libmpg123/id3.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + A9087E6DA26E7FDF9609DCAD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E2ED1E19CDD9440B15BF0C59 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 0F03317AECAE342CC052B7BA /* mpg123 */ = { + isa = PBXGroup; + children = ( + 3E657050E1B0F982FC81C690 /* compat */, + 2C61E28ACF50093C5E75E8CA /* libmpg123 */, + A6C936B49B3FADE6EA134CF4 /* Products */, + ); + name = mpg123; + sourceTree = ""; + }; + 2C61E28ACF50093C5E75E8CA /* libmpg123 */ = { + isa = PBXGroup; + children = ( + F4F6A4743D6788A682065AB4 /* dct64.c */, + 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */, + A60D55A2C7D902D4048E2BE2 /* feature.c */, + AD3049FCD56B02AEBD06903C /* format.c */, + 78DBF380C14CD7B205EBA9C0 /* frame.c */, + E598BBB4FCAB56E6ECC751F4 /* icy.c */, + C3752BE686E0ED98C5849226 /* icy2utf8.c */, + F56A100A0C7CAB3CFC98A64A /* id3.c */, + 754AC0BABDBBA4EC025A76FA /* index.c */, + 748089C69CBB42788456D006 /* layer1.c */, + 9796B208BFD16ABAA76CF848 /* layer2.c */, + BAACDA4AE2E792FCCA83208A /* layer3.c */, + 54E0A14CA243977E1862978C /* libmpg123.c */, + 5B10DD6681370D18E83E03A6 /* ntom.c */, + 1B61528CDECD143E1D70B8CC /* optimize.c */, + 440E80E08C7F6512D11E3720 /* parse.c */, + 489101566A5CAE88A711D796 /* readers.c */, + 0BDCDC32593FD264CF5ED272 /* stringbuf.c */, + 907B4FB6D8EC33E81D8B05F6 /* synth.c */, + A1E03F02D3D989B44DB8C542 /* synth_8bit.c */, + C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */, + 739C6384C0FF59B6371E59C4 /* synth_s32.c */, + 6B2790408CF33D72C9A86680 /* tabinit.c */, + ); + name = libmpg123; + sourceTree = ""; + }; + 3E657050E1B0F982FC81C690 /* compat */ = { + isa = PBXGroup; + children = ( + A7ABBCE59297E2D7DA7DAB25 /* compat.c */, + CDD5DB15FEB9D30711D20955 /* compat_str.c */, + ); + name = compat; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6CFC1BC3B56CFFF5FA0BD203 /* mpg123 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9743C6CC90A9C83E8445250C /* Build configuration list for PBXNativeTarget "mpg123" */; + buildPhases = ( + 18EFFF0D1256007F05F15D4D /* Resources */, + 829D18647C0319D66F9E76A4 /* Sources */, + A9087E6DA26E7FDF9609DCAD /* Frameworks */, + E2ED1E19CDD9440B15BF0C59 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mpg123; + productName = mpg123; + productReference = C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "mpg123" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 0F03317AECAE342CC052B7BA /* mpg123 */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6CFC1BC3B56CFFF5FA0BD203 /* openmpt-mpg123.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 18EFFF0D1256007F05F15D4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 829D18647C0319D66F9E76A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F06D05D7C69C68FF288C69D /* compat.c in Sources */, + F155B58DD59CBDBF5989EBCD /* compat_str.c in Sources */, + D1E3070CCBA4C37E05A3C54C /* dct64.c in Sources */, + 21B328E68EDB3758906E2726 /* equalizer.c in Sources */, + 6C03B21AB052578CF279905A /* feature.c in Sources */, + 2CE230149E04D10653CB7E54 /* format.c in Sources */, + EE6448D8E826054A22250718 /* frame.c in Sources */, + E236244C3D7777BE10D1C28C /* icy.c in Sources */, + 8ADD039E1D6ACD90864371DE /* icy2utf8.c in Sources */, + C3D66B021F17BE74F2720942 /* id3.c in Sources */, + 9CA288B296644524D06346F2 /* index.c in Sources */, + 26299D7E974C3E704D12EBBE /* layer1.c in Sources */, + 142B46E0854DE7D23B149520 /* layer2.c in Sources */, + 022CF042734F913429163E82 /* layer3.c in Sources */, + C39C716430C47FD632576FA4 /* libmpg123.c in Sources */, + EAB0691E1B9461102EAC975E /* ntom.c in Sources */, + 0DDEA7A4A06C7196094515E4 /* optimize.c in Sources */, + 82DB3C387C9CF8AAB69BFA78 /* parse.c in Sources */, + C2065F0E06550480487C3D4E /* readers.c in Sources */, + BCB343AA29DB521C2B6E41EA /* stringbuf.c in Sources */, + 64A7B16E5E696DE098686FAE /* synth.c in Sources */, + D618207A2D7D936CDF8BAEBA /* synth_8bit.c in Sources */, + 022FC83459953B260BA35674 /* synth_real.c in Sources */, + 5BC0EB1CC8E8F98ECA7BE95C /* synth_s32.c in Sources */, + 242DF798687C9D0AAAA3D5D8 /* tabinit.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 4C50EB499ED7163B711B7989 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + OPT_GENERIC, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/mpg123; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-ios/all"; + USER_HEADER_SEARCH_PATHS = ( + ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/src/libmpg123, + ../../../include/mpg123/src/compat, + ../../../include/mpg123/src, + ); + }; + name = Debug; + }; + 7C31350CED53D5FEA31A834C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-mpg123"; + }; + name = Release; + }; + 98A0BBC3A55D6B351A47DA03 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + OPT_GENERIC, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/mpg123; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-ios/all"; + USER_HEADER_SEARCH_PATHS = ( + ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/src/libmpg123, + ../../../include/mpg123/src/compat, + ../../../include/mpg123/src, + ); + }; + name = Release; + }; + 9C9C6D92965E2A04D05D2BD2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-mpg123"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "mpg123" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C50EB499ED7163B711B7989 /* Debug */, + 98A0BBC3A55D6B351A47DA03 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 9743C6CC90A9C83E8445250C /* Build configuration list for PBXNativeTarget "openmpt-mpg123.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9C9C6D92965E2A04D05D2BD2 /* Debug */, + 7C31350CED53D5FEA31A834C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/ogg.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/ogg.xcodeproj/project.pbxproj new file mode 100644 index 000000000..ae4e12e53 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/ogg.xcodeproj/project.pbxproj @@ -0,0 +1,255 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 9C9F8407CD837BF9E09BB247 /* bitwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 1891292F3EB758E1A5BE4F6F /* bitwise.c */; }; + FF0BAB212FEFA3134307D961 /* framing.c in Sources */ = {isa = PBXBuildFile; fileRef = B766F1A9DD8D215B449417E9 /* framing.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1891292F3EB758E1A5BE4F6F /* bitwise.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bitwise.c; path = ../../../include/ogg/src/bitwise.c; sourceTree = ""; }; + 1E47F32D446E22DFAB75196D /* ogg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ogg.h; path = ../../../include/ogg/include/ogg/ogg.h; sourceTree = ""; }; + 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-ogg.dll"; path = "openmpt-ogg.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + 93F6FCDFE159F3115778F31F /* os_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = os_types.h; path = ../../../include/ogg/include/ogg/os_types.h; sourceTree = ""; }; + B766F1A9DD8D215B449417E9 /* framing.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = framing.c; path = ../../../include/ogg/src/framing.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 95F8A3D038E6CA82C80CAA10 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + CC7C283CE38EC36ED3AABE7C /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 5775D4184366DFCA959E7A58 /* src */ = { + isa = PBXGroup; + children = ( + 1891292F3EB758E1A5BE4F6F /* bitwise.c */, + B766F1A9DD8D215B449417E9 /* framing.c */, + ); + name = src; + sourceTree = ""; + }; + 5E8C725002DF100215175890 /* include */ = { + isa = PBXGroup; + children = ( + BE79831562CC20C775046955 /* ogg */, + ); + name = include; + sourceTree = ""; + }; + A078B4BDABA964AF054BE2FD /* ogg */ = { + isa = PBXGroup; + children = ( + 5E8C725002DF100215175890 /* include */, + 5775D4184366DFCA959E7A58 /* src */, + A6C936B49B3FADE6EA134CF4 /* Products */, + ); + name = ogg; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */, + ); + name = Products; + sourceTree = ""; + }; + BE79831562CC20C775046955 /* ogg */ = { + isa = PBXGroup; + children = ( + 1E47F32D446E22DFAB75196D /* ogg.h */, + 93F6FCDFE159F3115778F31F /* os_types.h */, + ); + name = ogg; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 886C6A4681D26BB8756DC886 /* ogg */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8433EC2F272212E1B647F26F /* Build configuration list for PBXNativeTarget "ogg" */; + buildPhases = ( + 05E02470A8CE4B2237F42AB0 /* Resources */, + 6F8D3DC7127B6479A1A14407 /* Sources */, + 95F8A3D038E6CA82C80CAA10 /* Frameworks */, + CC7C283CE38EC36ED3AABE7C /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ogg; + productName = ogg; + productReference = 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ogg" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = A078B4BDABA964AF054BE2FD /* ogg */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 886C6A4681D26BB8756DC886 /* openmpt-ogg.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 05E02470A8CE4B2237F42AB0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6F8D3DC7127B6479A1A14407 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C9F8407CD837BF9E09BB247 /* bitwise.c in Sources */, + FF0BAB212FEFA3134307D961 /* framing.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 8F6FCF26DF8363D862019566 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/ogg; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + }; + name = Release; + }; + C49D8BAF120081E1881F81EF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-ogg"; + }; + name = Release; + }; + C86DC9EC74D08A1E3359002C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/ogg; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + }; + name = Debug; + }; + DFACBF75A3188127E1BC25B5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-ogg"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ogg" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C86DC9EC74D08A1E3359002C /* Debug */, + 8F6FCF26DF8363D862019566 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 8433EC2F272212E1B647F26F /* Build configuration list for PBXNativeTarget "openmpt-ogg.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DFACBF75A3188127E1BC25B5 /* Debug */, + C49D8BAF120081E1881F81EF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/vorbis.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/vorbis.xcodeproj/project.pbxproj new file mode 100644 index 000000000..572583157 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/ext/vorbis.xcodeproj/project.pbxproj @@ -0,0 +1,531 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 16716A7E46033970211078BE /* block.c in Sources */ = {isa = PBXBuildFile; fileRef = 777077261A5E9DD8A9847D66 /* block.c */; }; + 16B25260019E7852498440A0 /* psy.c in Sources */ = {isa = PBXBuildFile; fileRef = EDFFC5E89252639AA48AAC28 /* psy.c */; }; + 3EA9B7E0953722526DB03620 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = E03CFA68E3ADCC9A651A70A8 /* info.c */; }; + 412482943AE63F0674E540D4 /* codebook.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A6247DC72D32C0EB771FE1C /* codebook.c */; }; + 42BABA9A3C7C770C767B78DA /* registry.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E246821A532AB45EF1FCC2 /* registry.c */; }; + 55E0C63CC703672E7CCA147C /* synthesis.c in Sources */ = {isa = PBXBuildFile; fileRef = 3A6CA00462A758B64A42E644 /* synthesis.c */; }; + 571301CEB254554085AEA00E /* floor1.c in Sources */ = {isa = PBXBuildFile; fileRef = 501CFA76672F95A8574B90B6 /* floor1.c */; }; + 63BC07FCBEFD5B6E9257A63C /* lookup.c in Sources */ = {isa = PBXBuildFile; fileRef = 35F064C44D02FFF63D1EFB04 /* lookup.c */; }; + 650BD9CE95EFD1C0A908080E /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = CEB55B76F4DB8B285BE281B6 /* smallft.c */; }; + 665EF2C06020AF329A1FB100 /* mapping0.c in Sources */ = {isa = PBXBuildFile; fileRef = 379713488007F77AC4A6C988 /* mapping0.c */; }; + 66F0DF98BD7E4A0A95F75DD8 /* mdct.c in Sources */ = {isa = PBXBuildFile; fileRef = C67232A0C9E304D24B4FA8E0 /* mdct.c */; }; + 7C34482667206E18AF063666 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 7091344E14E3D200271C1A8E /* lpc.c */; }; + A4B9FD2CFFFB509ED3559B6C /* floor0.c in Sources */ = {isa = PBXBuildFile; fileRef = 3AED1EF451FFBA26421BB534 /* floor0.c */; }; + A7912A52EBDFCFC42E070892 /* vorbisfile.c in Sources */ = {isa = PBXBuildFile; fileRef = C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */; }; + B1D3BC04AB957876E5947A44 /* envelope.c in Sources */ = {isa = PBXBuildFile; fileRef = 14D8424C5D49267EA1E7F88C /* envelope.c */; }; + BC748D10B6364982F0354B50 /* analysis.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */; }; + BDB5A0B818F6F42AEC513EF8 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 72232FC08935CAF27951C600 /* window.c */; }; + D5E5E506C0D20AF808B7D346 /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F30132E1382B0E025BAF96E /* lsp.c */; }; + D85CD4BE497F75B0FF4622FE /* vorbisenc.c in Sources */ = {isa = PBXBuildFile; fileRef = 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */; }; + E344DF0C2793847E69BABD4C /* sharedbook.c in Sources */ = {isa = PBXBuildFile; fileRef = 72897ED494552C06D10A5514 /* sharedbook.c */; }; + E77EFABE1862F2B02B7B28FE /* bitrate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0944F5662F6B251896721BA6 /* bitrate.c */; }; + FC4D923C52DAFCAE2B54107C /* res0.c in Sources */ = {isa = PBXBuildFile; fileRef = 16DFB5041A5087369BBD2B44 /* res0.c */; }; + FC66A059C11BF6CB758A9E99 /* openmpt-ogg.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = 322B76417ACAB4739DF66C81 /* openmpt-ogg.lib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 886C6A4681D26BB8756DC886; + remoteInfo = "openmpt-ogg.dll"; + }; + EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5036DE60765D0E12DD6404A0; + remoteInfo = "openmpt-ogg.dll"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-vorbis.dll"; path = "openmpt-vorbis.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + 07BE8ECA1ED129FC0EED250A /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = window.h; path = ../../../include/vorbis/lib/window.h; sourceTree = ""; }; + 0944F5662F6B251896721BA6 /* bitrate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bitrate.c; path = ../../../include/vorbis/lib/bitrate.c; sourceTree = ""; }; + 0C6D4B2032937AD2999A7160 /* smallft.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = smallft.h; path = ../../../include/vorbis/lib/smallft.h; sourceTree = ""; }; + 0D82D8FD2F4E862F6C03AF3D /* psych_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_8.h; path = ../../../include/vorbis/lib/modes/psych_8.h; sourceTree = ""; }; + 13C8DC265C39C058A0D89266 /* codebook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codebook.h; path = ../../../include/vorbis/lib/codebook.h; sourceTree = ""; }; + 14D8424C5D49267EA1E7F88C /* envelope.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = envelope.c; path = ../../../include/vorbis/lib/envelope.c; sourceTree = ""; }; + 15F93858BA4BD60ACC841E98 /* lsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lsp.h; path = ../../../include/vorbis/lib/lsp.h; sourceTree = ""; }; + 16DFB5041A5087369BBD2B44 /* res0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = res0.c; path = ../../../include/vorbis/lib/res0.c; sourceTree = ""; }; + 16F680C77237D43945921F07 /* codec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codec.h; path = ../../../include/vorbis/include/vorbis/codec.h; sourceTree = ""; }; + 175A5978BBACF72ACDE53FB8 /* lpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lpc.h; path = ../../../include/vorbis/lib/lpc.h; sourceTree = ""; }; + 1F836091517CAB43CB5BE6D1 /* residue_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44.h; path = ../../../include/vorbis/lib/modes/residue_44.h; sourceTree = ""; }; + 2740402E4D666FE0B46D666E /* masking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = masking.h; path = ../../../include/vorbis/lib/masking.h; sourceTree = ""; }; + 285CE11ECBA86A50E679375E /* os.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = os.h; path = ../../../include/vorbis/lib/os.h; sourceTree = ""; }; + 2A6247DC72D32C0EB771FE1C /* codebook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = codebook.c; path = ../../../include/vorbis/lib/codebook.c; sourceTree = ""; }; + 2AAE7645EE1A37F72CBDDC85 /* setup_11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_11.h; path = ../../../include/vorbis/lib/modes/setup_11.h; sourceTree = ""; }; + 35CF7AFDF93B3CAF37DEE13D /* psych_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_44.h; path = ../../../include/vorbis/lib/modes/psych_44.h; sourceTree = ""; }; + 35F064C44D02FFF63D1EFB04 /* lookup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lookup.c; path = ../../../include/vorbis/lib/lookup.c; sourceTree = ""; }; + 374A6BCA5F85247C4720B20A /* highlevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = highlevel.h; path = ../../../include/vorbis/lib/highlevel.h; sourceTree = ""; }; + 379713488007F77AC4A6C988 /* mapping0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mapping0.c; path = ../../../include/vorbis/lib/mapping0.c; sourceTree = ""; }; + 386FE2DA60AA9B8C4846291A /* openmpt-ogg.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "ogg.xcodeproj"; path = ogg.xcodeproj; sourceTree = SOURCE_ROOT; }; + 3A6CA00462A758B64A42E644 /* synthesis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synthesis.c; path = ../../../include/vorbis/lib/synthesis.c; sourceTree = ""; }; + 3AED1EF451FFBA26421BB534 /* floor0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = floor0.c; path = ../../../include/vorbis/lib/floor0.c; sourceTree = ""; }; + 3B10AC6A3E817E9CBFEE22AA /* mdct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mdct.h; path = ../../../include/vorbis/lib/mdct.h; sourceTree = ""; }; + 3BA7A5A17FF64B13C21D83E1 /* vorbisenc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisenc.h; path = ../../../include/vorbis/include/vorbis/vorbisenc.h; sourceTree = ""; }; + 450CC03BDA837F6D491FD67B /* residue_44u.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44u.h; path = ../../../include/vorbis/lib/modes/residue_44u.h; sourceTree = ""; }; + 46FCE5106D2314C2D42A0B50 /* bitrate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bitrate.h; path = ../../../include/vorbis/lib/bitrate.h; sourceTree = ""; }; + 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = analysis.c; path = ../../../include/vorbis/lib/analysis.c; sourceTree = ""; }; + 501CFA76672F95A8574B90B6 /* floor1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = floor1.c; path = ../../../include/vorbis/lib/floor1.c; sourceTree = ""; }; + 5BED095DF163C88F60001F9D /* setup_44p51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44p51.h; path = ../../../include/vorbis/lib/modes/setup_44p51.h; sourceTree = ""; }; + 63614891852CF5C3C1E21ED1 /* setup_X.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_X.h; path = ../../../include/vorbis/lib/modes/setup_X.h; sourceTree = ""; }; + 6B3067A02E9C29526D3FCDE0 /* lookup_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lookup_data.h; path = ../../../include/vorbis/lib/lookup_data.h; sourceTree = ""; }; + 6B6795D0827A310272962C10 /* scales.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scales.h; path = ../../../include/vorbis/lib/scales.h; sourceTree = ""; }; + 6CCD7211303933C36EDCD851 /* setup_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44.h; path = ../../../include/vorbis/lib/modes/setup_44.h; sourceTree = ""; }; + 6E91170FA08A61C11A699D4F /* residue_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_16.h; path = ../../../include/vorbis/lib/modes/residue_16.h; sourceTree = ""; }; + 6F30132E1382B0E025BAF96E /* lsp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lsp.c; path = ../../../include/vorbis/lib/lsp.c; sourceTree = ""; }; + 7091344E14E3D200271C1A8E /* lpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpc.c; path = ../../../include/vorbis/lib/lpc.c; sourceTree = ""; }; + 72232FC08935CAF27951C600 /* window.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../../../include/vorbis/lib/window.c; sourceTree = ""; }; + 72897ED494552C06D10A5514 /* sharedbook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sharedbook.c; path = ../../../include/vorbis/lib/sharedbook.c; sourceTree = ""; }; + 746BBDBB37D77F6D767B23FB /* psych_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_16.h; path = ../../../include/vorbis/lib/modes/psych_16.h; sourceTree = ""; }; + 777077261A5E9DD8A9847D66 /* block.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = block.c; path = ../../../include/vorbis/lib/block.c; sourceTree = ""; }; + 7EC1E432F2AA5BE414F80A72 /* res_books_stereo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_stereo.h; path = ../../../include/vorbis/lib/books/coupled/res_books_stereo.h; sourceTree = ""; }; + 90EE3C51B2B9E983EF6F1291 /* setup_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_8.h; path = ../../../include/vorbis/lib/modes/setup_8.h; sourceTree = ""; }; + 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = vorbisenc.c; path = ../../../include/vorbis/lib/vorbisenc.c; sourceTree = ""; }; + 94C8EB12391B88C44B53D152 /* psy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psy.h; path = ../../../include/vorbis/lib/psy.h; sourceTree = ""; }; + 960E1F895979E13B981D85C9 /* setup_22.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_22.h; path = ../../../include/vorbis/lib/modes/setup_22.h; sourceTree = ""; }; + AB69B4CF6ED57681AD791B0F /* setup_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_16.h; path = ../../../include/vorbis/lib/modes/setup_16.h; sourceTree = ""; }; + B9289C7B068B92AD7CAA92BB /* setup_44u.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44u.h; path = ../../../include/vorbis/lib/modes/setup_44u.h; sourceTree = ""; }; + B980BE8E4EF77DC0BD93D4CE /* codec_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codec_internal.h; path = ../../../include/vorbis/lib/codec_internal.h; sourceTree = ""; }; + BB48DACC03B9BEFE4858910C /* registry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = registry.h; path = ../../../include/vorbis/lib/registry.h; sourceTree = ""; }; + C38A75AF76807F61C7A2DBEF /* res_books_uncoupled.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_uncoupled.h; path = ../../../include/vorbis/lib/books/uncoupled/res_books_uncoupled.h; sourceTree = ""; }; + C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = vorbisfile.c; path = ../../../include/vorbis/lib/vorbisfile.c; sourceTree = ""; }; + C67232A0C9E304D24B4FA8E0 /* mdct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdct.c; path = ../../../include/vorbis/lib/mdct.c; sourceTree = ""; }; + C97DEB5A61CAD10C9011D19A /* res_books_51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_51.h; path = ../../../include/vorbis/lib/books/coupled/res_books_51.h; sourceTree = ""; }; + CB8BC3CEE29E5F00D2BA5A0E /* lookup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lookup.h; path = ../../../include/vorbis/lib/lookup.h; sourceTree = ""; }; + CEB55B76F4DB8B285BE281B6 /* smallft.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = smallft.c; path = ../../../include/vorbis/lib/smallft.c; sourceTree = ""; }; + D1E246821A532AB45EF1FCC2 /* registry.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = registry.c; path = ../../../include/vorbis/lib/registry.c; sourceTree = ""; }; + D90D21756B9AEB67D4738FB5 /* vorbisfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisfile.h; path = ../../../include/vorbis/include/vorbis/vorbisfile.h; sourceTree = ""; }; + DAF247F2DE631A245FCFBE32 /* misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = misc.h; path = ../../../include/vorbis/lib/misc.h; sourceTree = ""; }; + DBC5215DC00C298F43F9579D /* residue_44p51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44p51.h; path = ../../../include/vorbis/lib/modes/residue_44p51.h; sourceTree = ""; }; + E03CFA68E3ADCC9A651A70A8 /* info.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = info.c; path = ../../../include/vorbis/lib/info.c; sourceTree = ""; }; + E7AEBC4BAB1A7DFDE9BE228B /* setup_32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_32.h; path = ../../../include/vorbis/lib/modes/setup_32.h; sourceTree = ""; }; + EABBD3D0332CB80277CB8A10 /* backends.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = backends.h; path = ../../../include/vorbis/lib/backends.h; sourceTree = ""; }; + EDFFC5E89252639AA48AAC28 /* psy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = psy.c; path = ../../../include/vorbis/lib/psy.c; sourceTree = ""; }; + EE56303600800CE83470F676 /* floor_books.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = floor_books.h; path = ../../../include/vorbis/lib/books/floor/floor_books.h; sourceTree = ""; }; + F1CF92D13F328903B5518911 /* residue_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_8.h; path = ../../../include/vorbis/lib/modes/residue_8.h; sourceTree = ""; }; + F3B07F31B71C40E3F5BFE571 /* psych_11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_11.h; path = ../../../include/vorbis/lib/modes/psych_11.h; sourceTree = ""; }; + FB9FDEF54902D527BF21D535 /* floor_all.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = floor_all.h; path = ../../../include/vorbis/lib/modes/floor_all.h; sourceTree = ""; }; + FE3ED69646AFBAC88B4E8CD6 /* envelope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = envelope.h; path = ../../../include/vorbis/lib/envelope.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7C0E12287574139A690F7068 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FC66A059C11BF6CB758A9E99 /* openmpt-ogg.lib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DA68C947892B286C0787AD4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 26717C15041C7EC7D7C10255 /* vorbis */ = { + isa = PBXGroup; + children = ( + 5E8C725002DF100215175890 /* include */, + 8D815E5679726A08CBAA0496 /* lib */, + A6C936B49B3FADE6EA134CF4 /* Products */, + 9D968EAA920D05DCE0E0A4EA /* Projects */, + ); + name = vorbis; + sourceTree = ""; + }; + 5A1F78C5713213F7614E0F05 /* vorbis */ = { + isa = PBXGroup; + children = ( + 16F680C77237D43945921F07 /* codec.h */, + 3BA7A5A17FF64B13C21D83E1 /* vorbisenc.h */, + D90D21756B9AEB67D4738FB5 /* vorbisfile.h */, + ); + name = vorbis; + sourceTree = ""; + }; + 5E8C725002DF100215175890 /* include */ = { + isa = PBXGroup; + children = ( + 5A1F78C5713213F7614E0F05 /* vorbis */, + ); + name = include; + sourceTree = ""; + }; + 77671A33BFD7FE650476D073 /* coupled */ = { + isa = PBXGroup; + children = ( + C97DEB5A61CAD10C9011D19A /* res_books_51.h */, + 7EC1E432F2AA5BE414F80A72 /* res_books_stereo.h */, + ); + name = coupled; + sourceTree = ""; + }; + 80C578BF97D813F187F40EFF /* Products */ = { + isa = PBXGroup; + children = ( + 322B76417ACAB4739DF66C81 /* openmpt-ogg.lib */, + ); + name = Products; + sourceTree = ""; + }; + 8D815E5679726A08CBAA0496 /* lib */ = { + isa = PBXGroup; + children = ( + 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */, + EABBD3D0332CB80277CB8A10 /* backends.h */, + 0944F5662F6B251896721BA6 /* bitrate.c */, + 46FCE5106D2314C2D42A0B50 /* bitrate.h */, + 777077261A5E9DD8A9847D66 /* block.c */, + EE14CC2A926769DCA49FB26A /* books */, + 2A6247DC72D32C0EB771FE1C /* codebook.c */, + 13C8DC265C39C058A0D89266 /* codebook.h */, + B980BE8E4EF77DC0BD93D4CE /* codec_internal.h */, + 14D8424C5D49267EA1E7F88C /* envelope.c */, + FE3ED69646AFBAC88B4E8CD6 /* envelope.h */, + 3AED1EF451FFBA26421BB534 /* floor0.c */, + 501CFA76672F95A8574B90B6 /* floor1.c */, + 374A6BCA5F85247C4720B20A /* highlevel.h */, + E03CFA68E3ADCC9A651A70A8 /* info.c */, + 35F064C44D02FFF63D1EFB04 /* lookup.c */, + CB8BC3CEE29E5F00D2BA5A0E /* lookup.h */, + 6B3067A02E9C29526D3FCDE0 /* lookup_data.h */, + 7091344E14E3D200271C1A8E /* lpc.c */, + 175A5978BBACF72ACDE53FB8 /* lpc.h */, + 6F30132E1382B0E025BAF96E /* lsp.c */, + 15F93858BA4BD60ACC841E98 /* lsp.h */, + 379713488007F77AC4A6C988 /* mapping0.c */, + 2740402E4D666FE0B46D666E /* masking.h */, + C67232A0C9E304D24B4FA8E0 /* mdct.c */, + 3B10AC6A3E817E9CBFEE22AA /* mdct.h */, + DAF247F2DE631A245FCFBE32 /* misc.h */, + 9547E85E399A86104BD2CE9E /* modes */, + 285CE11ECBA86A50E679375E /* os.h */, + EDFFC5E89252639AA48AAC28 /* psy.c */, + 94C8EB12391B88C44B53D152 /* psy.h */, + D1E246821A532AB45EF1FCC2 /* registry.c */, + BB48DACC03B9BEFE4858910C /* registry.h */, + 16DFB5041A5087369BBD2B44 /* res0.c */, + 6B6795D0827A310272962C10 /* scales.h */, + 72897ED494552C06D10A5514 /* sharedbook.c */, + CEB55B76F4DB8B285BE281B6 /* smallft.c */, + 0C6D4B2032937AD2999A7160 /* smallft.h */, + 3A6CA00462A758B64A42E644 /* synthesis.c */, + 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */, + C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */, + 72232FC08935CAF27951C600 /* window.c */, + 07BE8ECA1ED129FC0EED250A /* window.h */, + ); + name = lib; + sourceTree = ""; + }; + 9547E85E399A86104BD2CE9E /* modes */ = { + isa = PBXGroup; + children = ( + FB9FDEF54902D527BF21D535 /* floor_all.h */, + F3B07F31B71C40E3F5BFE571 /* psych_11.h */, + 746BBDBB37D77F6D767B23FB /* psych_16.h */, + 35CF7AFDF93B3CAF37DEE13D /* psych_44.h */, + 0D82D8FD2F4E862F6C03AF3D /* psych_8.h */, + 6E91170FA08A61C11A699D4F /* residue_16.h */, + 1F836091517CAB43CB5BE6D1 /* residue_44.h */, + DBC5215DC00C298F43F9579D /* residue_44p51.h */, + 450CC03BDA837F6D491FD67B /* residue_44u.h */, + F1CF92D13F328903B5518911 /* residue_8.h */, + 2AAE7645EE1A37F72CBDDC85 /* setup_11.h */, + AB69B4CF6ED57681AD791B0F /* setup_16.h */, + 960E1F895979E13B981D85C9 /* setup_22.h */, + E7AEBC4BAB1A7DFDE9BE228B /* setup_32.h */, + 6CCD7211303933C36EDCD851 /* setup_44.h */, + 5BED095DF163C88F60001F9D /* setup_44p51.h */, + B9289C7B068B92AD7CAA92BB /* setup_44u.h */, + 90EE3C51B2B9E983EF6F1291 /* setup_8.h */, + 63614891852CF5C3C1E21ED1 /* setup_X.h */, + ); + name = modes; + sourceTree = ""; + }; + 9D968EAA920D05DCE0E0A4EA /* Projects */ = { + isa = PBXGroup; + children = ( + 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */, + ); + name = Projects; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */, + ); + name = Products; + sourceTree = ""; + }; + E272DBD9043E890B40F3B219 /* uncoupled */ = { + isa = PBXGroup; + children = ( + C38A75AF76807F61C7A2DBEF /* res_books_uncoupled.h */, + ); + name = uncoupled; + sourceTree = ""; + }; + EE14CC2A926769DCA49FB26A /* books */ = { + isa = PBXGroup; + children = ( + 77671A33BFD7FE650476D073 /* coupled */, + FCE62BDF13F8C7110414C21F /* floor */, + E272DBD9043E890B40F3B219 /* uncoupled */, + ); + name = books; + sourceTree = ""; + }; + FCE62BDF13F8C7110414C21F /* floor */ = { + isa = PBXGroup; + children = ( + EE56303600800CE83470F676 /* floor_books.h */, + ); + name = floor; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6EE3599EB7543DD0FBF30FDE /* vorbis */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6A495A8763AF5BF9574AB8C7 /* Build configuration list for PBXNativeTarget "vorbis" */; + buildPhases = ( + EBF592C8E55B943AD8F6F108 /* Resources */, + 55A2AC1F4F08AD9142A40A5F /* Sources */, + 7C0E12287574139A690F7068 /* Frameworks */, + 8DA68C947892B286C0787AD4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */, + ); + name = vorbis; + productName = vorbis; + productReference = 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "vorbis" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 26717C15041C7EC7D7C10255 /* vorbis */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 80C578BF97D813F187F40EFF /* Products */; + ProjectRef = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 6EE3599EB7543DD0FBF30FDE /* openmpt-vorbis.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 322B76417ACAB4739DF66C81 /* openmpt-ogg.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-ogg.lib"; + remoteRef = EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + EBF592C8E55B943AD8F6F108 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 55A2AC1F4F08AD9142A40A5F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BC748D10B6364982F0354B50 /* analysis.c in Sources */, + E77EFABE1862F2B02B7B28FE /* bitrate.c in Sources */, + 16716A7E46033970211078BE /* block.c in Sources */, + 412482943AE63F0674E540D4 /* codebook.c in Sources */, + B1D3BC04AB957876E5947A44 /* envelope.c in Sources */, + A4B9FD2CFFFB509ED3559B6C /* floor0.c in Sources */, + 571301CEB254554085AEA00E /* floor1.c in Sources */, + 3EA9B7E0953722526DB03620 /* info.c in Sources */, + 63BC07FCBEFD5B6E9257A63C /* lookup.c in Sources */, + 7C34482667206E18AF063666 /* lpc.c in Sources */, + D5E5E506C0D20AF808B7D346 /* lsp.c in Sources */, + 665EF2C06020AF329A1FB100 /* mapping0.c in Sources */, + 66F0DF98BD7E4A0A95F75DD8 /* mdct.c in Sources */, + 16B25260019E7852498440A0 /* psy.c in Sources */, + 42BABA9A3C7C770C767B78DA /* registry.c in Sources */, + FC4D923C52DAFCAE2B54107C /* res0.c in Sources */, + E344DF0C2793847E69BABD4C /* sharedbook.c in Sources */, + 650BD9CE95EFD1C0A908080E /* smallft.c in Sources */, + 55E0C63CC703672E7CCA147C /* synthesis.c in Sources */, + D85CD4BE497F75B0FF4622FE /* vorbisenc.c in Sources */, + A7912A52EBDFCFC42E070892 /* vorbisfile.c in Sources */, + BDB5A0B818F6F42AEC513EF8 /* window.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-ogg.lib"; + targetProxy = 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1FD85444725E7F3644A2E284 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/vorbis; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../../../include/vorbis/include, + ../../../include/vorbis/lib, + ); + }; + name = Debug; + }; + 6BA64F7E7862FEF0ED4D6DBE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/vorbis; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../../../include/vorbis/include, + ../../../include/vorbis/lib, + ); + }; + name = Release; + }; + AC0271CDA5C42E3FDFC3300D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-vorbis"; + }; + name = Debug; + }; + FD2934076E4BD4F924128247 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-vorbis"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "vorbis" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1FD85444725E7F3644A2E284 /* Debug */, + 6BA64F7E7862FEF0ED4D6DBE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 6A495A8763AF5BF9574AB8C7 /* Build configuration list for PBXNativeTarget "openmpt-vorbis.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AC0271CDA5C42E3FDFC3300D /* Debug */, + FD2934076E4BD4F924128247 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcodeproj/project.pbxproj new file mode 100644 index 000000000..04883a2ef --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcodeproj/project.pbxproj @@ -0,0 +1,1851 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00BB926F99087821C74F78AF /* Load_xm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */; }; + 00CD0D05B3C316B704E57345 /* DMOPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E0923A2DD491839F597C986D /* DMOPlugin.cpp */; }; + 03096A39B5FF73EB0721D079 /* libopenmpt_cxx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */; }; + 0BABF0E5544B2F177776E725 /* Distortion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */; }; + 0CEBFC05EC091637C8127245 /* Load_psm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */; }; + 0D8FA4E7F326AC19B66BBB27 /* SampleFormatVorbis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */; }; + 0ED9B165EDF6CB97CA0027A5 /* Load_mod.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */; }; + 119C6E37113F51694B940477 /* RowVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */; }; + 14522B09AC9F10BBDAE61149 /* Tagging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */; }; + 1452C745AC9FACF7DAE6AD85 /* Dlsbank.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */; }; + 1553F71F02BB89D19FB57D5F /* WavesReverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */; }; + 168C3C51AED92203DD202291 /* Message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */; }; + 18C62C9BF7E346CDD3ECA2DB /* SampleIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78CAB4630B587E55743122A3 /* SampleIO.cpp */; }; + 1CD4D902FBF1F334D7FB4F42 /* mptFileIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */; }; + 1CE1B0B6B52E9668E37596F6 /* Profiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F52A05ED3A145D015C87E9E /* Profiler.cpp */; }; + 1E48E6EB2E2E131D1AA19D2B /* Gargle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */; }; + 1F7082161F13654859681856 /* mptFileType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */; }; + 247D3937039A5369DFA3AF77 /* Load_plm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */; }; + 281FA911C06C8EC3EEB38F51 /* Sndfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */; }; + 2B1F4A030A3C6435E645C043 /* Load_mo3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */; }; + 30BE965074D2678268A3EC90 /* mptTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B176D8582299794AD8602698 /* mptTime.cpp */; }; + 30C4FED93067E20B6ABC9519 /* ModChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */; }; + 31268193410BADC52D7F37D3 /* ContainerXPK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */; }; + 31B9FE03CF9AFEB5A7194443 /* UpgradeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */; }; + 32925EA3CADF4455F92644E3 /* pattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB4660EB0F95065D51BC3F2B /* pattern.cpp */; }; + 32D83065D0B93117A83776A5 /* ITCompression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */; }; + 33DB2DAD46050A5F79F5F3ED /* Paula.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A09A55A16256C7DB615895 /* Paula.cpp */; }; + 370352EC246AE59EC164D92C /* PluginManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE32D5B4DABD882655A253F4 /* PluginManager.cpp */; }; + 393D72CF5409E18157DA790F /* MPEGFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */; }; + 39B7C99F18D4E3D1F4DE3FDF /* Load_mdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2052C727B2E091191BB93567 /* Load_mdl.cpp */; }; + 3C92F25FD4DFD8110326D89F /* Fastmix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1054EEE754A3945996CACD27 /* Fastmix.cpp */; }; + 3EF604A50D1958579427AAE5 /* DSP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E2066CCD3D47C03F10A20B0D /* DSP.cpp */; }; + 3F8606FDF27C10AF439E6D3D /* SampleFormatMP3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */; }; + 40F236CF2E59C981CB53BD0F /* I3DL2Reverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */; }; + 4174F40120920E33FC9B6A41 /* Load_uax.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */; }; + 44F9DD452416F77700205385 /* Load_c67.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B99E396D4C2C035FB504A7AD /* Load_c67.cpp */; }; + 46A543E1568A701342FDFA21 /* ContainerUMX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */; }; + 49C7038128E41DB304ED79C1 /* Load_okt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AE995E9FD775FDB66500429 /* Load_okt.cpp */; }; + 49F242A9929180DBB5BD38E9 /* SampleFormatFLAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */; }; + 4E13C16F2D30DBA1093A37AF /* Load_669.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B569F9F747F7C3E9B0D06837 /* Load_669.cpp */; }; + 4FD75379AB22A3AB995489B9 /* InstrumentExtensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */; }; + 50BD34A3E633F3D554D04AE3 /* EQ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */; }; + 527E833E969254708A63D97E /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 830F3566F431D658A9F883A6 /* Logging.cpp */; }; + 537472DD32918D0F0E9AE91D /* Load_imf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34D45985C7622377303AC7C5 /* Load_imf.cpp */; }; + 56DD54C135FA6EF31203CB01 /* Load_mtm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */; }; + 574F1261366C2C93127588A1 /* load_j2b.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A33106C935BED0BB9E977509 /* load_j2b.cpp */; }; + 5EE7936B3E04AD9D1A0E09AB /* Load_667.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB46E6335DD4B025C6AD5473 /* Load_667.cpp */; }; + 63B0011DD79878CFF9E6275D /* Load_mus_km.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */; }; + 6600F8E10024EE13B04ACF21 /* ContainerMMCMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */; }; + 689E270C1013C2BEB8D8CD4C /* DigiBoosterEcho.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */; }; + 69AC6475078D6527DF0BAAB5 /* ParamEq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */; }; + 6A44FDD1AE58CF03A22A5411 /* tuning.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 48199D39B93C3E2B6F02EB79 /* tuning.cpp */; }; + 707EA3954F9BBDC72BA519D5 /* Load_gdm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */; }; + 7744F34756620D79326B6987 /* Load_ptm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */; }; + 77A73F692A9D491B7BBFA5A9 /* SampleFormatBRR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */; }; + 7A5E5DAB8A4389DD76B713EB /* MixFuncTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */; }; + 7B65168B5A8230BD368B8CCB /* Load_dbm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */; }; + 7DDE7A6B76A93A1D011DA0AB /* SampleFormatMediaFoundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */; }; + 7F5CA93E3358C270150AFF7E /* openmpt-vorbis.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = AB169C264570851881A8EA66 /* openmpt-vorbis.lib */; }; + 7FDA539F18273951466E39DF /* Load_it.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62235C27A6720199E8993A67 /* Load_it.cpp */; }; + 80EEA677809189A9BAE63CB7 /* MIDIMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */; }; + 8479AC1F9F461AD1A316B25F /* Load_digi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D14936A73E714519400434E7 /* Load_digi.cpp */; }; + 84A9E60B844CC93DBEA17C4B /* MixerLoops.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */; }; + 8676CA3F6593E471419D407F /* Load_gt2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */; }; + 8751165421750B86D19AEC94 /* mptStringBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C510221C396A670EB74DF05C /* mptStringBuffer.cpp */; }; + 8B4D81ED6A6A9C1F4673F82D /* Load_dsm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */; }; + 8D04F5E56C221017482B6C25 /* WAVTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */; }; + 8F84E60E36FA81C0DFBF8C4E /* openmpt-ogg.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7F44F63A21E068EF03E336 /* openmpt-ogg.lib */; }; + 90C3E5D96FE1000B4BEA5C19 /* Load_mid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC1456C17EA220B3E77AC501 /* Load_mid.cpp */; }; + 926864F471857F264D8EDB34 /* mptRandom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */; }; + 9715CA0B7632E43D523C404B /* Load_s3m.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */; }; + 976568F7F2B0B929E0E29F37 /* libopenmpt_ext_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */; }; + 97AC91CD76C9ABFF52D3080D /* Load_stm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */; }; + 97B1A0C5975483F7D1A93705 /* Echo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C9696EDF3FC09DFA60A252D /* Echo.cpp */; }; + 9F1029ABB9DC985DBDAD2FEB /* ModSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A32EC1731056CFE511E9BFB3 /* ModSample.cpp */; }; + 9F2D020A8C9494BC298E884A /* PlugInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D89E49F2E528FC64600DC832 /* PlugInterface.cpp */; }; + 9FC1BA253DA2BAD715210065 /* Flanger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3286C74DF54727BF527C058D /* Flanger.cpp */; }; + A0E13DD3392E238567752413 /* XMTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */; }; + A5DAFA6B19C3721D3C1120AB /* WindowedFIR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14715833DAFF4FA549017673 /* WindowedFIR.cpp */; }; + A7B576CD86D290FF62DBED0D /* Load_amf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37F80675CA85D067335E74B5 /* Load_amf.cpp */; }; + A896F1F84677F2AA1DF63838 /* LFOPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */; }; + A9C7C28B051312BDF344F8CB /* AudioCriticalSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */; }; + A9D47C71514A1823FA0F22B1 /* SoundFilePlayConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */; }; + AB7FFC4D9117037F545C128D /* mod_specifications.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */; }; + ABC5779D79E8CB4F00F71DDD /* OPL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3A14F450EE2A2B7E23CED85 /* OPL.cpp */; }; + B17E84D14F5F858326DDCB11 /* ContainerPP20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */; }; + B5220D6D8345611F0A53B3AD /* AGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFC43D151B059087EE5FDB55 /* AGC.cpp */; }; + B591ED4C6887F6FEB9AA538C /* ComponentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */; }; + B5D9190DF9ECEA3FEDBE6F4D /* Sndmix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */; }; + BA54A1E79971BC19757B1827 /* Load_ams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29DC06EFBC69D0E12542752F /* Load_ams.cpp */; }; + BB65D2D86E5BDC8ABF7E3918 /* mptFileTemporary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */; }; + BBC2281DFFD5F94FF3A77E5D /* Tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */; }; + BC15882904B4C65B27E07E69 /* patternContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */; }; + BCC110A956E505DB070AE6E9 /* DMOUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */; }; + BD3885019C559F33785EFB41 /* Load_wav.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */; }; + BD4216739C5F30A578688CB3 /* Load_fmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */; }; + BE9B2A6B02AEFB9DF68080AB /* Snd_fx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */; }; + C0082C03041BFD35F7ED8243 /* Reverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B50C144B262EB53DDBF5628B /* Reverb.cpp */; }; + C4FBD3C878F7ECFA5AAA2A08 /* openmpt-mpg123.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = 738151100DDB3A024A139F50 /* openmpt-mpg123.lib */; }; + C55C8AFDA479A52F8083013D /* UMXTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */; }; + C746074BA663217D826C7D8B /* Load_mt2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */; }; + C79768571036A68933625E97 /* libopenmpt_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */; }; + C81D1553A73A2F8583438B93 /* Load_dmf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */; }; + CB31B3AF3F1A2B616167D9EF /* modsmp_ctrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */; }; + CC12FBA114B239D337DDF1E1 /* Compressor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9334A009842C0DFBF02F8E49 /* Compressor.cpp */; }; + CCEFFE57CC92E18906E79497 /* MIDIEvents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */; }; + CEDA1F2FDEBF4B61CB32D56F /* Chorus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84A787B7269123A91DB835F7 /* Chorus.cpp */; }; + CF000469179F429B3ACAFAA9 /* tuningCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */; }; + CF116C1742F9E3C965479257 /* Load_symmod.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7D070D1F43950491B1972B5F /* Load_symmod.cpp */; }; + D1EA5157B1076B898D10C797 /* Load_far.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BB2E75F2E40B1519719559F /* Load_far.cpp */; }; + D2EFC1DFEDBC3091F18CC81F /* Load_dsym.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */; }; + D309698B1BA8A7BD3ED45FCB /* SampleFormatOpus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */; }; + D443016FB3601BA18F6977AF /* S3MTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */; }; + D83D74BB708A5A6D9ED15AFB /* Snd_flt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */; }; + D86AE3F94C535BAB6EA10A39 /* ModSequence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEC583E195537B530355A221 /* ModSequence.cpp */; }; + DC9752537A78530551F69893 /* MixerSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */; }; + DEB582A5DE5865D718AD18E5 /* modcommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */; }; + DEBC9FDC22D0710E16A1F61C /* version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FDF24AF52801665192D64 /* version.cpp */; }; + DF08AE5AEEEDDA8CDB61649A /* mptPathString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */; }; + E6583D037EA522B5ACEC2343 /* ITTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 778D494BBBDBEEBDFE03278B /* ITTools.cpp */; }; + E76008D1C67D2303A2867F11 /* Load_med.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F093E392197082B8A6FAC79 /* Load_med.cpp */; }; + E79434E3857535955CF37B23 /* SampleFormats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */; }; + E7C01BBFC6DD35F1A2E691FF /* Load_itp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A572747FCE4F13965BD9587 /* Load_itp.cpp */; }; + E9363E2F818323E1AFCA246F /* TinyFFT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */; }; + EA420947C95F2379A5687F87 /* Load_sfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C950084F5BDDD241C4B6768F /* Load_sfx.cpp */; }; + EDE4FB2CD37C025E96C1116C /* serialization_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */; }; + F0D031F98EB132AB662F7839 /* ModInstrument.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */; }; + F4EF37CFD40C5201B015AE0F /* Load_ult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FD19A57125F64497B380897 /* Load_ult.cpp */; }; + F57A8B7BD497A5ADB0A101BB /* Load_xmf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */; }; + F59363E88FB7591A3FDD3A28 /* SymMODEcho.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */; }; + F5A6792FD4C39361B0CCEF6F /* Load_dtm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */; }; + F65565599436660B6BB4AB99 /* libopenmpt_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */; }; + FD083C9917D4AB4B1BA542D9 /* OggStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */; }; + FD572F63B04D3915016F95A3 /* SampleFormatSFZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */; }; + FE6ED6D3DD8BF105B9954D13 /* Load_stp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 35790BDC7DE9F00EC288C21C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 04155894998C17C608286ED4 /* ext/mpg123.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C6BCBF7D1D4A29EFF5C33DBD; + remoteInfo = "openmpt-mpg123.dll"; + }; + 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E64FF33AA9BBB4ECE85F597A /* ext/ogg.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 886C6A4681D26BB8756DC886; + remoteInfo = "openmpt-ogg.dll"; + }; + 7BC1F4B7C432D8E908D1AAF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 41BBEA4AD732A97C45CF008A /* ext/vorbis.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 058BB8B85C19232A349236F8; + remoteInfo = "openmpt-vorbis.dll"; + }; + 87B37E75D02462A714C334B5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 04155894998C17C608286ED4 /* ext/mpg123.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 6CFC1BC3B56CFFF5FA0BD203; + remoteInfo = "openmpt-mpg123.dll"; + }; + CDFC6750166D4B825B0C1D90 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 41BBEA4AD732A97C45CF008A /* ext/vorbis.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 6EE3599EB7543DD0FBF30FDE; + remoteInfo = "openmpt-vorbis.dll"; + }; + EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E64FF33AA9BBB4ECE85F597A /* ext/ogg.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5036DE60765D0E12DD6404A0; + remoteInfo = "openmpt-ogg.dll"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00114BD59DF24C8775709215 /* callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = callbackstream.hpp; path = ../../src/mpt/io_read/callbackstream.hpp; sourceTree = ""; }; + 01230426588877180A969266 /* buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = buffer.hpp; path = ../../src/mpt/io_write/buffer.hpp; sourceTree = ""; }; + 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Distortion.cpp; path = ../../soundlib/plugins/dmo/Distortion.cpp; sourceTree = ""; }; + 01D708ED277F035F45AF872D /* libopenmpt_stream_callbacks_buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_buffer.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_buffer.h; sourceTree = ""; }; + 021DA33D0EA855AF898D217D /* constexpr_throw.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = constexpr_throw.hpp; path = ../../src/mpt/base/constexpr_throw.hpp; sourceTree = ""; }; + 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mus_km.cpp; path = ../../soundlib/Load_mus_km.cpp; sourceTree = ""; }; + 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TinyFFT.cpp; path = ../../soundlib/TinyFFT.cpp; sourceTree = ""; }; + 04155894998C17C608286ED4 /* openmpt-mpg123.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "mpg123.xcodeproj"; path = ext/mpg123.xcodeproj; sourceTree = SOURCE_ROOT; }; + 046F30B171973F23732A2EF1 /* numeric.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = numeric.hpp; path = ../../src/mpt/base/numeric.hpp; sourceTree = ""; }; + 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = EQ.cpp; path = ../../sounddsp/EQ.cpp; sourceTree = ""; }; + 04EAEC77C7AB4CE924E02AB7 /* DMOPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DMOPlugin.h; path = ../../soundlib/plugins/dmo/DMOPlugin.h; sourceTree = ""; }; + 06C40A24C9846A9626B94864 /* io_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_stdstream.hpp; path = ../../src/mpt/io/io_stdstream.hpp; sourceTree = ""; }; + 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_stm.cpp; path = ../../soundlib/Load_stm.cpp; sourceTree = ""; }; + 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatSFZ.cpp; path = ../../soundlib/SampleFormatSFZ.cpp; sourceTree = ""; }; + 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileType.cpp; path = ../../common/mptFileType.cpp; sourceTree = ""; }; + 07580841CEBCC33359749681 /* tests_string_utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_utility.hpp; path = ../../src/mpt/string/tests/tests_string_utility.hpp; sourceTree = ""; }; + 079DA5A7A1C19AD951E77BE7 /* filedata_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_memory.hpp; path = ../../src/mpt/io_read/filedata_memory.hpp; sourceTree = ""; }; + 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ptm.cpp; path = ../../soundlib/Load_ptm.cpp; sourceTree = ""; }; + 09387CD815C32F4A90A7FB18 /* PluginMixBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginMixBuffer.h; path = ../../soundlib/plugins/PluginMixBuffer.h; sourceTree = ""; }; + 09573FAA7A79E09C30408DEA /* arch.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = arch.hpp; path = ../../src/mpt/arch/arch.hpp; sourceTree = ""; }; + 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mtm.cpp; path = ../../soundlib/Load_mtm.cpp; sourceTree = ""; }; + 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = modsmp_ctrl.cpp; path = ../../soundlib/modsmp_ctrl.cpp; sourceTree = ""; }; + 0A20B0FECCE111702A15EF3E /* ComponentManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ComponentManager.h; path = ../../common/ComponentManager.h; sourceTree = ""; }; + 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerXPK.cpp; path = ../../soundlib/ContainerXPK.cpp; sourceTree = ""; }; + 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dtm.cpp; path = ../../soundlib/Load_dtm.cpp; sourceTree = ""; }; + 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mt2.cpp; path = ../../soundlib/Load_mt2.cpp; sourceTree = ""; }; + 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mo3.cpp; path = ../../soundlib/Load_mo3.cpp; sourceTree = ""; }; + 0F8105B483DB4AA601BED3F4 /* dos_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dos_version.hpp; path = ../../src/mpt/osinfo/dos_version.hpp; sourceTree = ""; }; + 0FDA8FB11C654223974A0DF1 /* libopenmpt_version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_version.h; path = ../../libopenmpt/libopenmpt_version.h; sourceTree = ""; }; + 1054EEE754A3945996CACD27 /* Fastmix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Fastmix.cpp; path = ../../soundlib/Fastmix.cpp; sourceTree = ""; }; + 107683B90475CD2B8960E1F9 /* detect_quirks.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_quirks.hpp; path = ../../src/mpt/base/detect_quirks.hpp; sourceTree = ""; }; + 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_gt2.cpp; path = ../../soundlib/Load_gt2.cpp; sourceTree = ""; }; + 1197459E05968F108A81A3DE /* feature_flags.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = feature_flags.hpp; path = ../../src/mpt/arch/feature_flags.hpp; sourceTree = ""; }; + 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerMMCMP.cpp; path = ../../soundlib/ContainerMMCMP.cpp; sourceTree = ""; }; + 12DCF57C800503EE8197F3BC /* mptBaseUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseUtils.h; path = ../../common/mptBaseUtils.h; sourceTree = ""; }; + 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileIO.cpp; path = ../../common/mptFileIO.cpp; sourceTree = ""; }; + 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ComponentManager.cpp; path = ../../common/ComponentManager.cpp; sourceTree = ""; }; + 14715833DAFF4FA549017673 /* WindowedFIR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WindowedFIR.cpp; path = ../../soundlib/WindowedFIR.cpp; sourceTree = ""; }; + 159B6F7E099AB8F08E85CDBE /* PluginManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginManager.h; path = ../../soundlib/plugins/PluginManager.h; sourceTree = ""; }; + 15A918AF09A862218E9376EF /* aligned_array.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = aligned_array.hpp; path = ../../src/mpt/base/aligned_array.hpp; sourceTree = ""; }; + 1679D9615AC87ED39CEFB7A1 /* alloc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = alloc.hpp; path = ../../src/mpt/base/alloc.hpp; sourceTree = ""; }; + 175234BFDDE02C314BE252FF /* detect_os.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_os.hpp; path = ../../src/mpt/base/detect_os.hpp; sourceTree = ""; }; + 178BC3E3DA4C245537810223 /* native_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = native_path.hpp; path = ../../src/mpt/path/native_path.hpp; sourceTree = ""; }; + 17F58A2FDAB5EAA137EAC86F /* detect_libc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_libc.hpp; path = ../../src/mpt/base/detect_libc.hpp; sourceTree = ""; }; + 18A72A335CF5CFA59F1D0873 /* seed.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = seed.hpp; path = ../../src/mpt/random/seed.hpp; sourceTree = ""; }; + 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Sndmix.cpp; path = ../../soundlib/Sndmix.cpp; sourceTree = ""; }; + 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RowVisitor.cpp; path = ../../soundlib/RowVisitor.cpp; sourceTree = ""; }; + 1A94BBC4BC7E57B6B3A56A04 /* mptStringFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptStringFormat.h; path = ../../common/mptStringFormat.h; sourceTree = ""; }; + 1AA25C6F0B99CA61779D4AAF /* check_platform.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = check_platform.hpp; path = ../../src/mpt/base/check_platform.hpp; sourceTree = ""; }; + 1AD54F9F7616A3114970EDDF /* Paula.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Paula.h; path = ../../soundlib/Paula.h; sourceTree = ""; }; + 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Tagging.cpp; path = ../../soundlib/Tagging.cpp; sourceTree = ""; }; + 1C2F81B7DEEFE2293C24BFF7 /* detect_arch.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_arch.hpp; path = ../../src/mpt/base/detect_arch.hpp; sourceTree = ""; }; + 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatOpus.cpp; path = ../../soundlib/SampleFormatOpus.cpp; sourceTree = ""; }; + 1CE2C4318A0AD2A38B9DC271 /* device.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = device.hpp; path = ../../src/mpt/random/device.hpp; sourceTree = ""; }; + 1E7AA06D8BA2AEDF8D359EAD /* simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple.hpp; path = ../../src/mpt/format/simple.hpp; sourceTree = ""; }; + 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_s3m.cpp; path = ../../soundlib/Load_s3m.cpp; sourceTree = ""; }; + 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WAVTools.cpp; path = ../../soundlib/WAVTools.cpp; sourceTree = ""; }; + 2052C727B2E091191BB93567 /* Load_mdl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mdl.cpp; path = ../../soundlib/Load_mdl.cpp; sourceTree = ""; }; + 209166838DB974F58F4C64C3 /* numbers.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = numbers.hpp; path = ../../src/mpt/base/numbers.hpp; sourceTree = ""; }; + 20B693A5E7448B175546B1E5 /* MixerSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerSettings.h; path = ../../soundlib/MixerSettings.h; sourceTree = ""; }; + 212A36FD7B2B4DEF4272453D /* semantic_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = semantic_version.hpp; path = ../../src/mpt/base/semantic_version.hpp; sourceTree = ""; }; + 2151B0037C9303754FED4E43 /* Mixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Mixer.h; path = ../../soundlib/Mixer.h; sourceTree = ""; }; + 22594181666D12B35A3E97C1 /* fileref.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fileref.hpp; path = ../../src/mpt/io_file/fileref.hpp; sourceTree = ""; }; + 2323E4A5944685974A0D32E5 /* Snd_defs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Snd_defs.h; path = ../../soundlib/Snd_defs.h; sourceTree = ""; }; + 236E8DFB1D304A6D572F4C3B /* Tagging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tagging.h; path = ../../soundlib/Tagging.h; sourceTree = ""; }; + 23EF16CF7F4F3B81C192DD0F /* filedata_base_buffered.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_buffered.hpp; path = ../../src/mpt/io_read/filedata_base_buffered.hpp; sourceTree = ""; }; + 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerUMX.cpp; path = ../../soundlib/ContainerUMX.cpp; sourceTree = ""; }; + 25EAC3A1C044AC93FC7D11E1 /* unique_basename.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = unique_basename.hpp; path = ../../src/mpt/io_file_unique/unique_basename.hpp; sourceTree = ""; }; + 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mod_specifications.cpp; path = ../../soundlib/mod_specifications.cpp; sourceTree = ""; }; + 27B40A4D98D6AB3F4E9D588D /* SampleIO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleIO.h; path = ../../soundlib/SampleIO.h; sourceTree = ""; }; + 2810796521D235D75BD137A5 /* XMTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = XMTools.h; path = ../../soundlib/XMTools.h; sourceTree = ""; }; + 28D2F38195FB01F3978DF1C1 /* modsmp_ctrl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = modsmp_ctrl.h; path = ../../soundlib/modsmp_ctrl.h; sourceTree = ""; }; + 29DC06EFBC69D0E12542752F /* Load_ams.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ams.cpp; path = ../../soundlib/Load_ams.cpp; sourceTree = ""; }; + 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_xm.cpp; path = ../../soundlib/Load_xm.cpp; sourceTree = ""; }; + 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixerSettings.cpp; path = ../../soundlib/MixerSettings.cpp; sourceTree = ""; }; + 2BF8C6379D1B672952E21477 /* WAVTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WAVTools.h; path = ../../soundlib/WAVTools.h; sourceTree = ""; }; + 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ITCompression.cpp; path = ../../soundlib/ITCompression.cpp; sourceTree = ""; }; + 2C28EA4338B39CB5B3986883 /* wrapping_divide.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrapping_divide.hpp; path = ../../src/mpt/base/wrapping_divide.hpp; sourceTree = ""; }; + 2D02F4CF9E2595C153EC430F /* UMXTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = UMXTools.h; path = ../../soundlib/UMXTools.h; sourceTree = ""; }; + 2E1DD07ED0076C70C72E7EBE /* tests_io.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_io.hpp; path = ../../src/mpt/io/tests/tests_io.hpp; sourceTree = ""; }; + 2E2F32DF9F51D3D15518811F /* hex.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = hex.hpp; path = ../../src/mpt/binary/hex.hpp; sourceTree = ""; }; + 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_xmf.cpp; path = ../../soundlib/Load_xmf.cpp; sourceTree = ""; }; + 2F3B0AD7F5C9024963CB2917 /* ITCompression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITCompression.h; path = ../../soundlib/ITCompression.h; sourceTree = ""; }; + 321030713E9AE2E3B97FAEB1 /* detect_compiler.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_compiler.hpp; path = ../../src/mpt/base/detect_compiler.hpp; sourceTree = ""; }; + 3286C74DF54727BF527C058D /* Flanger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Flanger.cpp; path = ../../soundlib/plugins/dmo/Flanger.cpp; sourceTree = ""; }; + 32BAAF6B89D057DDB618EDAB /* tests_base_saturate_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_saturate_cast.hpp; path = ../../src/mpt/base/tests/tests_base_saturate_cast.hpp; sourceTree = ""; }; + 338C775D77DB1CCFBA02559D /* BitReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BitReader.h; path = ../../soundlib/BitReader.h; sourceTree = ""; }; + 34D45985C7622377303AC7C5 /* Load_imf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_imf.cpp; path = ../../soundlib/Load_imf.cpp; sourceTree = ""; }; + 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_c.cpp; path = ../../libopenmpt/libopenmpt_c.cpp; sourceTree = ""; }; + 36619CBCFDC657AE887E2AFC /* inputfile_filecursor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = inputfile_filecursor.hpp; path = ../../src/mpt/io_file_read/inputfile_filecursor.hpp; sourceTree = ""; }; + 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dmf.cpp; path = ../../soundlib/Load_dmf.cpp; sourceTree = ""; }; + 37064A799107616B584E58B9 /* tests_random.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_random.hpp; path = ../../src/mpt/random/tests/tests_random.hpp; sourceTree = ""; }; + 37F80675CA85D067335E74B5 /* Load_amf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_amf.cpp; path = ../../soundlib/Load_amf.cpp; sourceTree = ""; }; + 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerPP20.cpp; path = ../../soundlib/ContainerPP20.cpp; sourceTree = ""; }; + 392551FD7D73F76FBF9B303D /* ModSample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSample.h; path = ../../soundlib/ModSample.h; sourceTree = ""; }; + 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AudioCriticalSection.cpp; path = ../../soundlib/AudioCriticalSection.cpp; sourceTree = ""; }; + 39C1318B738BE83D28E737CB /* filecursor_filename_traits.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_filename_traits.hpp; path = ../../src/mpt/io_read/filecursor_filename_traits.hpp; sourceTree = ""; }; + 39CF376FCC5D01613535A5AF /* FloatMixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FloatMixer.h; path = ../../soundlib/FloatMixer.h; sourceTree = ""; }; + 3A4473F97E93196BC0BA5239 /* join.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = join.hpp; path = ../../src/mpt/format/join.hpp; sourceTree = ""; }; + 3AADECCD91C3953FBE0C2B0D /* libopenmpt_stream_callbacks_fd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_fd.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_fd.h; sourceTree = ""; }; + 3AC37DA5015175176F539BE5 /* namespace.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = namespace.hpp; path = ../../src/mpt/base/namespace.hpp; sourceTree = ""; }; + 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = S3MTools.cpp; path = ../../soundlib/S3MTools.cpp; sourceTree = ""; }; + 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UpgradeModule.cpp; path = ../../soundlib/UpgradeModule.cpp; sourceTree = ""; }; + 3C628FD12D59FDC3995D7E11 /* nlohmann_json.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = nlohmann_json.hpp; path = ../../src/mpt/detect/nlohmann_json.hpp; sourceTree = ""; }; + 3CC72D5B942CA04D463ABB9B /* integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = integer.hpp; path = ../../src/mpt/endian/integer.hpp; sourceTree = ""; }; + 3D34478136F603F370F505C1 /* TinyFFT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TinyFFT.h; path = ../../soundlib/TinyFFT.h; sourceTree = ""; }; + 3E2FDF24AF52801665192D64 /* version.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = version.cpp; path = ../../common/version.cpp; sourceTree = ""; }; + 3EEBB71B8158038D397E755B /* libopenmpt_stream_callbacks_file_mingw.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_mingw.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_mingw.h; sourceTree = ""; }; + 3F5591FF83A43771C5CB703F /* Container.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Container.h; path = ../../soundlib/Container.h; sourceTree = ""; }; + 406A557CF3605F2E4482BBBC /* out_of_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = out_of_memory.hpp; path = ../../src/mpt/out_of_memory/out_of_memory.hpp; sourceTree = ""; }; + 40C5E675B1E8876767AF34B5 /* uuid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = uuid.hpp; path = ../../src/mpt/uuid/uuid.hpp; sourceTree = ""; }; + 417FE082D6F69FB44592F6C2 /* libc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libc.hpp; path = ../../src/mpt/check/libc.hpp; sourceTree = ""; }; + 41BBBCC5DBDFB1F78C059305 /* exception_text.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = exception_text.hpp; path = ../../src/mpt/exception/exception_text.hpp; sourceTree = ""; }; + 41BBEA4AD732A97C45CF008A /* openmpt-vorbis.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "vorbis.xcodeproj"; path = ext/vorbis.xcodeproj; sourceTree = SOURCE_ROOT; }; + 41DFAAC7AF07B939B09AA907 /* libopenmpt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt.h; path = ../../libopenmpt/libopenmpt.h; sourceTree = ""; }; + 43B7419134AEAF83A0B22FD1 /* libopenmpt_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_config.h; path = ../../libopenmpt/libopenmpt_config.h; sourceTree = ""; }; + 43CBFB4A068C5BBC63C1398A /* mptFileTemporary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileTemporary.h; path = ../../common/mptFileTemporary.h; sourceTree = ""; }; + 44E6E1C323897D35D86B8003 /* tests_base_bit.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_bit.hpp; path = ../../src/mpt/base/tests/tests_base_bit.hpp; sourceTree = ""; }; + 45D0E0DE525B9350CD405F1E /* DigiBoosterEcho.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DigiBoosterEcho.h; path = ../../soundlib/plugins/DigiBoosterEcho.h; sourceTree = ""; }; + 45DBF5F73F9DB269799CB437 /* Dlsbank.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Dlsbank.h; path = ../../soundlib/Dlsbank.h; sourceTree = ""; }; + 4614D43FB73775316CFE227F /* math.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = math.hpp; path = ../../src/mpt/base/math.hpp; sourceTree = ""; }; + 46877D383A86C6AABF71DB78 /* PluginStructs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginStructs.h; path = ../../soundlib/plugins/PluginStructs.h; sourceTree = ""; }; + 46BE019F097E621166B33FDF /* SampleNormalize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleNormalize.h; path = ../../soundlib/SampleNormalize.h; sourceTree = ""; }; + 473316F00DC10E627BC33530 /* x86_amd64.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = x86_amd64.hpp; path = ../../src/mpt/arch/x86_amd64.hpp; sourceTree = ""; }; + 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatMP3.cpp; path = ../../soundlib/SampleFormatMP3.cpp; sourceTree = ""; }; + 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SymMODEcho.cpp; path = ../../soundlib/plugins/SymMODEcho.cpp; sourceTree = ""; }; + 4756C54F9DE42FC1765D438F /* OPL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OPL.h; path = ../../soundlib/OPL.h; sourceTree = ""; }; + 48199D39B93C3E2B6F02EB79 /* tuning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = tuning.cpp; path = ../../soundlib/tuning.cpp; sourceTree = ""; }; + 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Tables.cpp; path = ../../soundlib/Tables.cpp; sourceTree = ""; }; + 49E264470CA2C4B969D7A287 /* engine_lcg.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = engine_lcg.hpp; path = ../../src/mpt/random/engine_lcg.hpp; sourceTree = ""; }; + 4AECD572BC0F766471D623B2 /* mptString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptString.h; path = ../../common/mptString.h; sourceTree = ""; }; + 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptPathString.cpp; path = ../../common/mptPathString.cpp; sourceTree = ""; }; + 4CDD73CDC0C5EB7FE3139A0D /* logic_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = logic_error.hpp; path = ../../src/mpt/exception/logic_error.hpp; sourceTree = ""; }; + 4D1485535F373B4538387393 /* tests_base_arithmetic_shift.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_arithmetic_shift.hpp; path = ../../src/mpt/base/tests/tests_base_arithmetic_shift.hpp; sourceTree = ""; }; + 4DFC0969924AAEDBD471E7A9 /* ltdl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = ltdl.hpp; path = ../../src/mpt/detect/ltdl.hpp; sourceTree = ""; }; + 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_plm.cpp; path = ../../soundlib/Load_plm.cpp; sourceTree = ""; }; + 4E96BB31E124852349FD2971 /* types.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = types.hpp; path = ../../src/mpt/string/types.hpp; sourceTree = ""; }; + 4FB7A50743B6EE79C8A20347 /* floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = floatingpoint.hpp; path = ../../src/mpt/base/floatingpoint.hpp; sourceTree = ""; }; + 50318A59BD5998CBBEEC8899 /* os_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = os_path.hpp; path = ../../src/mpt/path/os_path.hpp; sourceTree = ""; }; + 50CF7EB4C1F21FA677B8CCF4 /* mptFileIO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileIO.h; path = ../../common/mptFileIO.h; sourceTree = ""; }; + 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MIDIMacros.cpp; path = ../../soundlib/MIDIMacros.cpp; sourceTree = ""; }; + 5178AA15C29B4B077861F855 /* mfc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mfc.hpp; path = ../../src/mpt/detect/mfc.hpp; sourceTree = ""; }; + 51E2F9635E6DABD5D95277A3 /* SoundFilePlayConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SoundFilePlayConfig.h; path = ../../soundlib/SoundFilePlayConfig.h; sourceTree = ""; }; + 51EB7985F3D51577EAFC27C5 /* base64url.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base64url.hpp; path = ../../src/mpt/binary/base64url.hpp; sourceTree = ""; }; + 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_uax.cpp; path = ../../soundlib/Load_uax.cpp; sourceTree = ""; }; + 54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = ""; }; + 55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = ""; }; + 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = ""; }; + 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = ""; }; + 5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = ""; }; + 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = ""; }; + 57E617F588CA0FE79BE24635 /* Reverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Reverb.h; path = ../../sounddsp/Reverb.h; sourceTree = ""; }; + 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_cxx.cpp; path = ../../libopenmpt/libopenmpt_cxx.cpp; sourceTree = ""; }; + 5AF83E8DC8204CFFC9B33CCD /* pointer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = pointer.hpp; path = ../../src/mpt/base/pointer.hpp; sourceTree = ""; }; + 5BE26A37EE7034295748D877 /* modcommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = modcommand.h; path = ../../soundlib/modcommand.h; sourceTree = ""; }; + 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatVorbis.cpp; path = ../../soundlib/SampleFormatVorbis.cpp; sourceTree = ""; }; + 5CFFC0612B231413B23166A1 /* parse.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = parse.hpp; path = ../../src/mpt/parse/parse.hpp; sourceTree = ""; }; + 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptRandom.cpp; path = ../../common/mptRandom.cpp; sourceTree = ""; }; + 5E8119A76B0BCC19E5F097E7 /* simple_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_integer.hpp; path = ../../src/mpt/format/simple_integer.hpp; sourceTree = ""; }; + 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModChannel.cpp; path = ../../soundlib/ModChannel.cpp; sourceTree = ""; }; + 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixFuncTable.cpp; path = ../../soundlib/MixFuncTable.cpp; sourceTree = ""; }; + 6058487C545791EED942A6BC /* PlugInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PlugInterface.h; path = ../../soundlib/plugins/PlugInterface.h; sourceTree = ""; }; + 62235C27A6720199E8993A67 /* Load_it.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_it.cpp; path = ../../soundlib/Load_it.cpp; sourceTree = ""; }; + 62E32DEB72C85A1D5F3BE42B /* filedata_base.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base.hpp; path = ../../src/mpt/io_read/filedata_base.hpp; sourceTree = ""; }; + 6303157093E70D62A6FF43B0 /* Logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../common/Logging.h; sourceTree = ""; }; + 632A109AF5B7DA8C5E907EDA /* io_span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_span.hpp; path = ../../src/mpt/io/io_span.hpp; sourceTree = ""; }; + 63FDD8AF94E1D0A1A7FA06EF /* Tables.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tables.h; path = ../../soundlib/Tables.h; sourceTree = ""; }; + 64377F84A84B50B69C1CD5C4 /* compiler.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = compiler.hpp; path = ../../src/mpt/check/compiler.hpp; sourceTree = ""; }; + 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DMOUtils.cpp; path = ../../soundlib/plugins/dmo/DMOUtils.cpp; sourceTree = ""; }; + 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_stp.cpp; path = ../../soundlib/Load_stp.cpp; sourceTree = ""; }; + 6687823BDAE1C72D58C5507B /* tuningcollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuningcollection.h; path = ../../soundlib/tuningcollection.h; sourceTree = ""; }; + 66CA3B04BE2FADF6703DC944 /* mptBaseMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseMacros.h; path = ../../common/mptBaseMacros.h; sourceTree = ""; }; + 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Message.cpp; path = ../../soundlib/Message.cpp; sourceTree = ""; }; + 6858F8CA2EE6F03C9CE9170A /* LFOPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LFOPlugin.h; path = ../../soundlib/plugins/LFOPlugin.h; sourceTree = ""; }; + 68FC5709D624657BD7B75549 /* concat.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = concat.hpp; path = ../../src/mpt/format/concat.hpp; sourceTree = ""; }; + 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_wav.cpp; path = ../../soundlib/Load_wav.cpp; sourceTree = ""; }; + 6A572747FCE4F13965BD9587 /* Load_itp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_itp.cpp; path = ../../soundlib/Load_itp.cpp; sourceTree = ""; }; + 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dbm.cpp; path = ../../soundlib/Load_dbm.cpp; sourceTree = ""; }; + 6AE995E9FD775FDB66500429 /* Load_okt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_okt.cpp; path = ../../soundlib/Load_okt.cpp; sourceTree = ""; }; + 6AF57E36C636D1A899911C76 /* stdafx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stdafx.h; path = ../../common/stdafx.h; sourceTree = ""; }; + 6B9C8BDDC301FECF75101A1D /* Gargle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Gargle.h; path = ../../soundlib/plugins/dmo/Gargle.h; sourceTree = ""; }; + 6C67B7D97E1EF7CBF38CE619 /* tests_base_math.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_math.hpp; path = ../../src/mpt/base/tests/tests_base_math.hpp; sourceTree = ""; }; + 6D2350A8B171F61AF3992EE8 /* FileReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FileReader.h; path = ../../common/FileReader.h; sourceTree = ""; }; + 6E84090F7E6935416ADCBF4F /* environment.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = environment.hpp; path = ../../src/mpt/environment/environment.hpp; sourceTree = ""; }; + 6F3A912F8923F36144AA076F /* filecursor_callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_callbackstream.hpp; path = ../../src/mpt/io_read/filecursor_callbackstream.hpp; sourceTree = ""; }; + 70644035FF1571275A9F8E75 /* libopenmpt_stream_callbacks_file_msvcrt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_msvcrt.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h; sourceTree = ""; }; + 712230EFB9C16F21DCED272F /* filecursor_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_memory.hpp; path = ../../src/mpt/io_read/filecursor_memory.hpp; sourceTree = ""; }; + 7154B71FCB55CE11929CC55F /* libopenmpt_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_internal.h; path = ../../libopenmpt/libopenmpt_internal.h; sourceTree = ""; }; + 7159D71DCB5AEE0F92A1E55D /* default_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_integer.hpp; path = ../../src/mpt/format/default_integer.hpp; sourceTree = ""; }; + 7214DF31A1A6AE237CB3ED71 /* opal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = opal.h; path = ../../soundlib/opal.h; sourceTree = ""; }; + 721CEF1FC98262117B907D5F /* helpers.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = helpers.hpp; path = ../../src/mpt/format/helpers.hpp; sourceTree = ""; }; + 73262ABB150FC6AD0C36D8FB /* DMOUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DMOUtils.h; path = ../../soundlib/plugins/dmo/DMOUtils.h; sourceTree = ""; }; + 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_ext_impl.cpp; path = ../../libopenmpt/libopenmpt_ext_impl.cpp; sourceTree = ""; }; + 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Snd_flt.cpp; path = ../../soundlib/Snd_flt.cpp; sourceTree = ""; }; + 73A52C155E915207A6771A55 /* EQ.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EQ.h; path = ../../sounddsp/EQ.h; sourceTree = ""; }; + 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = modcommand.cpp; path = ../../soundlib/modcommand.cpp; sourceTree = ""; }; + 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Snd_fx.cpp; path = ../../soundlib/Snd_fx.cpp; sourceTree = ""; }; + 74D96CA8E5FC0D9A9BC2BAE8 /* mptAssert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptAssert.h; path = ../../common/mptAssert.h; sourceTree = ""; }; + 74DCDADDCC424DCF7E50691D /* MixFuncTable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixFuncTable.h; path = ../../soundlib/MixFuncTable.h; sourceTree = ""; }; + 7523D3EEA607CBE0B920022E /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../../common/version.h; sourceTree = ""; }; + 755174CF6950BE41EE3BD30F /* detect_libcxx.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_libcxx.hpp; path = ../../src/mpt/base/detect_libcxx.hpp; sourceTree = ""; }; + 75EFCB7913D0CC2BEB4F11B9 /* runtime_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = runtime_error.hpp; path = ../../src/mpt/exception/runtime_error.hpp; sourceTree = ""; }; + 778D494BBBDBEEBDFE03278B /* ITTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ITTools.cpp; path = ../../soundlib/ITTools.cpp; sourceTree = ""; }; + 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mod.cpp; path = ../../soundlib/Load_mod.cpp; sourceTree = ""; }; + 787945A7E5A15419E73443E7 /* integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = integer.hpp; path = ../../src/mpt/base/integer.hpp; sourceTree = ""; }; + 788395FAAA7CE0AC245C1C3A /* mfc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mfc.hpp; path = ../../src/mpt/check/mfc.hpp; sourceTree = ""; }; + 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Gargle.cpp; path = ../../soundlib/plugins/dmo/Gargle.cpp; sourceTree = ""; }; + 78CAB4630B587E55743122A3 /* SampleIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleIO.cpp; path = ../../soundlib/SampleIO.cpp; sourceTree = ""; }; + 793E301E72FFEC90ACFEEE5E /* base.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base.hpp; path = ../../src/mpt/io/base.hpp; sourceTree = ""; }; + 7A6823C37429E035AE28E203 /* Message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Message.h; path = ../../soundlib/Message.h; sourceTree = ""; }; + 7C15603DE93D6EAFEAD05E7D /* engine.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = engine.hpp; path = ../../src/mpt/random/engine.hpp; sourceTree = ""; }; + 7C2DCED7ED506FC9A3171D17 /* path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = path.hpp; path = ../../src/mpt/path/path.hpp; sourceTree = ""; }; + 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMTools.cpp; path = ../../soundlib/XMTools.cpp; sourceTree = ""; }; + 7D070D1F43950491B1972B5F /* Load_symmod.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_symmod.cpp; path = ../../soundlib/Load_symmod.cpp; sourceTree = ""; }; + 7D6EAF1E983B1DD09C0BB55E /* tests_crc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_crc.hpp; path = ../../src/mpt/crc/tests/tests_crc.hpp; sourceTree = ""; }; + 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WavesReverb.cpp; path = ../../soundlib/plugins/dmo/WavesReverb.cpp; sourceTree = ""; }; + 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_impl.cpp; path = ../../libopenmpt/libopenmpt_impl.cpp; sourceTree = ""; }; + 7FD19A57125F64497B380897 /* Load_ult.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ult.cpp; path = ../../soundlib/Load_ult.cpp; sourceTree = ""; }; + 80C993CB8D54463D0839120B /* message_macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = message_macros.hpp; path = ../../src/mpt/format/message_macros.hpp; sourceTree = ""; }; + 80F9D5FD1722E7EFD889443D /* default_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_floatingpoint.hpp; path = ../../src/mpt/format/default_floatingpoint.hpp; sourceTree = ""; }; + 82EA4C5D44A2DDCFEBBDAA9D /* tests_base_wrapping_divide.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_wrapping_divide.hpp; path = ../../src/mpt/base/tests/tests_base_wrapping_divide.hpp; sourceTree = ""; }; + 830F3566F431D658A9F883A6 /* Logging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Logging.cpp; path = ../../common/Logging.cpp; sourceTree = ""; }; + 84A787B7269123A91DB835F7 /* Chorus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Chorus.cpp; path = ../../soundlib/plugins/dmo/Chorus.cpp; sourceTree = ""; }; + 85812219180EEC0B80E79059 /* secure.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = secure.hpp; path = ../../src/mpt/base/secure.hpp; sourceTree = ""; }; + 85A36D37F9FDB22977E13B77 /* os_path_long.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = os_path_long.hpp; path = ../../src/mpt/path/os_path_long.hpp; sourceTree = ""; }; + 86260AE5E2AD0F576B4FC925 /* compiletime_warning.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = compiletime_warning.hpp; path = ../../src/mpt/base/compiletime_warning.hpp; sourceTree = ""; }; + 87A62ABDE1A741AFA8EE38FD /* AudioCriticalSection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioCriticalSection.h; path = ../../soundlib/AudioCriticalSection.h; sourceTree = ""; }; + 8856685FF57E76D1F711669F /* base64.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base64.hpp; path = ../../src/mpt/binary/base64.hpp; sourceTree = ""; }; + 8876678BE2777E7DA9BE75CB /* default_engines.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_engines.hpp; path = ../../src/mpt/random/default_engines.hpp; sourceTree = ""; }; + 8A87EA73FEE22F657CC5B8B3 /* macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = macros.hpp; path = ../../src/mpt/string_transcode/macros.hpp; sourceTree = ""; }; + 8ABDA3472E24D0F9455A8987 /* filedata_base_unseekable.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_unseekable.hpp; path = ../../src/mpt/io_read/filedata_base_unseekable.hpp; sourceTree = ""; }; + 8ABF23E958E2779BDFF0CA29 /* mutex.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mutex.hpp; path = ../../src/mpt/mutex/mutex.hpp; sourceTree = ""; }; + 8B1AB3CB32904F7DDB555A0B /* filecursor_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_stdstream.hpp; path = ../../src/mpt/io_read/filecursor_stdstream.hpp; sourceTree = ""; }; + 8BE3D4DDCE50214F8676931D /* libopenmpt_stream_callbacks_file_posix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_posix.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_posix.h; sourceTree = ""; }; + 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = patternContainer.cpp; path = ../../soundlib/patternContainer.cpp; sourceTree = ""; }; + 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ParamEq.cpp; path = ../../soundlib/plugins/dmo/ParamEq.cpp; sourceTree = ""; }; + 8C8CA6B3531A9E25C11CC4F3 /* ModSampleCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSampleCopy.h; path = ../../soundlib/ModSampleCopy.h; sourceTree = ""; }; + 8CA9A5C72521933951088407 /* simple_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_floatingpoint.hpp; path = ../../src/mpt/format/simple_floatingpoint.hpp; sourceTree = ""; }; + 8DE932C12076FCB3894FA101 /* crand.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = crand.hpp; path = ../../src/mpt/random/crand.hpp; sourceTree = ""; }; + 8DF141A2BED53994D1ED6FE2 /* mptTime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptTime.h; path = ../../common/mptTime.h; sourceTree = ""; }; + 8EA1F2E35357495507C5F123 /* tests_format_simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_format_simple.hpp; path = ../../src/mpt/format/tests/tests_format_simple.hpp; sourceTree = ""; }; + 8F093E392197082B8A6FAC79 /* Load_med.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_med.cpp; path = ../../soundlib/Load_med.cpp; sourceTree = ""; }; + 8F52A05ED3A145D015C87E9E /* Profiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Profiler.cpp; path = ../../common/Profiler.cpp; sourceTree = ""; }; + 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatBRR.cpp; path = ../../soundlib/SampleFormatBRR.cpp; sourceTree = ""; }; + 90E45EE632CDFAD829F50D26 /* mptStringBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptStringBuffer.h; path = ../../common/mptStringBuffer.h; sourceTree = ""; }; + 9133E604FE5BF476FFEEE444 /* OpCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OpCodes.h; path = ../../soundlib/plugins/OpCodes.h; sourceTree = ""; }; + 915D6003E8C2D2F59AD0EE43 /* message.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = message.hpp; path = ../../src/mpt/format/message.hpp; sourceTree = ""; }; + 91AA522185A99B930A94B061 /* I3DL2Reverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = I3DL2Reverb.h; path = ../../soundlib/plugins/dmo/I3DL2Reverb.h; sourceTree = ""; }; + 91EC613953A4F2ABFABFBF79 /* libopenmpt_stream_callbacks_file.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file.h; sourceTree = ""; }; + 92AB21E22B230F54570A0022 /* windows_wine_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows_wine_version.hpp; path = ../../src/mpt/osinfo/windows_wine_version.hpp; sourceTree = ""; }; + 9334A009842C0DFBF02F8E49 /* Compressor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Compressor.cpp; path = ../../soundlib/plugins/dmo/Compressor.cpp; sourceTree = ""; }; + 9469EF975BCEAA89E6867DD7 /* unique_tempfilename.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = unique_tempfilename.hpp; path = ../../src/mpt/io_file_unique/unique_tempfilename.hpp; sourceTree = ""; }; + 949CE444733F7FB628218284 /* io_virtual_wrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_virtual_wrapper.hpp; path = ../../src/mpt/io/io_virtual_wrapper.hpp; sourceTree = ""; }; + 94CA18088E8BD47AC88AD648 /* Profiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Profiler.h; path = ../../common/Profiler.h; sourceTree = ""; }; + 9620F5BDA843ABAF8144E3FD /* tests_endian_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_floatingpoint.hpp; path = ../../src/mpt/endian/tests/tests_endian_floatingpoint.hpp; sourceTree = ""; }; + 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = serialization_utils.cpp; path = ../../common/serialization_utils.cpp; sourceTree = ""; }; + 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OggStream.cpp; path = ../../soundlib/OggStream.cpp; sourceTree = ""; }; + 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_gdm.cpp; path = ../../soundlib/Load_gdm.cpp; sourceTree = ""; }; + 995821ED5E0D785F127C202D /* tests_string_buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_buffer.hpp; path = ../../src/mpt/string/tests/tests_string_buffer.hpp; sourceTree = ""; }; + 9B1917A761A70F19CFA935E7 /* ParamEq.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ParamEq.h; path = ../../soundlib/plugins/dmo/ParamEq.h; sourceTree = ""; }; + 9B95674D94FB68BF8896C58D /* libopenmpt.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = libopenmpt.dll; path = libopenmpt.dll; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BB2E75F2E40B1519719559F /* Load_far.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_far.cpp; path = ../../soundlib/Load_far.cpp; sourceTree = ""; }; + 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dsym.cpp; path = ../../soundlib/Load_dsym.cpp; sourceTree = ""; }; + 9BE4DE898CDC4C7BF8DFCCC9 /* libopenmpt_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_impl.hpp; path = ../../libopenmpt/libopenmpt_impl.hpp; sourceTree = ""; }; + 9C9696EDF3FC09DFA60A252D /* Echo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Echo.cpp; path = ../../soundlib/plugins/dmo/Echo.cpp; sourceTree = ""; }; + 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_fmt.cpp; path = ../../soundlib/Load_fmt.cpp; sourceTree = ""; }; + 9E091D790F2BBE6BC4F26BB9 /* IntMixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IntMixer.h; path = ../../soundlib/IntMixer.h; sourceTree = ""; }; + 9E11C9D7F49F3449CD184817 /* DSP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DSP.h; path = ../../sounddsp/DSP.h; sourceTree = ""; }; + 9E737DF712CDC2E990B14C37 /* Distortion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Distortion.h; path = ../../soundlib/plugins/dmo/Distortion.h; sourceTree = ""; }; + 9E8AC865F88BDF57BFD2D6A5 /* tests_binary.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_binary.hpp; path = ../../src/mpt/binary/tests/tests_binary.hpp; sourceTree = ""; }; + 9EB0D073130B156590EE9EB3 /* Compressor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Compressor.h; path = ../../soundlib/plugins/dmo/Compressor.h; sourceTree = ""; }; + 9F187E69B9E4ED1BBDB584A9 /* outputfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = outputfile.hpp; path = ../../src/mpt/io_file/outputfile.hpp; sourceTree = ""; }; + 9FCB791A628BD98CBFC0B75A /* dos_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dos_memory.hpp; path = ../../src/mpt/osinfo/dos_memory.hpp; sourceTree = ""; }; + A0ADCD61E4FC72D32723ABA1 /* MPEGFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MPEGFrame.h; path = ../../soundlib/MPEGFrame.h; sourceTree = ""; }; + A105879DAD903A0F287505DD /* source_location.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = source_location.hpp; path = ../../src/mpt/base/source_location.hpp; sourceTree = ""; }; + A235F524F99B6816ABA98364 /* BuildSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BuildSettings.h; path = ../../common/BuildSettings.h; sourceTree = ""; }; + A2D7595A44C0F54C3BE8079A /* SymMODEcho.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SymMODEcho.h; path = ../../soundlib/plugins/SymMODEcho.h; sourceTree = ""; }; + A32EC1731056CFE511E9BFB3 /* ModSample.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModSample.cpp; path = ../../soundlib/ModSample.cpp; sourceTree = ""; }; + A33106C935BED0BB9E977509 /* load_j2b.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = load_j2b.cpp; path = ../../soundlib/load_j2b.cpp; sourceTree = ""; }; + A34959973B963F4969DD3FD7 /* filedata.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata.hpp; path = ../../src/mpt/io_read/filedata.hpp; sourceTree = ""; }; + A527626137B52C53A08DD0A1 /* int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = int24.hpp; path = ../../src/mpt/endian/int24.hpp; sourceTree = ""; }; + A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MIDIEvents.cpp; path = ../../soundlib/MIDIEvents.cpp; sourceTree = ""; }; + A7A09A55A16256C7DB615895 /* Paula.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Paula.cpp; path = ../../soundlib/Paula.cpp; sourceTree = ""; }; + A998D521CF40CF93ED715361 /* tests_string_transcode.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_transcode.hpp; path = ../../src/mpt/string_transcode/tests/tests_string_transcode.hpp; sourceTree = ""; }; + A9BD0A251CDE97177DA3D865 /* tests_base_saturate_round.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_saturate_round.hpp; path = ../../src/mpt/base/tests/tests_base_saturate_round.hpp; sourceTree = ""; }; + AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = I3DL2Reverb.cpp; path = ../../soundlib/plugins/dmo/I3DL2Reverb.cpp; sourceTree = ""; }; + AA79D3BB9E791D2D236431FB /* tests_uuid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_uuid.hpp; path = ../../src/mpt/uuid/tests/tests_uuid.hpp; sourceTree = ""; }; + AA915D236D51BD95CA869B63 /* AudioReadTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioReadTarget.h; path = ../../soundlib/AudioReadTarget.h; sourceTree = ""; }; + AB10601718386E8919CB5E57 /* version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = version.hpp; path = ../../src/mpt/base/version.hpp; sourceTree = ""; }; + AC5DD2341D807326D3472074 /* misc_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = misc_util.h; path = ../../common/misc_util.h; sourceTree = ""; }; + AED9469B1C01550D1D9444DB /* buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = buffer.hpp; path = ../../src/mpt/string/buffer.hpp; sourceTree = ""; }; + AFFB10484288DA3AAB617E88 /* mptFileType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileType.h; path = ../../common/mptFileType.h; sourceTree = ""; }; + B05C5FEF07C1D2E1B9CFEE2F /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/string/utility.hpp; sourceTree = ""; }; + B0E5D2B80C27262ADF8170F8 /* io.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io.hpp; path = ../../src/mpt/io/io.hpp; sourceTree = ""; }; + B176D8582299794AD8602698 /* mptTime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptTime.cpp; path = ../../common/mptTime.cpp; sourceTree = ""; }; + B30D8BC554F727B74C1E3A05 /* MixerInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerInterface.h; path = ../../soundlib/MixerInterface.h; sourceTree = ""; }; + B3975CD927F1A1CBA5D52B19 /* preprocessor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = preprocessor.hpp; path = ../../src/mpt/base/preprocessor.hpp; sourceTree = ""; }; + B3A14F450EE2A2B7E23CED85 /* OPL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OPL.cpp; path = ../../soundlib/OPL.cpp; sourceTree = ""; }; + B50C144B262EB53DDBF5628B /* Reverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Reverb.cpp; path = ../../sounddsp/Reverb.cpp; sourceTree = ""; }; + B517EB3DCFE459EFD3B4F17D /* exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = exception.hpp; path = ../../src/mpt/exception/exception.hpp; sourceTree = ""; }; + B5449C6B226CAADD23FF9AAB /* ModSequence.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSequence.h; path = ../../soundlib/ModSequence.h; sourceTree = ""; }; + B547A5AF29A1EAA1A78573EF /* type_traits.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = type_traits.hpp; path = ../../src/mpt/endian/type_traits.hpp; sourceTree = ""; }; + B569F9F747F7C3E9B0D06837 /* Load_669.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_669.cpp; path = ../../soundlib/Load_669.cpp; sourceTree = ""; }; + B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixerLoops.cpp; path = ../../soundlib/MixerLoops.cpp; sourceTree = ""; }; + B99E396D4C2C035FB504A7AD /* Load_c67.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_c67.cpp; path = ../../soundlib/Load_c67.cpp; sourceTree = ""; }; + B9B7FE84CBE1DB36FFD2C4C4 /* windows.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows.hpp; path = ../../src/mpt/check/windows.hpp; sourceTree = ""; }; + BA171099817BCB8B0C339ED9 /* tests_format_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_format_message.hpp; path = ../../src/mpt/format/tests/tests_format_message.hpp; sourceTree = ""; }; + BA5BA85780E99FC9EEEBC697 /* Flanger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Flanger.h; path = ../../soundlib/plugins/dmo/Flanger.h; sourceTree = ""; }; + BA99A2F415DAF666E9354134 /* mptCPU.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptCPU.h; path = ../../common/mptCPU.h; sourceTree = ""; }; + BAA825C62BCAC6B8E1917406 /* mptRandom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptRandom.h; path = ../../common/mptRandom.h; sourceTree = ""; }; + BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Sndfile.cpp; path = ../../soundlib/Sndfile.cpp; sourceTree = ""; }; + BBEF0B95B5B0C807EFAFC9D5 /* ITTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITTools.h; path = ../../soundlib/ITTools.h; sourceTree = ""; }; + BD023BA1315C8093AF4009E1 /* simple_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_spec.hpp; path = ../../src/mpt/format/simple_spec.hpp; sourceTree = ""; }; + BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MPEGFrame.cpp; path = ../../soundlib/MPEGFrame.cpp; sourceTree = ""; }; + BFC43D151B059087EE5FDB55 /* AGC.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AGC.cpp; path = ../../sounddsp/AGC.cpp; sourceTree = ""; }; + C0B331FD5340FBEFBC19A03D /* MixerLoops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerLoops.h; path = ../../soundlib/MixerLoops.h; sourceTree = ""; }; + C10B2BDD886FE6CF1327BA1D /* tests_endian_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_integer.hpp; path = ../../src/mpt/endian/tests/tests_endian_integer.hpp; sourceTree = ""; }; + C183253A1B843C2CE2CB337A /* system_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = system_error.hpp; path = ../../src/mpt/system_error/system_error.hpp; sourceTree = ""; }; + C34D6D67860DCDD9E342ABA7 /* libopenmpt_ext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_ext.h; path = ../../libopenmpt/libopenmpt_ext.h; sourceTree = ""; }; + C3E634155673FE07BF4CA255 /* macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = macros.hpp; path = ../../src/mpt/base/macros.hpp; sourceTree = ""; }; + C3FAC67D5688906FBF6134BD /* detect.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect.hpp; path = ../../src/mpt/base/detect.hpp; sourceTree = ""; }; + C510221C396A670EB74DF05C /* mptStringBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptStringBuffer.cpp; path = ../../common/mptStringBuffer.cpp; sourceTree = ""; }; + C6F2110A1E5783FCD0659F4A /* FileReaderFwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FileReaderFwd.h; path = ../../common/FileReaderFwd.h; sourceTree = ""; }; + C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UMXTools.cpp; path = ../../soundlib/UMXTools.cpp; sourceTree = ""; }; + C875E7BBB96D55AD2570D5FB /* floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = floatingpoint.hpp; path = ../../src/mpt/endian/floatingpoint.hpp; sourceTree = ""; }; + C885A07E2286B770E9CDAEBE /* windows_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows_version.hpp; path = ../../src/mpt/osinfo/windows_version.hpp; sourceTree = ""; }; + C950084F5BDDD241C4B6768F /* Load_sfx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_sfx.cpp; path = ../../soundlib/Load_sfx.cpp; sourceTree = ""; }; + C9545B192355720BEA9C6959 /* arithmetic_shift.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = arithmetic_shift.hpp; path = ../../src/mpt/base/arithmetic_shift.hpp; sourceTree = ""; }; + C9DD180C21428AFED350A64C /* mptPathString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptPathString.h; path = ../../common/mptPathString.h; sourceTree = ""; }; + CA2995890E783AFB509F73C9 /* array.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = array.hpp; path = ../../src/mpt/base/array.hpp; sourceTree = ""; }; + CA67A8613B8A4953F150F6A1 /* S3MTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = S3MTools.h; path = ../../soundlib/S3MTools.h; sourceTree = ""; }; + CB4660EB0F95065D51BC3F2B /* pattern.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pattern.cpp; path = ../../soundlib/pattern.cpp; sourceTree = ""; }; + CB46E6335DD4B025C6AD5473 /* Load_667.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_667.cpp; path = ../../soundlib/Load_667.cpp; sourceTree = ""; }; + CB69F5BB3FC43AADBDA7C3FB /* patternContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = patternContainer.h; path = ../../soundlib/patternContainer.h; sourceTree = ""; }; + CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModInstrument.cpp; path = ../../soundlib/ModInstrument.cpp; sourceTree = ""; }; + CE0AB78B121E88BD05F00DCB /* fstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fstream.hpp; path = ../../src/mpt/io_file/fstream.hpp; sourceTree = ""; }; + CE271C83BB8EAF355888A2C3 /* filedata_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_stdstream.hpp; path = ../../src/mpt/io_read/filedata_stdstream.hpp; sourceTree = ""; }; + CE32D5B4DABD882655A253F4 /* PluginManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginManager.cpp; path = ../../soundlib/plugins/PluginManager.cpp; sourceTree = ""; }; + CE6385639C86D91523952BA3 /* split.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = split.hpp; path = ../../src/mpt/parse/split.hpp; sourceTree = ""; }; + CEC583E195537B530355A221 /* ModSequence.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModSequence.cpp; path = ../../soundlib/ModSequence.cpp; sourceTree = ""; }; + CF52BC181CB5B24A92D4B258 /* crc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = crc.hpp; path = ../../src/mpt/crc/crc.hpp; sourceTree = ""; }; + CF8AA7E9C94C645B034B6629 /* dl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dl.hpp; path = ../../src/mpt/detect/dl.hpp; sourceTree = ""; }; + D030DC83C9F298F503F19AC3 /* Sndfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Sndfile.h; path = ../../soundlib/Sndfile.h; sourceTree = ""; }; + D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DigiBoosterEcho.cpp; path = ../../soundlib/plugins/DigiBoosterEcho.cpp; sourceTree = ""; }; + D14936A73E714519400434E7 /* Load_digi.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_digi.cpp; path = ../../soundlib/Load_digi.cpp; sourceTree = ""; }; + D1D7F649CB99B2BB0598B489 /* bit.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = bit.hpp; path = ../../src/mpt/base/bit.hpp; sourceTree = ""; }; + D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatMediaFoundation.cpp; path = ../../soundlib/SampleFormatMediaFoundation.cpp; sourceTree = ""; }; + D35A7771C759C0E34C44D5B1 /* WavesReverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WavesReverb.h; path = ../../soundlib/plugins/dmo/WavesReverb.h; sourceTree = ""; }; + D37D7529660B3F1BCEE3E369 /* MIDIMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MIDIMacros.h; path = ../../soundlib/MIDIMacros.h; sourceTree = ""; }; + D432AEE7E417DB19D08B6527 /* tests_parse.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_parse.hpp; path = ../../src/mpt/parse/tests/tests_parse.hpp; sourceTree = ""; }; + D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LFOPlugin.cpp; path = ../../soundlib/plugins/LFOPlugin.cpp; sourceTree = ""; }; + D89E49F2E528FC64600DC832 /* PlugInterface.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PlugInterface.cpp; path = ../../soundlib/plugins/PlugInterface.cpp; sourceTree = ""; }; + D941724BCA38E03D363C608B /* saturate_round.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = saturate_round.hpp; path = ../../src/mpt/base/saturate_round.hpp; sourceTree = ""; }; + DA41BBEFE6CC6E6161B13A2F /* transcode.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = transcode.hpp; path = ../../src/mpt/string_transcode/transcode.hpp; sourceTree = ""; }; + DAAB5DFD47D36C6F49665C3D /* WindowedFIR.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WindowedFIR.h; path = ../../soundlib/WindowedFIR.h; sourceTree = ""; }; + DC234F403388C232E596DD80 /* versionNumber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = versionNumber.h; path = ../../common/versionNumber.h; sourceTree = ""; }; + DC3C845FF708F311FAD98A9F /* filecursor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor.hpp; path = ../../src/mpt/io_read/filecursor.hpp; sourceTree = ""; }; + DD3070EFE9BB2361649FEF2F /* default_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_string.hpp; path = ../../src/mpt/format/default_string.hpp; sourceTree = ""; }; + DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormats.cpp; path = ../../soundlib/SampleFormats.cpp; sourceTree = ""; }; + DFABF246C3F2FA7847E02886 /* sample.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = sample.hpp; path = ../../src/mpt/audio/sample.hpp; sourceTree = ""; }; + DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = tuningCollection.cpp; path = ../../soundlib/tuningCollection.cpp; sourceTree = ""; }; + E0244DAB72B2179DDB8ABBEB /* ModChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModChannel.h; path = ../../soundlib/ModChannel.h; sourceTree = ""; }; + E047D7E9F1FF17DB676D0629 /* default_formatter.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_formatter.hpp; path = ../../src/mpt/format/default_formatter.hpp; sourceTree = ""; }; + E0923A2DD491839F597C986D /* DMOPlugin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DMOPlugin.cpp; path = ../../soundlib/plugins/dmo/DMOPlugin.cpp; sourceTree = ""; }; + E0CF51E794CB6B19767DA827 /* filedata_callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_callbackstream.hpp; path = ../../src/mpt/io_read/filedata_callbackstream.hpp; sourceTree = ""; }; + E2066CCD3D47C03F10A20B0D /* DSP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DSP.cpp; path = ../../sounddsp/DSP.cpp; sourceTree = ""; }; + E276AB813DD6D033801A71C1 /* filedata_base_seekable.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_seekable.hpp; path = ../../src/mpt/io_read/filedata_base_seekable.hpp; sourceTree = ""; }; + E2B3BCB34FDBCB25516EBAF3 /* random.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = random.hpp; path = ../../src/mpt/random/random.hpp; sourceTree = ""; }; + E438935FD53001514133819F /* mod_specifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mod_specifications.h; path = ../../soundlib/mod_specifications.h; sourceTree = ""; }; + E4C0ABA9F677EB9B6BE5D9E9 /* libopenmpt_ext_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_ext_impl.hpp; path = ../../libopenmpt/libopenmpt_ext_impl.hpp; sourceTree = ""; }; + E59C6F4DDF5E2BBF195D2D8D /* Loaders.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Loaders.h; path = ../../soundlib/Loaders.h; sourceTree = ""; }; + E64FF33AA9BBB4ECE85F597A /* openmpt-ogg.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "ogg.xcodeproj"; path = ext/ogg.xcodeproj; sourceTree = SOURCE_ROOT; }; + E6905433791E1E25E1F6C273 /* SampleCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleCopy.h; path = ../../soundlib/SampleCopy.h; sourceTree = ""; }; + E7811C8A7A0EE67CE2E78ACA /* class.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = class.hpp; path = ../../src/mpt/osinfo/class.hpp; sourceTree = ""; }; + E898D5ABAF26CD1D1D28F3EB /* ModInstrument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModInstrument.h; path = ../../soundlib/ModInstrument.h; sourceTree = ""; }; + EABA2F1F4147999119C0AD5F /* AGC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AGC.h; path = ../../sounddsp/AGC.h; sourceTree = ""; }; + EC1456C17EA220B3E77AC501 /* Load_mid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mid.cpp; path = ../../soundlib/Load_mid.cpp; sourceTree = ""; }; + ED3DBD7D7FCB876FE8A42BBD /* memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = memory.hpp; path = ../../src/mpt/base/memory.hpp; sourceTree = ""; }; + EEC8D9B98156A3ABEA2F47F9 /* tuningbase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuningbase.h; path = ../../soundlib/tuningbase.h; sourceTree = ""; }; + EF78F5224ABA48941E149362 /* Dither.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Dither.h; path = ../../common/Dither.h; sourceTree = ""; }; + F06C78E982FA42DBEBD2E729 /* RowVisitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RowVisitor.h; path = ../../soundlib/RowVisitor.h; sourceTree = ""; }; + F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_psm.cpp; path = ../../soundlib/Load_psm.cpp; sourceTree = ""; }; + F18CD1F1E58C1B636A773031 /* saturate_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = saturate_cast.hpp; path = ../../src/mpt/base/saturate_cast.hpp; sourceTree = ""; }; + F19C0735EB5DC3A7255CC575 /* pattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pattern.h; path = ../../soundlib/pattern.h; sourceTree = ""; }; + F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SoundFilePlayConfig.cpp; path = ../../soundlib/SoundFilePlayConfig.cpp; sourceTree = ""; }; + F1E743CB3635E93D785D220B /* OggStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OggStream.h; path = ../../soundlib/OggStream.h; sourceTree = ""; }; + F1F533090CC1A1BB10923949 /* filereader.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filereader.hpp; path = ../../src/mpt/io_read/filereader.hpp; sourceTree = ""; }; + F244B139942E4D2B8B555F79 /* basic_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = basic_path.hpp; path = ../../src/mpt/path/basic_path.hpp; sourceTree = ""; }; + F42AAB0986B874FBEF911949 /* MIDIEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MIDIEvents.h; path = ../../soundlib/MIDIEvents.h; sourceTree = ""; }; + F4775C614BDCCF53FDEAEAA1 /* Chorus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Chorus.h; path = ../../soundlib/plugins/dmo/Chorus.h; sourceTree = ""; }; + F48DAABB97F4D86DAF2A90FB /* filecursor_traits_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_traits_memory.hpp; path = ../../src/mpt/io_read/filecursor_traits_memory.hpp; sourceTree = ""; }; + F5D2F247BC60E9B92A631087 /* libopenmpt.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt.hpp; path = ../../libopenmpt/libopenmpt.hpp; sourceTree = ""; }; + F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dsm.cpp; path = ../../soundlib/Load_dsm.cpp; sourceTree = ""; }; + F61229996734CA8B1CFB77D9 /* guid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = guid.hpp; path = ../../src/mpt/uuid/guid.hpp; sourceTree = ""; }; + F6F37E8F68161F811DDCCCCF /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/base/span.hpp; sourceTree = ""; }; + F78A378464B245F6664535C4 /* mptBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseTypes.h; path = ../../common/mptBaseTypes.h; sourceTree = ""; }; + F7B5558991D94ABB41FF2BC9 /* fileadapter.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fileadapter.hpp; path = ../../src/mpt/io_file_adapter/fileadapter.hpp; sourceTree = ""; }; + F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatFLAC.cpp; path = ../../soundlib/SampleFormatFLAC.cpp; sourceTree = ""; }; + FB5FB0E7EF5EFA59744A0F27 /* libopenmpt_ext.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_ext.hpp; path = ../../libopenmpt/libopenmpt_ext.hpp; sourceTree = ""; }; + FB635E3D352E14EFEA89647D /* filecursor_traits_filedata.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_traits_filedata.hpp; path = ../../src/mpt/io_read/filecursor_traits_filedata.hpp; sourceTree = ""; }; + FBE197BEECD905B058DC85FE /* serialization_utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = serialization_utils.h; path = ../../common/serialization_utils.h; sourceTree = ""; }; + FBF22E79CF82B5EBC2544CB9 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_posix_lfs64.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h; sourceTree = ""; }; + FC85D407DBA2EE39B7AC4A47 /* inputfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = inputfile.hpp; path = ../../src/mpt/io_file/inputfile.hpp; sourceTree = ""; }; + FED01DA32FB4159542CC4BE3 /* tuning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuning.h; path = ../../soundlib/tuning.h; sourceTree = ""; }; + FEDB3A1791690409FA41A857 /* Echo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Echo.h; path = ../../soundlib/plugins/dmo/Echo.h; sourceTree = ""; }; + FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileTemporary.cpp; path = ../../common/mptFileTemporary.cpp; sourceTree = ""; }; + FFB3088F4401AE018628E6CF /* Resampler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Resampler.h; path = ../../soundlib/Resampler.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 74A5BE3DE630D6AF9531FC7D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C4FBD3C878F7ECFA5AAA2A08 /* openmpt-mpg123.lib in Frameworks */, + 7F5CA93E3358C270150AFF7E /* openmpt-vorbis.lib in Frameworks */, + 8F84E60E36FA81C0DFBF8C4E /* openmpt-ogg.lib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0AD991E90B8C8EDB7F6E6029 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 02978A9119AA25C309C620D1 /* detect */ = { + isa = PBXGroup; + children = ( + CF8AA7E9C94C645B034B6629 /* dl.hpp */, + 4DFC0969924AAEDBD471E7A9 /* ltdl.hpp */, + 5178AA15C29B4B077861F855 /* mfc.hpp */, + 3C628FD12D59FDC3995D7E11 /* nlohmann_json.hpp */, + ); + name = detect; + sourceTree = ""; + }; + 0317FD4359A567B5321E7B83 /* tests */ = { + isa = PBXGroup; + children = ( + 9620F5BDA843ABAF8144E3FD /* tests_endian_floatingpoint.hpp */, + 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */, + C10B2BDD886FE6CF1327BA1D /* tests_endian_integer.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 06E88D9CF1D4B38E39BA7BDC /* Products */ = { + isa = PBXGroup; + children = ( + 738151100DDB3A024A139F50 /* openmpt-mpg123.lib */, + ); + name = Products; + sourceTree = ""; + }; + 1063AA8FB3AF33C1CE8000CF /* io */ = { + isa = PBXGroup; + children = ( + 793E301E72FFEC90ACFEEE5E /* base.hpp */, + B0E5D2B80C27262ADF8170F8 /* io.hpp */, + 632A109AF5B7DA8C5E907EDA /* io_span.hpp */, + 06C40A24C9846A9626B94864 /* io_stdstream.hpp */, + 949CE444733F7FB628218284 /* io_virtual_wrapper.hpp */, + 4B6DA50C44D3A67E386F034C /* tests */, + ); + name = io; + sourceTree = ""; + }; + 11F2BC8C3818EC3E9F1FE2CC /* tests */ = { + isa = PBXGroup; + children = ( + 7D6EAF1E983B1DD09C0BB55E /* tests_crc.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 1B3CA80DE95FFBBF706E4E4D /* io_file_adapter */ = { + isa = PBXGroup; + children = ( + F7B5558991D94ABB41FF2BC9 /* fileadapter.hpp */, + ); + name = io_file_adapter; + sourceTree = ""; + }; + 2AB619BD41C8B4EF31E4AFFD /* endian */ = { + isa = PBXGroup; + children = ( + C875E7BBB96D55AD2570D5FB /* floatingpoint.hpp */, + A527626137B52C53A08DD0A1 /* int24.hpp */, + 3CC72D5B942CA04D463ABB9B /* integer.hpp */, + 0317FD4359A567B5321E7B83 /* tests */, + B547A5AF29A1EAA1A78573EF /* type_traits.hpp */, + ); + name = endian; + sourceTree = ""; + }; + 30779B89F3E35D3B328701C9 /* environment */ = { + isa = PBXGroup; + children = ( + 6E84090F7E6935416ADCBF4F /* environment.hpp */, + ); + name = environment; + sourceTree = ""; + }; + 31DC889B1CC8AE8D64AE76DB /* plugins */ = { + isa = PBXGroup; + children = ( + D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */, + 45D0E0DE525B9350CD405F1E /* DigiBoosterEcho.h */, + D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */, + 6858F8CA2EE6F03C9CE9170A /* LFOPlugin.h */, + 9133E604FE5BF476FFEEE444 /* OpCodes.h */, + D89E49F2E528FC64600DC832 /* PlugInterface.cpp */, + 6058487C545791EED942A6BC /* PlugInterface.h */, + CE32D5B4DABD882655A253F4 /* PluginManager.cpp */, + 159B6F7E099AB8F08E85CDBE /* PluginManager.h */, + 09387CD815C32F4A90A7FB18 /* PluginMixBuffer.h */, + 46877D383A86C6AABF71DB78 /* PluginStructs.h */, + 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */, + A2D7595A44C0F54C3BE8079A /* SymMODEcho.h */, + 47207888320C9E7A79F266C8 /* dmo */, + ); + name = plugins; + sourceTree = ""; + }; + 3C7CE88D62A3183FC9AA0ECD /* io_file */ = { + isa = PBXGroup; + children = ( + 22594181666D12B35A3E97C1 /* fileref.hpp */, + CE0AB78B121E88BD05F00DCB /* fstream.hpp */, + FC85D407DBA2EE39B7AC4A47 /* inputfile.hpp */, + 9F187E69B9E4ED1BBDB584A9 /* outputfile.hpp */, + ); + name = io_file; + sourceTree = ""; + }; + 42C3CDB59951382771CA4BF5 /* tests */ = { + isa = PBXGroup; + children = ( + 37064A799107616B584E58B9 /* tests_random.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 47207888320C9E7A79F266C8 /* dmo */ = { + isa = PBXGroup; + children = ( + 84A787B7269123A91DB835F7 /* Chorus.cpp */, + F4775C614BDCCF53FDEAEAA1 /* Chorus.h */, + 9334A009842C0DFBF02F8E49 /* Compressor.cpp */, + 9EB0D073130B156590EE9EB3 /* Compressor.h */, + E0923A2DD491839F597C986D /* DMOPlugin.cpp */, + 04EAEC77C7AB4CE924E02AB7 /* DMOPlugin.h */, + 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */, + 73262ABB150FC6AD0C36D8FB /* DMOUtils.h */, + 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */, + 9E737DF712CDC2E990B14C37 /* Distortion.h */, + 9C9696EDF3FC09DFA60A252D /* Echo.cpp */, + FEDB3A1791690409FA41A857 /* Echo.h */, + 3286C74DF54727BF527C058D /* Flanger.cpp */, + BA5BA85780E99FC9EEEBC697 /* Flanger.h */, + 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */, + 6B9C8BDDC301FECF75101A1D /* Gargle.h */, + AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */, + 91AA522185A99B930A94B061 /* I3DL2Reverb.h */, + 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */, + 9B1917A761A70F19CFA935E7 /* ParamEq.h */, + 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */, + D35A7771C759C0E34C44D5B1 /* WavesReverb.h */, + ); + name = dmo; + sourceTree = ""; + }; + 477F53A3EA6D7A55799359E3 /* audio */ = { + isa = PBXGroup; + children = ( + DFABF246C3F2FA7847E02886 /* sample.hpp */, + 55356226EAAC215859487866 /* span.hpp */, + ); + name = audio; + sourceTree = ""; + }; + 4B6DA50C44D3A67E386F034C /* tests */ = { + isa = PBXGroup; + children = ( + 2E1DD07ED0076C70C72E7EBE /* tests_io.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 4DC01D3DA44D87AF7CC69B7D /* tests */ = { + isa = PBXGroup; + children = ( + BA171099817BCB8B0C339ED9 /* tests_format_message.hpp */, + 8EA1F2E35357495507C5F123 /* tests_format_simple.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 4ECA2D3165DCC86355F8C371 /* format */ = { + isa = PBXGroup; + children = ( + 68FC5709D624657BD7B75549 /* concat.hpp */, + 80F9D5FD1722E7EFD889443D /* default_floatingpoint.hpp */, + E047D7E9F1FF17DB676D0629 /* default_formatter.hpp */, + 7159D71DCB5AEE0F92A1E55D /* default_integer.hpp */, + DD3070EFE9BB2361649FEF2F /* default_string.hpp */, + 721CEF1FC98262117B907D5F /* helpers.hpp */, + 3A4473F97E93196BC0BA5239 /* join.hpp */, + 915D6003E8C2D2F59AD0EE43 /* message.hpp */, + 80C993CB8D54463D0839120B /* message_macros.hpp */, + 1E7AA06D8BA2AEDF8D359EAD /* simple.hpp */, + 8CA9A5C72521933951088407 /* simple_floatingpoint.hpp */, + 5E8119A76B0BCC19E5F097E7 /* simple_integer.hpp */, + BD023BA1315C8093AF4009E1 /* simple_spec.hpp */, + 4DC01D3DA44D87AF7CC69B7D /* tests */, + ); + name = format; + sourceTree = ""; + }; + 5288703955F9426BD765E679 /* path */ = { + isa = PBXGroup; + children = ( + F244B139942E4D2B8B555F79 /* basic_path.hpp */, + 178BC3E3DA4C245537810223 /* native_path.hpp */, + 50318A59BD5998CBBEEC8899 /* os_path.hpp */, + 85A36D37F9FDB22977E13B77 /* os_path_long.hpp */, + 7C2DCED7ED506FC9A3171D17 /* path.hpp */, + ); + name = path; + sourceTree = ""; + }; + 54C514A39D35F8D5E1D4CAE3 /* io_write */ = { + isa = PBXGroup; + children = ( + 01230426588877180A969266 /* buffer.hpp */, + ); + name = io_write; + sourceTree = ""; + }; + 5691D14D5A02A37FDB6F478D /* uuid */ = { + isa = PBXGroup; + children = ( + F61229996734CA8B1CFB77D9 /* guid.hpp */, + B62CF44BA1191A3DE8FEE28B /* tests */, + 40C5E675B1E8876767AF34B5 /* uuid.hpp */, + ); + name = uuid; + sourceTree = ""; + }; + 570A99913B51A1C3BF3ECFD1 /* string_transcode */ = { + isa = PBXGroup; + children = ( + 8A87EA73FEE22F657CC5B8B3 /* macros.hpp */, + ADB520ED1ED7C1DFD49E6F2D /* tests */, + DA41BBEFE6CC6E6161B13A2F /* transcode.hpp */, + ); + name = string_transcode; + sourceTree = ""; + }; + 5775D4184366DFCA959E7A58 /* src */ = { + isa = PBXGroup; + children = ( + 88A413A1D8B7A8535B35D9E1 /* mpt */, + ); + name = src; + sourceTree = ""; + }; + 59D7B3BB70EA4EED610649FB /* osinfo */ = { + isa = PBXGroup; + children = ( + E7811C8A7A0EE67CE2E78ACA /* class.hpp */, + 9FCB791A628BD98CBFC0B75A /* dos_memory.hpp */, + 0F8105B483DB4AA601BED3F4 /* dos_version.hpp */, + C885A07E2286B770E9CDAEBE /* windows_version.hpp */, + 92AB21E22B230F54570A0022 /* windows_wine_version.hpp */, + ); + name = osinfo; + sourceTree = ""; + }; + 5D4AB94D745D547F64794F8D /* string */ = { + isa = PBXGroup; + children = ( + AED9469B1C01550D1D9444DB /* buffer.hpp */, + 9602920BEC8FFC7DC509104B /* tests */, + 4E96BB31E124852349FD2971 /* types.hpp */, + B05C5FEF07C1D2E1B9CFEE2F /* utility.hpp */, + ); + name = string; + sourceTree = ""; + }; + 63D3103B06C136ED95E7167B /* check */ = { + isa = PBXGroup; + children = ( + 64377F84A84B50B69C1CD5C4 /* compiler.hpp */, + 417FE082D6F69FB44592F6C2 /* libc.hpp */, + 788395FAAA7CE0AC245C1C3A /* mfc.hpp */, + B9B7FE84CBE1DB36FFD2C4C4 /* windows.hpp */, + ); + name = check; + sourceTree = ""; + }; + 651C6428688D365AE9F9DA68 /* sounddsp */ = { + isa = PBXGroup; + children = ( + BFC43D151B059087EE5FDB55 /* AGC.cpp */, + EABA2F1F4147999119C0AD5F /* AGC.h */, + E2066CCD3D47C03F10A20B0D /* DSP.cpp */, + 9E11C9D7F49F3449CD184817 /* DSP.h */, + 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */, + 73A52C155E915207A6771A55 /* EQ.h */, + B50C144B262EB53DDBF5628B /* Reverb.cpp */, + 57E617F588CA0FE79BE24635 /* Reverb.h */, + ); + name = sounddsp; + sourceTree = ""; + }; + 7EC25859D54FC2CBADC8D699 /* tests */ = { + isa = PBXGroup; + children = ( + 9E8AC865F88BDF57BFD2D6A5 /* tests_binary.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 80C578BF97D813F187F40EFF /* Products */ = { + isa = PBXGroup; + children = ( + 5B7F44F63A21E068EF03E336 /* openmpt-ogg.lib */, + ); + name = Products; + sourceTree = ""; + }; + 83E18D7BD14483AD476383BB /* system_error */ = { + isa = PBXGroup; + children = ( + C183253A1B843C2CE2CB337A /* system_error.hpp */, + ); + name = system_error; + sourceTree = ""; + }; + 88A413A1D8B7A8535B35D9E1 /* mpt */ = { + isa = PBXGroup; + children = ( + FE13EC1B0184BE4D82F1625B /* arch */, + 477F53A3EA6D7A55799359E3 /* audio */, + ADCB9F55B13C718732A91595 /* base */, + B88D0869CF9FA39BBFBB9EA9 /* binary */, + 63D3103B06C136ED95E7167B /* check */, + A3AF43EF4801E1A15A3A2A2F /* crc */, + 02978A9119AA25C309C620D1 /* detect */, + 2AB619BD41C8B4EF31E4AFFD /* endian */, + 30779B89F3E35D3B328701C9 /* environment */, + CA56FDBDF291B66FDA2D43FD /* exception */, + 4ECA2D3165DCC86355F8C371 /* format */, + 1063AA8FB3AF33C1CE8000CF /* io */, + 3C7CE88D62A3183FC9AA0ECD /* io_file */, + 1B3CA80DE95FFBBF706E4E4D /* io_file_adapter */, + B9911C4306F412757D131283 /* io_file_read */, + C86808B95DDEC7EBCC7B1EF9 /* io_file_unique */, + FB1C5B4521428AF788498185 /* io_read */, + 54C514A39D35F8D5E1D4CAE3 /* io_write */, + 8FB69E0532A4C4B7C1CAA445 /* mutex */, + 59D7B3BB70EA4EED610649FB /* osinfo */, + CF94F547018E3FF97B6D7B87 /* out_of_memory */, + EB3711558E2538071D4B1795 /* parse */, + 5288703955F9426BD765E679 /* path */, + F76908210E7BA353FE979E61 /* random */, + 5D4AB94D745D547F64794F8D /* string */, + 570A99913B51A1C3BF3ECFD1 /* string_transcode */, + 83E18D7BD14483AD476383BB /* system_error */, + 5691D14D5A02A37FDB6F478D /* uuid */, + ); + name = mpt; + sourceTree = ""; + }; + 8BDA4A4F76C67041BEAC388F /* tests */ = { + isa = PBXGroup; + children = ( + 4D1485535F373B4538387393 /* tests_base_arithmetic_shift.hpp */, + 44E6E1C323897D35D86B8003 /* tests_base_bit.hpp */, + 6C67B7D97E1EF7CBF38CE619 /* tests_base_math.hpp */, + 32BAAF6B89D057DDB618EDAB /* tests_base_saturate_cast.hpp */, + A9BD0A251CDE97177DA3D865 /* tests_base_saturate_round.hpp */, + 82EA4C5D44A2DDCFEBBDAA9D /* tests_base_wrapping_divide.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 8FB69E0532A4C4B7C1CAA445 /* mutex */ = { + isa = PBXGroup; + children = ( + 8ABF23E958E2779BDFF0CA29 /* mutex.hpp */, + ); + name = mutex; + sourceTree = ""; + }; + 9320911A7F119CCCD149375A /* libopenmpt */ = { + isa = PBXGroup; + children = ( + 9660399A39ABC2CC547C8FDA /* common */, + C5150E7CDC27A9AECC43A4BC /* libopenmpt */, + 651C6428688D365AE9F9DA68 /* sounddsp */, + E6A8DD88EA19AFBA6B8653C8 /* soundlib */, + 5775D4184366DFCA959E7A58 /* src */, + A6C936B49B3FADE6EA134CF4 /* Products */, + 9D968EAA920D05DCE0E0A4EA /* Projects */, + ); + name = libopenmpt; + sourceTree = ""; + }; + 9602920BEC8FFC7DC509104B /* tests */ = { + isa = PBXGroup; + children = ( + 995821ED5E0D785F127C202D /* tests_string_buffer.hpp */, + 07580841CEBCC33359749681 /* tests_string_utility.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 9660399A39ABC2CC547C8FDA /* common */ = { + isa = PBXGroup; + children = ( + A235F524F99B6816ABA98364 /* BuildSettings.h */, + 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */, + 0A20B0FECCE111702A15EF3E /* ComponentManager.h */, + EF78F5224ABA48941E149362 /* Dither.h */, + 6D2350A8B171F61AF3992EE8 /* FileReader.h */, + C6F2110A1E5783FCD0659F4A /* FileReaderFwd.h */, + 830F3566F431D658A9F883A6 /* Logging.cpp */, + 6303157093E70D62A6FF43B0 /* Logging.h */, + 8F52A05ED3A145D015C87E9E /* Profiler.cpp */, + 94CA18088E8BD47AC88AD648 /* Profiler.h */, + AC5DD2341D807326D3472074 /* misc_util.h */, + 74D96CA8E5FC0D9A9BC2BAE8 /* mptAssert.h */, + 66CA3B04BE2FADF6703DC944 /* mptBaseMacros.h */, + F78A378464B245F6664535C4 /* mptBaseTypes.h */, + 12DCF57C800503EE8197F3BC /* mptBaseUtils.h */, + BA99A2F415DAF666E9354134 /* mptCPU.h */, + 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */, + 50CF7EB4C1F21FA677B8CCF4 /* mptFileIO.h */, + FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */, + 43CBFB4A068C5BBC63C1398A /* mptFileTemporary.h */, + 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */, + AFFB10484288DA3AAB617E88 /* mptFileType.h */, + 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */, + C9DD180C21428AFED350A64C /* mptPathString.h */, + 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */, + BAA825C62BCAC6B8E1917406 /* mptRandom.h */, + 4AECD572BC0F766471D623B2 /* mptString.h */, + C510221C396A670EB74DF05C /* mptStringBuffer.cpp */, + 90E45EE632CDFAD829F50D26 /* mptStringBuffer.h */, + 1A94BBC4BC7E57B6B3A56A04 /* mptStringFormat.h */, + B176D8582299794AD8602698 /* mptTime.cpp */, + 8DF141A2BED53994D1ED6FE2 /* mptTime.h */, + 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */, + FBE197BEECD905B058DC85FE /* serialization_utils.h */, + 6AF57E36C636D1A899911C76 /* stdafx.h */, + 3E2FDF24AF52801665192D64 /* version.cpp */, + 7523D3EEA607CBE0B920022E /* version.h */, + DC234F403388C232E596DD80 /* versionNumber.h */, + ); + name = common; + sourceTree = ""; + }; + 9D968EAA920D05DCE0E0A4EA /* Projects */ = { + isa = PBXGroup; + children = ( + 04155894998C17C608286ED4 /* mpg123.xcodeproj */, + 41BBEA4AD732A97C45CF008A /* vorbis.xcodeproj */, + E64FF33AA9BBB4ECE85F597A /* ogg.xcodeproj */, + ); + name = Projects; + sourceTree = ""; + }; + A3AF43EF4801E1A15A3A2A2F /* crc */ = { + isa = PBXGroup; + children = ( + CF52BC181CB5B24A92D4B258 /* crc.hpp */, + 11F2BC8C3818EC3E9F1FE2CC /* tests */, + ); + name = crc; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 9B95674D94FB68BF8896C58D /* libopenmpt.dll */, + ); + name = Products; + sourceTree = ""; + }; + ADB520ED1ED7C1DFD49E6F2D /* tests */ = { + isa = PBXGroup; + children = ( + A998D521CF40CF93ED715361 /* tests_string_transcode.hpp */, + ); + name = tests; + sourceTree = ""; + }; + ADCB9F55B13C718732A91595 /* base */ = { + isa = PBXGroup; + children = ( + 54F2D0191B80C78B8982EE59 /* algorithm.hpp */, + 15A918AF09A862218E9376EF /* aligned_array.hpp */, + 1679D9615AC87ED39CEFB7A1 /* alloc.hpp */, + C9545B192355720BEA9C6959 /* arithmetic_shift.hpp */, + CA2995890E783AFB509F73C9 /* array.hpp */, + D1D7F649CB99B2BB0598B489 /* bit.hpp */, + 1AA25C6F0B99CA61779D4AAF /* check_platform.hpp */, + 86260AE5E2AD0F576B4FC925 /* compiletime_warning.hpp */, + 021DA33D0EA855AF898D217D /* constexpr_throw.hpp */, + C3FAC67D5688906FBF6134BD /* detect.hpp */, + 1C2F81B7DEEFE2293C24BFF7 /* detect_arch.hpp */, + 321030713E9AE2E3B97FAEB1 /* detect_compiler.hpp */, + 17F58A2FDAB5EAA137EAC86F /* detect_libc.hpp */, + 755174CF6950BE41EE3BD30F /* detect_libcxx.hpp */, + 175234BFDDE02C314BE252FF /* detect_os.hpp */, + 107683B90475CD2B8960E1F9 /* detect_quirks.hpp */, + 4FB7A50743B6EE79C8A20347 /* floatingpoint.hpp */, + 787945A7E5A15419E73443E7 /* integer.hpp */, + C3E634155673FE07BF4CA255 /* macros.hpp */, + 4614D43FB73775316CFE227F /* math.hpp */, + ED3DBD7D7FCB876FE8A42BBD /* memory.hpp */, + 3AC37DA5015175176F539BE5 /* namespace.hpp */, + 209166838DB974F58F4C64C3 /* numbers.hpp */, + 046F30B171973F23732A2EF1 /* numeric.hpp */, + 5AF83E8DC8204CFFC9B33CCD /* pointer.hpp */, + B3975CD927F1A1CBA5D52B19 /* preprocessor.hpp */, + F18CD1F1E58C1B636A773031 /* saturate_cast.hpp */, + D941724BCA38E03D363C608B /* saturate_round.hpp */, + 85812219180EEC0B80E79059 /* secure.hpp */, + 212A36FD7B2B4DEF4272453D /* semantic_version.hpp */, + A105879DAD903A0F287505DD /* source_location.hpp */, + F6F37E8F68161F811DDCCCCF /* span.hpp */, + 8BDA4A4F76C67041BEAC388F /* tests */, + 5609DBF3C331EA65C4C4DA33 /* utility.hpp */, + AB10601718386E8919CB5E57 /* version.hpp */, + 2C28EA4338B39CB5B3986883 /* wrapping_divide.hpp */, + ); + name = base; + sourceTree = ""; + }; + B62CF44BA1191A3DE8FEE28B /* tests */ = { + isa = PBXGroup; + children = ( + AA79D3BB9E791D2D236431FB /* tests_uuid.hpp */, + ); + name = tests; + sourceTree = ""; + }; + B88D0869CF9FA39BBFBB9EA9 /* binary */ = { + isa = PBXGroup; + children = ( + 8856685FF57E76D1F711669F /* base64.hpp */, + 51EB7985F3D51577EAFC27C5 /* base64url.hpp */, + 2E2F32DF9F51D3D15518811F /* hex.hpp */, + 7EC25859D54FC2CBADC8D699 /* tests */, + ); + name = binary; + sourceTree = ""; + }; + B9911C4306F412757D131283 /* io_file_read */ = { + isa = PBXGroup; + children = ( + 36619CBCFDC657AE887E2AFC /* inputfile_filecursor.hpp */, + ); + name = io_file_read; + sourceTree = ""; + }; + C5150E7CDC27A9AECC43A4BC /* libopenmpt */ = { + isa = PBXGroup; + children = ( + 41DFAAC7AF07B939B09AA907 /* libopenmpt.h */, + F5D2F247BC60E9B92A631087 /* libopenmpt.hpp */, + 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */, + 43B7419134AEAF83A0B22FD1 /* libopenmpt_config.h */, + 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */, + C34D6D67860DCDD9E342ABA7 /* libopenmpt_ext.h */, + FB5FB0E7EF5EFA59744A0F27 /* libopenmpt_ext.hpp */, + 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */, + E4C0ABA9F677EB9B6BE5D9E9 /* libopenmpt_ext_impl.hpp */, + 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */, + 9BE4DE898CDC4C7BF8DFCCC9 /* libopenmpt_impl.hpp */, + 7154B71FCB55CE11929CC55F /* libopenmpt_internal.h */, + 01D708ED277F035F45AF872D /* libopenmpt_stream_callbacks_buffer.h */, + 3AADECCD91C3953FBE0C2B0D /* libopenmpt_stream_callbacks_fd.h */, + 91EC613953A4F2ABFABFBF79 /* libopenmpt_stream_callbacks_file.h */, + 3EEBB71B8158038D397E755B /* libopenmpt_stream_callbacks_file_mingw.h */, + 70644035FF1571275A9F8E75 /* libopenmpt_stream_callbacks_file_msvcrt.h */, + 8BE3D4DDCE50214F8676931D /* libopenmpt_stream_callbacks_file_posix.h */, + FBF22E79CF82B5EBC2544CB9 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */, + 0FDA8FB11C654223974A0DF1 /* libopenmpt_version.h */, + ); + name = libopenmpt; + sourceTree = ""; + }; + C86808B95DDEC7EBCC7B1EF9 /* io_file_unique */ = { + isa = PBXGroup; + children = ( + 25EAC3A1C044AC93FC7D11E1 /* unique_basename.hpp */, + 9469EF975BCEAA89E6867DD7 /* unique_tempfilename.hpp */, + ); + name = io_file_unique; + sourceTree = ""; + }; + CA56FDBDF291B66FDA2D43FD /* exception */ = { + isa = PBXGroup; + children = ( + B517EB3DCFE459EFD3B4F17D /* exception.hpp */, + 41BBBCC5DBDFB1F78C059305 /* exception_text.hpp */, + 4CDD73CDC0C5EB7FE3139A0D /* logic_error.hpp */, + 75EFCB7913D0CC2BEB4F11B9 /* runtime_error.hpp */, + ); + name = exception; + sourceTree = ""; + }; + CAFA4717B5E66D09FDCC3557 /* Products */ = { + isa = PBXGroup; + children = ( + AB169C264570851881A8EA66 /* openmpt-vorbis.lib */, + ); + name = Products; + sourceTree = ""; + }; + CF94F547018E3FF97B6D7B87 /* out_of_memory */ = { + isa = PBXGroup; + children = ( + 406A557CF3605F2E4482BBBC /* out_of_memory.hpp */, + ); + name = out_of_memory; + sourceTree = ""; + }; + E6A8DD88EA19AFBA6B8653C8 /* soundlib */ = { + isa = PBXGroup; + children = ( + 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */, + 87A62ABDE1A741AFA8EE38FD /* AudioCriticalSection.h */, + AA915D236D51BD95CA869B63 /* AudioReadTarget.h */, + 338C775D77DB1CCFBA02559D /* BitReader.h */, + 3F5591FF83A43771C5CB703F /* Container.h */, + 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */, + 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */, + 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */, + 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */, + 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */, + 45DBF5F73F9DB269799CB437 /* Dlsbank.h */, + 1054EEE754A3945996CACD27 /* Fastmix.cpp */, + 39CF376FCC5D01613535A5AF /* FloatMixer.h */, + 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */, + 2F3B0AD7F5C9024963CB2917 /* ITCompression.h */, + 778D494BBBDBEEBDFE03278B /* ITTools.cpp */, + BBEF0B95B5B0C807EFAFC9D5 /* ITTools.h */, + 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */, + 9E091D790F2BBE6BC4F26BB9 /* IntMixer.h */, + CB46E6335DD4B025C6AD5473 /* Load_667.cpp */, + B569F9F747F7C3E9B0D06837 /* Load_669.cpp */, + 37F80675CA85D067335E74B5 /* Load_amf.cpp */, + 29DC06EFBC69D0E12542752F /* Load_ams.cpp */, + B99E396D4C2C035FB504A7AD /* Load_c67.cpp */, + 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */, + D14936A73E714519400434E7 /* Load_digi.cpp */, + 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */, + F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */, + 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */, + 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */, + 9BB2E75F2E40B1519719559F /* Load_far.cpp */, + 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */, + 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */, + 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */, + 34D45985C7622377303AC7C5 /* Load_imf.cpp */, + 62235C27A6720199E8993A67 /* Load_it.cpp */, + 6A572747FCE4F13965BD9587 /* Load_itp.cpp */, + 2052C727B2E091191BB93567 /* Load_mdl.cpp */, + 8F093E392197082B8A6FAC79 /* Load_med.cpp */, + EC1456C17EA220B3E77AC501 /* Load_mid.cpp */, + 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */, + 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */, + 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */, + 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */, + 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */, + 6AE995E9FD775FDB66500429 /* Load_okt.cpp */, + 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */, + F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */, + 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */, + 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */, + C950084F5BDDD241C4B6768F /* Load_sfx.cpp */, + 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */, + 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */, + 7D070D1F43950491B1972B5F /* Load_symmod.cpp */, + 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */, + 7FD19A57125F64497B380897 /* Load_ult.cpp */, + 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */, + 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */, + 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */, + E59C6F4DDF5E2BBF195D2D8D /* Loaders.h */, + A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */, + F42AAB0986B874FBEF911949 /* MIDIEvents.h */, + 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */, + D37D7529660B3F1BCEE3E369 /* MIDIMacros.h */, + BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */, + A0ADCD61E4FC72D32723ABA1 /* MPEGFrame.h */, + 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */, + 7A6823C37429E035AE28E203 /* Message.h */, + 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */, + 74DCDADDCC424DCF7E50691D /* MixFuncTable.h */, + 2151B0037C9303754FED4E43 /* Mixer.h */, + B30D8BC554F727B74C1E3A05 /* MixerInterface.h */, + B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */, + C0B331FD5340FBEFBC19A03D /* MixerLoops.h */, + 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */, + 20B693A5E7448B175546B1E5 /* MixerSettings.h */, + 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */, + E0244DAB72B2179DDB8ABBEB /* ModChannel.h */, + CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */, + E898D5ABAF26CD1D1D28F3EB /* ModInstrument.h */, + A32EC1731056CFE511E9BFB3 /* ModSample.cpp */, + 392551FD7D73F76FBF9B303D /* ModSample.h */, + 8C8CA6B3531A9E25C11CC4F3 /* ModSampleCopy.h */, + CEC583E195537B530355A221 /* ModSequence.cpp */, + B5449C6B226CAADD23FF9AAB /* ModSequence.h */, + B3A14F450EE2A2B7E23CED85 /* OPL.cpp */, + 4756C54F9DE42FC1765D438F /* OPL.h */, + 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */, + F1E743CB3635E93D785D220B /* OggStream.h */, + A7A09A55A16256C7DB615895 /* Paula.cpp */, + 1AD54F9F7616A3114970EDDF /* Paula.h */, + FFB3088F4401AE018628E6CF /* Resampler.h */, + 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */, + F06C78E982FA42DBEBD2E729 /* RowVisitor.h */, + 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */, + CA67A8613B8A4953F150F6A1 /* S3MTools.h */, + E6905433791E1E25E1F6C273 /* SampleCopy.h */, + 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */, + F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */, + 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */, + D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */, + 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */, + 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */, + 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */, + DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */, + 78CAB4630B587E55743122A3 /* SampleIO.cpp */, + 27B40A4D98D6AB3F4E9D588D /* SampleIO.h */, + 46BE019F097E621166B33FDF /* SampleNormalize.h */, + 2323E4A5944685974A0D32E5 /* Snd_defs.h */, + 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */, + 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */, + BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */, + D030DC83C9F298F503F19AC3 /* Sndfile.h */, + 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */, + F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */, + 51E2F9635E6DABD5D95277A3 /* SoundFilePlayConfig.h */, + 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */, + 63FDD8AF94E1D0A1A7FA06EF /* Tables.h */, + 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */, + 236E8DFB1D304A6D572F4C3B /* Tagging.h */, + 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */, + 3D34478136F603F370F505C1 /* TinyFFT.h */, + C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */, + 2D02F4CF9E2595C153EC430F /* UMXTools.h */, + 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */, + 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */, + 2BF8C6379D1B672952E21477 /* WAVTools.h */, + 14715833DAFF4FA549017673 /* WindowedFIR.cpp */, + DAAB5DFD47D36C6F49665C3D /* WindowedFIR.h */, + 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */, + 2810796521D235D75BD137A5 /* XMTools.h */, + A33106C935BED0BB9E977509 /* load_j2b.cpp */, + 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */, + E438935FD53001514133819F /* mod_specifications.h */, + 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */, + 5BE26A37EE7034295748D877 /* modcommand.h */, + 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */, + 28D2F38195FB01F3978DF1C1 /* modsmp_ctrl.h */, + 7214DF31A1A6AE237CB3ED71 /* opal.h */, + CB4660EB0F95065D51BC3F2B /* pattern.cpp */, + F19C0735EB5DC3A7255CC575 /* pattern.h */, + 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */, + CB69F5BB3FC43AADBDA7C3FB /* patternContainer.h */, + 31DC889B1CC8AE8D64AE76DB /* plugins */, + 48199D39B93C3E2B6F02EB79 /* tuning.cpp */, + FED01DA32FB4159542CC4BE3 /* tuning.h */, + DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */, + EEC8D9B98156A3ABEA2F47F9 /* tuningbase.h */, + 6687823BDAE1C72D58C5507B /* tuningcollection.h */, + ); + name = soundlib; + sourceTree = ""; + }; + EB3711558E2538071D4B1795 /* parse */ = { + isa = PBXGroup; + children = ( + 5CFFC0612B231413B23166A1 /* parse.hpp */, + CE6385639C86D91523952BA3 /* split.hpp */, + FFE5A7EF48568C218CF55E2F /* tests */, + ); + name = parse; + sourceTree = ""; + }; + F76908210E7BA353FE979E61 /* random */ = { + isa = PBXGroup; + children = ( + 8DE932C12076FCB3894FA101 /* crand.hpp */, + 8876678BE2777E7DA9BE75CB /* default_engines.hpp */, + 1CE2C4318A0AD2A38B9DC271 /* device.hpp */, + 7C15603DE93D6EAFEAD05E7D /* engine.hpp */, + 49E264470CA2C4B969D7A287 /* engine_lcg.hpp */, + E2B3BCB34FDBCB25516EBAF3 /* random.hpp */, + 18A72A335CF5CFA59F1D0873 /* seed.hpp */, + 42C3CDB59951382771CA4BF5 /* tests */, + ); + name = random; + sourceTree = ""; + }; + FB1C5B4521428AF788498185 /* io_read */ = { + isa = PBXGroup; + children = ( + 00114BD59DF24C8775709215 /* callbackstream.hpp */, + DC3C845FF708F311FAD98A9F /* filecursor.hpp */, + 6F3A912F8923F36144AA076F /* filecursor_callbackstream.hpp */, + 39C1318B738BE83D28E737CB /* filecursor_filename_traits.hpp */, + 712230EFB9C16F21DCED272F /* filecursor_memory.hpp */, + 8B1AB3CB32904F7DDB555A0B /* filecursor_stdstream.hpp */, + FB635E3D352E14EFEA89647D /* filecursor_traits_filedata.hpp */, + F48DAABB97F4D86DAF2A90FB /* filecursor_traits_memory.hpp */, + A34959973B963F4969DD3FD7 /* filedata.hpp */, + 62E32DEB72C85A1D5F3BE42B /* filedata_base.hpp */, + 23EF16CF7F4F3B81C192DD0F /* filedata_base_buffered.hpp */, + E276AB813DD6D033801A71C1 /* filedata_base_seekable.hpp */, + 8ABDA3472E24D0F9455A8987 /* filedata_base_unseekable.hpp */, + E0CF51E794CB6B19767DA827 /* filedata_callbackstream.hpp */, + 079DA5A7A1C19AD951E77BE7 /* filedata_memory.hpp */, + CE271C83BB8EAF355888A2C3 /* filedata_stdstream.hpp */, + F1F533090CC1A1BB10923949 /* filereader.hpp */, + ); + name = io_read; + sourceTree = ""; + }; + FE13EC1B0184BE4D82F1625B /* arch */ = { + isa = PBXGroup; + children = ( + 09573FAA7A79E09C30408DEA /* arch.hpp */, + 1197459E05968F108A81A3DE /* feature_flags.hpp */, + 473316F00DC10E627BC33530 /* x86_amd64.hpp */, + ); + name = arch; + sourceTree = ""; + }; + FFE5A7EF48568C218CF55E2F /* tests */ = { + isa = PBXGroup; + children = ( + D432AEE7E417DB19D08B6527 /* tests_parse.hpp */, + ); + name = tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 92770993A989A4C599A59FD3 /* libopenmpt */ = { + isa = PBXNativeTarget; + buildConfigurationList = 62E1069CD46C1F0E836D44DC /* Build configuration list for PBXNativeTarget "libopenmpt" */; + buildPhases = ( + E48D3EDD5618574F05197D1D /* Resources */, + 4E3A5834BFC570A66EC69674 /* Sources */, + 74A5BE3DE630D6AF9531FC7D /* Frameworks */, + 0AD991E90B8C8EDB7F6E6029 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + F4A0CAA5DF8CF0972772B8E5 /* PBXTargetDependency */, + B8B28420A39EAA12EB847260 /* PBXTargetDependency */, + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */, + ); + name = libopenmpt; + productName = libopenmpt; + productReference = 9B95674D94FB68BF8896C58D /* libopenmpt.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "libopenmpt" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 9320911A7F119CCCD149375A /* libopenmpt */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 06E88D9CF1D4B38E39BA7BDC /* Products */; + ProjectRef = 04155894998C17C608286ED4 /* mpg123.xcodeproj */; + }, + { + ProductGroup = CAFA4717B5E66D09FDCC3557 /* Products */; + ProjectRef = 41BBEA4AD732A97C45CF008A /* vorbis.xcodeproj */; + }, + { + ProductGroup = 80C578BF97D813F187F40EFF /* Products */; + ProjectRef = E64FF33AA9BBB4ECE85F597A /* ogg.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 92770993A989A4C599A59FD3 /* libopenmpt.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 5B7F44F63A21E068EF03E336 /* openmpt-ogg.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-ogg.lib"; + remoteRef = EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 738151100DDB3A024A139F50 /* openmpt-mpg123.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-mpg123.lib"; + remoteRef = 35790BDC7DE9F00EC288C21C /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + AB169C264570851881A8EA66 /* openmpt-vorbis.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-vorbis.lib"; + remoteRef = 7BC1F4B7C432D8E908D1AAF7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + E48D3EDD5618574F05197D1D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4E3A5834BFC570A66EC69674 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B591ED4C6887F6FEB9AA538C /* ComponentManager.cpp in Sources */, + 527E833E969254708A63D97E /* Logging.cpp in Sources */, + 1CE1B0B6B52E9668E37596F6 /* Profiler.cpp in Sources */, + 1CD4D902FBF1F334D7FB4F42 /* mptFileIO.cpp in Sources */, + BB65D2D86E5BDC8ABF7E3918 /* mptFileTemporary.cpp in Sources */, + 1F7082161F13654859681856 /* mptFileType.cpp in Sources */, + DF08AE5AEEEDDA8CDB61649A /* mptPathString.cpp in Sources */, + 926864F471857F264D8EDB34 /* mptRandom.cpp in Sources */, + 8751165421750B86D19AEC94 /* mptStringBuffer.cpp in Sources */, + 30BE965074D2678268A3EC90 /* mptTime.cpp in Sources */, + EDE4FB2CD37C025E96C1116C /* serialization_utils.cpp in Sources */, + DEBC9FDC22D0710E16A1F61C /* version.cpp in Sources */, + F65565599436660B6BB4AB99 /* libopenmpt_c.cpp in Sources */, + 03096A39B5FF73EB0721D079 /* libopenmpt_cxx.cpp in Sources */, + 976568F7F2B0B929E0E29F37 /* libopenmpt_ext_impl.cpp in Sources */, + C79768571036A68933625E97 /* libopenmpt_impl.cpp in Sources */, + B5220D6D8345611F0A53B3AD /* AGC.cpp in Sources */, + 3EF604A50D1958579427AAE5 /* DSP.cpp in Sources */, + 50BD34A3E633F3D554D04AE3 /* EQ.cpp in Sources */, + C0082C03041BFD35F7ED8243 /* Reverb.cpp in Sources */, + A9C7C28B051312BDF344F8CB /* AudioCriticalSection.cpp in Sources */, + 6600F8E10024EE13B04ACF21 /* ContainerMMCMP.cpp in Sources */, + B17E84D14F5F858326DDCB11 /* ContainerPP20.cpp in Sources */, + 46A543E1568A701342FDFA21 /* ContainerUMX.cpp in Sources */, + 31268193410BADC52D7F37D3 /* ContainerXPK.cpp in Sources */, + 1452C745AC9FACF7DAE6AD85 /* Dlsbank.cpp in Sources */, + 3C92F25FD4DFD8110326D89F /* Fastmix.cpp in Sources */, + 32D83065D0B93117A83776A5 /* ITCompression.cpp in Sources */, + E6583D037EA522B5ACEC2343 /* ITTools.cpp in Sources */, + 4FD75379AB22A3AB995489B9 /* InstrumentExtensions.cpp in Sources */, + 5EE7936B3E04AD9D1A0E09AB /* Load_667.cpp in Sources */, + 4E13C16F2D30DBA1093A37AF /* Load_669.cpp in Sources */, + A7B576CD86D290FF62DBED0D /* Load_amf.cpp in Sources */, + BA54A1E79971BC19757B1827 /* Load_ams.cpp in Sources */, + 44F9DD452416F77700205385 /* Load_c67.cpp in Sources */, + 7B65168B5A8230BD368B8CCB /* Load_dbm.cpp in Sources */, + 8479AC1F9F461AD1A316B25F /* Load_digi.cpp in Sources */, + C81D1553A73A2F8583438B93 /* Load_dmf.cpp in Sources */, + 8B4D81ED6A6A9C1F4673F82D /* Load_dsm.cpp in Sources */, + D2EFC1DFEDBC3091F18CC81F /* Load_dsym.cpp in Sources */, + F5A6792FD4C39361B0CCEF6F /* Load_dtm.cpp in Sources */, + D1EA5157B1076B898D10C797 /* Load_far.cpp in Sources */, + BD4216739C5F30A578688CB3 /* Load_fmt.cpp in Sources */, + 707EA3954F9BBDC72BA519D5 /* Load_gdm.cpp in Sources */, + 8676CA3F6593E471419D407F /* Load_gt2.cpp in Sources */, + 537472DD32918D0F0E9AE91D /* Load_imf.cpp in Sources */, + 7FDA539F18273951466E39DF /* Load_it.cpp in Sources */, + E7C01BBFC6DD35F1A2E691FF /* Load_itp.cpp in Sources */, + 39B7C99F18D4E3D1F4DE3FDF /* Load_mdl.cpp in Sources */, + E76008D1C67D2303A2867F11 /* Load_med.cpp in Sources */, + 90C3E5D96FE1000B4BEA5C19 /* Load_mid.cpp in Sources */, + 2B1F4A030A3C6435E645C043 /* Load_mo3.cpp in Sources */, + 0ED9B165EDF6CB97CA0027A5 /* Load_mod.cpp in Sources */, + C746074BA663217D826C7D8B /* Load_mt2.cpp in Sources */, + 56DD54C135FA6EF31203CB01 /* Load_mtm.cpp in Sources */, + 63B0011DD79878CFF9E6275D /* Load_mus_km.cpp in Sources */, + 49C7038128E41DB304ED79C1 /* Load_okt.cpp in Sources */, + 247D3937039A5369DFA3AF77 /* Load_plm.cpp in Sources */, + 0CEBFC05EC091637C8127245 /* Load_psm.cpp in Sources */, + 7744F34756620D79326B6987 /* Load_ptm.cpp in Sources */, + 9715CA0B7632E43D523C404B /* Load_s3m.cpp in Sources */, + EA420947C95F2379A5687F87 /* Load_sfx.cpp in Sources */, + 97AC91CD76C9ABFF52D3080D /* Load_stm.cpp in Sources */, + FE6ED6D3DD8BF105B9954D13 /* Load_stp.cpp in Sources */, + CF116C1742F9E3C965479257 /* Load_symmod.cpp in Sources */, + 4174F40120920E33FC9B6A41 /* Load_uax.cpp in Sources */, + F4EF37CFD40C5201B015AE0F /* Load_ult.cpp in Sources */, + BD3885019C559F33785EFB41 /* Load_wav.cpp in Sources */, + 00BB926F99087821C74F78AF /* Load_xm.cpp in Sources */, + F57A8B7BD497A5ADB0A101BB /* Load_xmf.cpp in Sources */, + CCEFFE57CC92E18906E79497 /* MIDIEvents.cpp in Sources */, + 80EEA677809189A9BAE63CB7 /* MIDIMacros.cpp in Sources */, + 393D72CF5409E18157DA790F /* MPEGFrame.cpp in Sources */, + 168C3C51AED92203DD202291 /* Message.cpp in Sources */, + 7A5E5DAB8A4389DD76B713EB /* MixFuncTable.cpp in Sources */, + 84A9E60B844CC93DBEA17C4B /* MixerLoops.cpp in Sources */, + DC9752537A78530551F69893 /* MixerSettings.cpp in Sources */, + 30C4FED93067E20B6ABC9519 /* ModChannel.cpp in Sources */, + F0D031F98EB132AB662F7839 /* ModInstrument.cpp in Sources */, + 9F1029ABB9DC985DBDAD2FEB /* ModSample.cpp in Sources */, + D86AE3F94C535BAB6EA10A39 /* ModSequence.cpp in Sources */, + ABC5779D79E8CB4F00F71DDD /* OPL.cpp in Sources */, + FD083C9917D4AB4B1BA542D9 /* OggStream.cpp in Sources */, + 33DB2DAD46050A5F79F5F3ED /* Paula.cpp in Sources */, + 119C6E37113F51694B940477 /* RowVisitor.cpp in Sources */, + D443016FB3601BA18F6977AF /* S3MTools.cpp in Sources */, + 77A73F692A9D491B7BBFA5A9 /* SampleFormatBRR.cpp in Sources */, + 49F242A9929180DBB5BD38E9 /* SampleFormatFLAC.cpp in Sources */, + 3F8606FDF27C10AF439E6D3D /* SampleFormatMP3.cpp in Sources */, + 7DDE7A6B76A93A1D011DA0AB /* SampleFormatMediaFoundation.cpp in Sources */, + D309698B1BA8A7BD3ED45FCB /* SampleFormatOpus.cpp in Sources */, + FD572F63B04D3915016F95A3 /* SampleFormatSFZ.cpp in Sources */, + 0D8FA4E7F326AC19B66BBB27 /* SampleFormatVorbis.cpp in Sources */, + E79434E3857535955CF37B23 /* SampleFormats.cpp in Sources */, + 18C62C9BF7E346CDD3ECA2DB /* SampleIO.cpp in Sources */, + D83D74BB708A5A6D9ED15AFB /* Snd_flt.cpp in Sources */, + BE9B2A6B02AEFB9DF68080AB /* Snd_fx.cpp in Sources */, + 281FA911C06C8EC3EEB38F51 /* Sndfile.cpp in Sources */, + B5D9190DF9ECEA3FEDBE6F4D /* Sndmix.cpp in Sources */, + A9D47C71514A1823FA0F22B1 /* SoundFilePlayConfig.cpp in Sources */, + BBC2281DFFD5F94FF3A77E5D /* Tables.cpp in Sources */, + 14522B09AC9F10BBDAE61149 /* Tagging.cpp in Sources */, + E9363E2F818323E1AFCA246F /* TinyFFT.cpp in Sources */, + C55C8AFDA479A52F8083013D /* UMXTools.cpp in Sources */, + 31B9FE03CF9AFEB5A7194443 /* UpgradeModule.cpp in Sources */, + 8D04F5E56C221017482B6C25 /* WAVTools.cpp in Sources */, + A5DAFA6B19C3721D3C1120AB /* WindowedFIR.cpp in Sources */, + A0E13DD3392E238567752413 /* XMTools.cpp in Sources */, + 574F1261366C2C93127588A1 /* load_j2b.cpp in Sources */, + AB7FFC4D9117037F545C128D /* mod_specifications.cpp in Sources */, + DEB582A5DE5865D718AD18E5 /* modcommand.cpp in Sources */, + CB31B3AF3F1A2B616167D9EF /* modsmp_ctrl.cpp in Sources */, + 32925EA3CADF4455F92644E3 /* pattern.cpp in Sources */, + BC15882904B4C65B27E07E69 /* patternContainer.cpp in Sources */, + 689E270C1013C2BEB8D8CD4C /* DigiBoosterEcho.cpp in Sources */, + A896F1F84677F2AA1DF63838 /* LFOPlugin.cpp in Sources */, + 9F2D020A8C9494BC298E884A /* PlugInterface.cpp in Sources */, + 370352EC246AE59EC164D92C /* PluginManager.cpp in Sources */, + F59363E88FB7591A3FDD3A28 /* SymMODEcho.cpp in Sources */, + CEDA1F2FDEBF4B61CB32D56F /* Chorus.cpp in Sources */, + CC12FBA114B239D337DDF1E1 /* Compressor.cpp in Sources */, + 00CD0D05B3C316B704E57345 /* DMOPlugin.cpp in Sources */, + BCC110A956E505DB070AE6E9 /* DMOUtils.cpp in Sources */, + 0BABF0E5544B2F177776E725 /* Distortion.cpp in Sources */, + 97B1A0C5975483F7D1A93705 /* Echo.cpp in Sources */, + 9FC1BA253DA2BAD715210065 /* Flanger.cpp in Sources */, + 1E48E6EB2E2E131D1AA19D2B /* Gargle.cpp in Sources */, + 40F236CF2E59C981CB53BD0F /* I3DL2Reverb.cpp in Sources */, + 69AC6475078D6527DF0BAAB5 /* ParamEq.cpp in Sources */, + 1553F71F02BB89D19FB57D5F /* WavesReverb.cpp in Sources */, + 6A44FDD1AE58CF03A22A5411 /* tuning.cpp in Sources */, + CF000469179F429B3ACAFAA9 /* tuningCollection.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-ogg.lib"; + targetProxy = 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */; + }; + B8B28420A39EAA12EB847260 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-vorbis.lib"; + targetProxy = CDFC6750166D4B825B0C1D90 /* PBXContainerItemProxy */; + }; + F4A0CAA5DF8CF0972772B8E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-mpg123.lib"; + targetProxy = 87B37E75D02462A714C334B5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1499E0DC457DD8CE58960F1C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../bin/release/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = libopenmpt; + }; + name = Release; + }; + 185F176389EA2FD538EB55A3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + LIBOPENMPT_BUILD, + MPT_WITH_MPG123, + MPT_WITH_OGG, + MPT_WITH_VORBIS, + MPT_WITH_VORBISFILE, + MPT_WITH_ZLIB, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "-lz", + ); + SYMROOT = "../../bin/release/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../include/mpg123/ports/Xcode, + ../../include/mpg123/src/libmpg123, + ../../include/ogg/include, + ../../include/vorbis/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../.., + ../../src, + ../../common, + ../../soundlib, + "\"$(IntDir)/svn_version\"", + ); + }; + name = Release; + }; + 3383DEE9622A32DBBB6B8D29 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + LIBOPENMPT_BUILD, + MPT_WITH_MPG123, + MPT_WITH_OGG, + MPT_WITH_VORBIS, + MPT_WITH_VORBISFILE, + MPT_WITH_ZLIB, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "-lz", + ); + SYMROOT = "../../bin/debug/xcode4-ios/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../include/mpg123/ports/Xcode, + ../../include/mpg123/src/libmpg123, + ../../include/ogg/include, + ../../include/vorbis/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../.., + ../../src, + ../../common, + ../../soundlib, + "\"$(IntDir)/svn_version\"", + ); + }; + name = Debug; + }; + 9C47E562F78938D4CAE383A2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../bin/debug/xcode4-ios/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = libopenmpt; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "libopenmpt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3383DEE9622A32DBBB6B8D29 /* Debug */, + 185F176389EA2FD538EB55A3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 62E1069CD46C1F0E836D44DC /* Build configuration list for PBXNativeTarget "libopenmpt.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9C47E562F78938D4CAE383A2 /* Debug */, + 1499E0DC457DD8CE58960F1C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcworkspace/contents.xcworkspacedata b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..88cd67a91 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-ios/libopenmpt.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e8c574682 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/mpg123.xcodeproj/project.pbxproj @@ -0,0 +1,341 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 022CF042734F913429163E82 /* layer3.c in Sources */ = {isa = PBXBuildFile; fileRef = BAACDA4AE2E792FCCA83208A /* layer3.c */; }; + 022FC83459953B260BA35674 /* synth_real.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */; }; + 0DDEA7A4A06C7196094515E4 /* optimize.c in Sources */ = {isa = PBXBuildFile; fileRef = 1B61528CDECD143E1D70B8CC /* optimize.c */; }; + 142B46E0854DE7D23B149520 /* layer2.c in Sources */ = {isa = PBXBuildFile; fileRef = 9796B208BFD16ABAA76CF848 /* layer2.c */; }; + 21B328E68EDB3758906E2726 /* equalizer.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */; }; + 242DF798687C9D0AAAA3D5D8 /* tabinit.c in Sources */ = {isa = PBXBuildFile; fileRef = 6B2790408CF33D72C9A86680 /* tabinit.c */; }; + 26299D7E974C3E704D12EBBE /* layer1.c in Sources */ = {isa = PBXBuildFile; fileRef = 748089C69CBB42788456D006 /* layer1.c */; }; + 2CE230149E04D10653CB7E54 /* format.c in Sources */ = {isa = PBXBuildFile; fileRef = AD3049FCD56B02AEBD06903C /* format.c */; }; + 2F06D05D7C69C68FF288C69D /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = A7ABBCE59297E2D7DA7DAB25 /* compat.c */; }; + 5BC0EB1CC8E8F98ECA7BE95C /* synth_s32.c in Sources */ = {isa = PBXBuildFile; fileRef = 739C6384C0FF59B6371E59C4 /* synth_s32.c */; }; + 64A7B16E5E696DE098686FAE /* synth.c in Sources */ = {isa = PBXBuildFile; fileRef = 907B4FB6D8EC33E81D8B05F6 /* synth.c */; }; + 6C03B21AB052578CF279905A /* feature.c in Sources */ = {isa = PBXBuildFile; fileRef = A60D55A2C7D902D4048E2BE2 /* feature.c */; }; + 82DB3C387C9CF8AAB69BFA78 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = 440E80E08C7F6512D11E3720 /* parse.c */; }; + 8ADD039E1D6ACD90864371DE /* icy2utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = C3752BE686E0ED98C5849226 /* icy2utf8.c */; }; + 9CA288B296644524D06346F2 /* index.c in Sources */ = {isa = PBXBuildFile; fileRef = 754AC0BABDBBA4EC025A76FA /* index.c */; }; + BCB343AA29DB521C2B6E41EA /* stringbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 0BDCDC32593FD264CF5ED272 /* stringbuf.c */; }; + C2065F0E06550480487C3D4E /* readers.c in Sources */ = {isa = PBXBuildFile; fileRef = 489101566A5CAE88A711D796 /* readers.c */; }; + C39C716430C47FD632576FA4 /* libmpg123.c in Sources */ = {isa = PBXBuildFile; fileRef = 54E0A14CA243977E1862978C /* libmpg123.c */; }; + C3D66B021F17BE74F2720942 /* id3.c in Sources */ = {isa = PBXBuildFile; fileRef = F56A100A0C7CAB3CFC98A64A /* id3.c */; }; + D1E3070CCBA4C37E05A3C54C /* dct64.c in Sources */ = {isa = PBXBuildFile; fileRef = F4F6A4743D6788A682065AB4 /* dct64.c */; }; + D618207A2D7D936CDF8BAEBA /* synth_8bit.c in Sources */ = {isa = PBXBuildFile; fileRef = A1E03F02D3D989B44DB8C542 /* synth_8bit.c */; }; + E236244C3D7777BE10D1C28C /* icy.c in Sources */ = {isa = PBXBuildFile; fileRef = E598BBB4FCAB56E6ECC751F4 /* icy.c */; }; + EAB0691E1B9461102EAC975E /* ntom.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B10DD6681370D18E83E03A6 /* ntom.c */; }; + EE6448D8E826054A22250718 /* frame.c in Sources */ = {isa = PBXBuildFile; fileRef = 78DBF380C14CD7B205EBA9C0 /* frame.c */; }; + F155B58DD59CBDBF5989EBCD /* compat_str.c in Sources */ = {isa = PBXBuildFile; fileRef = CDD5DB15FEB9D30711D20955 /* compat_str.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0BDCDC32593FD264CF5ED272 /* stringbuf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = stringbuf.c; path = ../../../include/mpg123/src/libmpg123/stringbuf.c; sourceTree = ""; }; + 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = equalizer.c; path = ../../../include/mpg123/src/libmpg123/equalizer.c; sourceTree = ""; }; + 1B61528CDECD143E1D70B8CC /* optimize.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = optimize.c; path = ../../../include/mpg123/src/libmpg123/optimize.c; sourceTree = ""; }; + 440E80E08C7F6512D11E3720 /* parse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = parse.c; path = ../../../include/mpg123/src/libmpg123/parse.c; sourceTree = ""; }; + 489101566A5CAE88A711D796 /* readers.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = readers.c; path = ../../../include/mpg123/src/libmpg123/readers.c; sourceTree = ""; }; + 54E0A14CA243977E1862978C /* libmpg123.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = libmpg123.c; path = ../../../include/mpg123/src/libmpg123/libmpg123.c; sourceTree = ""; }; + 5B10DD6681370D18E83E03A6 /* ntom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = ntom.c; path = ../../../include/mpg123/src/libmpg123/ntom.c; sourceTree = ""; }; + 6B2790408CF33D72C9A86680 /* tabinit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = tabinit.c; path = ../../../include/mpg123/src/libmpg123/tabinit.c; sourceTree = ""; }; + 739C6384C0FF59B6371E59C4 /* synth_s32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_s32.c; path = ../../../include/mpg123/src/libmpg123/synth_s32.c; sourceTree = ""; }; + 748089C69CBB42788456D006 /* layer1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer1.c; path = ../../../include/mpg123/src/libmpg123/layer1.c; sourceTree = ""; }; + 754AC0BABDBBA4EC025A76FA /* index.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = index.c; path = ../../../include/mpg123/src/libmpg123/index.c; sourceTree = ""; }; + 78DBF380C14CD7B205EBA9C0 /* frame.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = frame.c; path = ../../../include/mpg123/src/libmpg123/frame.c; sourceTree = ""; }; + 907B4FB6D8EC33E81D8B05F6 /* synth.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth.c; path = ../../../include/mpg123/src/libmpg123/synth.c; sourceTree = ""; }; + 9796B208BFD16ABAA76CF848 /* layer2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer2.c; path = ../../../include/mpg123/src/libmpg123/layer2.c; sourceTree = ""; }; + A1E03F02D3D989B44DB8C542 /* synth_8bit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_8bit.c; path = ../../../include/mpg123/src/libmpg123/synth_8bit.c; sourceTree = ""; }; + A60D55A2C7D902D4048E2BE2 /* feature.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = feature.c; path = ../../../include/mpg123/src/libmpg123/feature.c; sourceTree = ""; }; + A7ABBCE59297E2D7DA7DAB25 /* compat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = compat.c; path = ../../../include/mpg123/src/compat/compat.c; sourceTree = ""; }; + AD3049FCD56B02AEBD06903C /* format.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = format.c; path = ../../../include/mpg123/src/libmpg123/format.c; sourceTree = ""; }; + BAACDA4AE2E792FCCA83208A /* layer3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = layer3.c; path = ../../../include/mpg123/src/libmpg123/layer3.c; sourceTree = ""; }; + C3752BE686E0ED98C5849226 /* icy2utf8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = icy2utf8.c; path = ../../../include/mpg123/src/libmpg123/icy2utf8.c; sourceTree = ""; }; + C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synth_real.c; path = ../../../include/mpg123/src/libmpg123/synth_real.c; sourceTree = ""; }; + C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-mpg123.dll"; path = "openmpt-mpg123.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + CDD5DB15FEB9D30711D20955 /* compat_str.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = compat_str.c; path = ../../../include/mpg123/src/compat/compat_str.c; sourceTree = ""; }; + E598BBB4FCAB56E6ECC751F4 /* icy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = icy.c; path = ../../../include/mpg123/src/libmpg123/icy.c; sourceTree = ""; }; + F4F6A4743D6788A682065AB4 /* dct64.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dct64.c; path = ../../../include/mpg123/src/libmpg123/dct64.c; sourceTree = ""; }; + F56A100A0C7CAB3CFC98A64A /* id3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = id3.c; path = ../../../include/mpg123/src/libmpg123/id3.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + A9087E6DA26E7FDF9609DCAD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E2ED1E19CDD9440B15BF0C59 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 0F03317AECAE342CC052B7BA /* mpg123 */ = { + isa = PBXGroup; + children = ( + 3E657050E1B0F982FC81C690 /* compat */, + 2C61E28ACF50093C5E75E8CA /* libmpg123 */, + A6C936B49B3FADE6EA134CF4 /* Products */, + ); + name = mpg123; + sourceTree = ""; + }; + 2C61E28ACF50093C5E75E8CA /* libmpg123 */ = { + isa = PBXGroup; + children = ( + F4F6A4743D6788A682065AB4 /* dct64.c */, + 0F54AFAE5CB7A5E0D2D6A5EE /* equalizer.c */, + A60D55A2C7D902D4048E2BE2 /* feature.c */, + AD3049FCD56B02AEBD06903C /* format.c */, + 78DBF380C14CD7B205EBA9C0 /* frame.c */, + E598BBB4FCAB56E6ECC751F4 /* icy.c */, + C3752BE686E0ED98C5849226 /* icy2utf8.c */, + F56A100A0C7CAB3CFC98A64A /* id3.c */, + 754AC0BABDBBA4EC025A76FA /* index.c */, + 748089C69CBB42788456D006 /* layer1.c */, + 9796B208BFD16ABAA76CF848 /* layer2.c */, + BAACDA4AE2E792FCCA83208A /* layer3.c */, + 54E0A14CA243977E1862978C /* libmpg123.c */, + 5B10DD6681370D18E83E03A6 /* ntom.c */, + 1B61528CDECD143E1D70B8CC /* optimize.c */, + 440E80E08C7F6512D11E3720 /* parse.c */, + 489101566A5CAE88A711D796 /* readers.c */, + 0BDCDC32593FD264CF5ED272 /* stringbuf.c */, + 907B4FB6D8EC33E81D8B05F6 /* synth.c */, + A1E03F02D3D989B44DB8C542 /* synth_8bit.c */, + C3CD341CF5C67ECE6FA5BA5C /* synth_real.c */, + 739C6384C0FF59B6371E59C4 /* synth_s32.c */, + 6B2790408CF33D72C9A86680 /* tabinit.c */, + ); + name = libmpg123; + sourceTree = ""; + }; + 3E657050E1B0F982FC81C690 /* compat */ = { + isa = PBXGroup; + children = ( + A7ABBCE59297E2D7DA7DAB25 /* compat.c */, + CDD5DB15FEB9D30711D20955 /* compat_str.c */, + ); + name = compat; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6CFC1BC3B56CFFF5FA0BD203 /* mpg123 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9743C6CC90A9C83E8445250C /* Build configuration list for PBXNativeTarget "mpg123" */; + buildPhases = ( + 18EFFF0D1256007F05F15D4D /* Resources */, + 829D18647C0319D66F9E76A4 /* Sources */, + A9087E6DA26E7FDF9609DCAD /* Frameworks */, + E2ED1E19CDD9440B15BF0C59 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mpg123; + productName = mpg123; + productReference = C6BCBF7D1D4A29EFF5C33DBD /* openmpt-mpg123.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "mpg123" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 0F03317AECAE342CC052B7BA /* mpg123 */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6CFC1BC3B56CFFF5FA0BD203 /* openmpt-mpg123.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 18EFFF0D1256007F05F15D4D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 829D18647C0319D66F9E76A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F06D05D7C69C68FF288C69D /* compat.c in Sources */, + F155B58DD59CBDBF5989EBCD /* compat_str.c in Sources */, + D1E3070CCBA4C37E05A3C54C /* dct64.c in Sources */, + 21B328E68EDB3758906E2726 /* equalizer.c in Sources */, + 6C03B21AB052578CF279905A /* feature.c in Sources */, + 2CE230149E04D10653CB7E54 /* format.c in Sources */, + EE6448D8E826054A22250718 /* frame.c in Sources */, + E236244C3D7777BE10D1C28C /* icy.c in Sources */, + 8ADD039E1D6ACD90864371DE /* icy2utf8.c in Sources */, + C3D66B021F17BE74F2720942 /* id3.c in Sources */, + 9CA288B296644524D06346F2 /* index.c in Sources */, + 26299D7E974C3E704D12EBBE /* layer1.c in Sources */, + 142B46E0854DE7D23B149520 /* layer2.c in Sources */, + 022CF042734F913429163E82 /* layer3.c in Sources */, + C39C716430C47FD632576FA4 /* libmpg123.c in Sources */, + EAB0691E1B9461102EAC975E /* ntom.c in Sources */, + 0DDEA7A4A06C7196094515E4 /* optimize.c in Sources */, + 82DB3C387C9CF8AAB69BFA78 /* parse.c in Sources */, + C2065F0E06550480487C3D4E /* readers.c in Sources */, + BCB343AA29DB521C2B6E41EA /* stringbuf.c in Sources */, + 64A7B16E5E696DE098686FAE /* synth.c in Sources */, + D618207A2D7D936CDF8BAEBA /* synth_8bit.c in Sources */, + 022FC83459953B260BA35674 /* synth_real.c in Sources */, + 5BC0EB1CC8E8F98ECA7BE95C /* synth_s32.c in Sources */, + 242DF798687C9D0AAAA3D5D8 /* tabinit.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 4C50EB499ED7163B711B7989 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + OPT_GENERIC, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/mpg123; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-macosx/all"; + USER_HEADER_SEARCH_PATHS = ( + ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/src/libmpg123, + ../../../include/mpg123/src/compat, + ../../../include/mpg123/src, + ); + }; + name = Debug; + }; + 7C31350CED53D5FEA31A834C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-mpg123"; + }; + name = Release; + }; + 98A0BBC3A55D6B351A47DA03 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + OPT_GENERIC, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/mpg123; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-macosx/all"; + USER_HEADER_SEARCH_PATHS = ( + ../../../include/mpg123/ports/Xcode, + ../../../include/mpg123/src/libmpg123, + ../../../include/mpg123/src/compat, + ../../../include/mpg123/src, + ); + }; + name = Release; + }; + 9C9C6D92965E2A04D05D2BD2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-mpg123"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "mpg123" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4C50EB499ED7163B711B7989 /* Debug */, + 98A0BBC3A55D6B351A47DA03 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 9743C6CC90A9C83E8445250C /* Build configuration list for PBXNativeTarget "openmpt-mpg123.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9C9C6D92965E2A04D05D2BD2 /* Debug */, + 7C31350CED53D5FEA31A834C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/ogg.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/ogg.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a8229ad33 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/ogg.xcodeproj/project.pbxproj @@ -0,0 +1,255 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 9C9F8407CD837BF9E09BB247 /* bitwise.c in Sources */ = {isa = PBXBuildFile; fileRef = 1891292F3EB758E1A5BE4F6F /* bitwise.c */; }; + FF0BAB212FEFA3134307D961 /* framing.c in Sources */ = {isa = PBXBuildFile; fileRef = B766F1A9DD8D215B449417E9 /* framing.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1891292F3EB758E1A5BE4F6F /* bitwise.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bitwise.c; path = ../../../include/ogg/src/bitwise.c; sourceTree = ""; }; + 1E47F32D446E22DFAB75196D /* ogg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ogg.h; path = ../../../include/ogg/include/ogg/ogg.h; sourceTree = ""; }; + 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-ogg.dll"; path = "openmpt-ogg.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + 93F6FCDFE159F3115778F31F /* os_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = os_types.h; path = ../../../include/ogg/include/ogg/os_types.h; sourceTree = ""; }; + B766F1A9DD8D215B449417E9 /* framing.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = framing.c; path = ../../../include/ogg/src/framing.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 95F8A3D038E6CA82C80CAA10 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + CC7C283CE38EC36ED3AABE7C /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 5775D4184366DFCA959E7A58 /* src */ = { + isa = PBXGroup; + children = ( + 1891292F3EB758E1A5BE4F6F /* bitwise.c */, + B766F1A9DD8D215B449417E9 /* framing.c */, + ); + name = src; + sourceTree = ""; + }; + 5E8C725002DF100215175890 /* include */ = { + isa = PBXGroup; + children = ( + BE79831562CC20C775046955 /* ogg */, + ); + name = include; + sourceTree = ""; + }; + A078B4BDABA964AF054BE2FD /* ogg */ = { + isa = PBXGroup; + children = ( + 5E8C725002DF100215175890 /* include */, + 5775D4184366DFCA959E7A58 /* src */, + A6C936B49B3FADE6EA134CF4 /* Products */, + ); + name = ogg; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */, + ); + name = Products; + sourceTree = ""; + }; + BE79831562CC20C775046955 /* ogg */ = { + isa = PBXGroup; + children = ( + 1E47F32D446E22DFAB75196D /* ogg.h */, + 93F6FCDFE159F3115778F31F /* os_types.h */, + ); + name = ogg; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 886C6A4681D26BB8756DC886 /* ogg */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8433EC2F272212E1B647F26F /* Build configuration list for PBXNativeTarget "ogg" */; + buildPhases = ( + 05E02470A8CE4B2237F42AB0 /* Resources */, + 6F8D3DC7127B6479A1A14407 /* Sources */, + 95F8A3D038E6CA82C80CAA10 /* Frameworks */, + CC7C283CE38EC36ED3AABE7C /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ogg; + productName = ogg; + productReference = 5036DE60765D0E12DD6404A0 /* openmpt-ogg.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ogg" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = A078B4BDABA964AF054BE2FD /* ogg */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 886C6A4681D26BB8756DC886 /* openmpt-ogg.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 05E02470A8CE4B2237F42AB0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6F8D3DC7127B6479A1A14407 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9C9F8407CD837BF9E09BB247 /* bitwise.c in Sources */, + FF0BAB212FEFA3134307D961 /* framing.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 8F6FCF26DF8363D862019566 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/ogg; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + }; + name = Release; + }; + C49D8BAF120081E1881F81EF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-ogg"; + }; + name = Release; + }; + C86DC9EC74D08A1E3359002C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/ogg; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + }; + name = Debug; + }; + DFACBF75A3188127E1BC25B5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-ogg"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "ogg" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C86DC9EC74D08A1E3359002C /* Debug */, + 8F6FCF26DF8363D862019566 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 8433EC2F272212E1B647F26F /* Build configuration list for PBXNativeTarget "openmpt-ogg.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DFACBF75A3188127E1BC25B5 /* Debug */, + C49D8BAF120081E1881F81EF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/vorbis.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/vorbis.xcodeproj/project.pbxproj new file mode 100644 index 000000000..bc51b3234 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/ext/vorbis.xcodeproj/project.pbxproj @@ -0,0 +1,531 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 16716A7E46033970211078BE /* block.c in Sources */ = {isa = PBXBuildFile; fileRef = 777077261A5E9DD8A9847D66 /* block.c */; }; + 16B25260019E7852498440A0 /* psy.c in Sources */ = {isa = PBXBuildFile; fileRef = EDFFC5E89252639AA48AAC28 /* psy.c */; }; + 3EA9B7E0953722526DB03620 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = E03CFA68E3ADCC9A651A70A8 /* info.c */; }; + 412482943AE63F0674E540D4 /* codebook.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A6247DC72D32C0EB771FE1C /* codebook.c */; }; + 42BABA9A3C7C770C767B78DA /* registry.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E246821A532AB45EF1FCC2 /* registry.c */; }; + 55E0C63CC703672E7CCA147C /* synthesis.c in Sources */ = {isa = PBXBuildFile; fileRef = 3A6CA00462A758B64A42E644 /* synthesis.c */; }; + 571301CEB254554085AEA00E /* floor1.c in Sources */ = {isa = PBXBuildFile; fileRef = 501CFA76672F95A8574B90B6 /* floor1.c */; }; + 63BC07FCBEFD5B6E9257A63C /* lookup.c in Sources */ = {isa = PBXBuildFile; fileRef = 35F064C44D02FFF63D1EFB04 /* lookup.c */; }; + 650BD9CE95EFD1C0A908080E /* smallft.c in Sources */ = {isa = PBXBuildFile; fileRef = CEB55B76F4DB8B285BE281B6 /* smallft.c */; }; + 665EF2C06020AF329A1FB100 /* mapping0.c in Sources */ = {isa = PBXBuildFile; fileRef = 379713488007F77AC4A6C988 /* mapping0.c */; }; + 66F0DF98BD7E4A0A95F75DD8 /* mdct.c in Sources */ = {isa = PBXBuildFile; fileRef = C67232A0C9E304D24B4FA8E0 /* mdct.c */; }; + 7C34482667206E18AF063666 /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 7091344E14E3D200271C1A8E /* lpc.c */; }; + A4B9FD2CFFFB509ED3559B6C /* floor0.c in Sources */ = {isa = PBXBuildFile; fileRef = 3AED1EF451FFBA26421BB534 /* floor0.c */; }; + A7912A52EBDFCFC42E070892 /* vorbisfile.c in Sources */ = {isa = PBXBuildFile; fileRef = C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */; }; + B1D3BC04AB957876E5947A44 /* envelope.c in Sources */ = {isa = PBXBuildFile; fileRef = 14D8424C5D49267EA1E7F88C /* envelope.c */; }; + BC748D10B6364982F0354B50 /* analysis.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */; }; + BDB5A0B818F6F42AEC513EF8 /* window.c in Sources */ = {isa = PBXBuildFile; fileRef = 72232FC08935CAF27951C600 /* window.c */; }; + D5E5E506C0D20AF808B7D346 /* lsp.c in Sources */ = {isa = PBXBuildFile; fileRef = 6F30132E1382B0E025BAF96E /* lsp.c */; }; + D85CD4BE497F75B0FF4622FE /* vorbisenc.c in Sources */ = {isa = PBXBuildFile; fileRef = 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */; }; + DBA06C398F9C856B714EC279 /* openmpt-ogg.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = E03059217A8A4213B6C2A761 /* openmpt-ogg.lib */; }; + E344DF0C2793847E69BABD4C /* sharedbook.c in Sources */ = {isa = PBXBuildFile; fileRef = 72897ED494552C06D10A5514 /* sharedbook.c */; }; + E77EFABE1862F2B02B7B28FE /* bitrate.c in Sources */ = {isa = PBXBuildFile; fileRef = 0944F5662F6B251896721BA6 /* bitrate.c */; }; + FC4D923C52DAFCAE2B54107C /* res0.c in Sources */ = {isa = PBXBuildFile; fileRef = 16DFB5041A5087369BBD2B44 /* res0.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 886C6A4681D26BB8756DC886; + remoteInfo = "openmpt-ogg.dll"; + }; + EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5036DE60765D0E12DD6404A0; + remoteInfo = "openmpt-ogg.dll"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = "openmpt-vorbis.dll"; path = "openmpt-vorbis.dll"; sourceTree = BUILT_PRODUCTS_DIR; }; + 07BE8ECA1ED129FC0EED250A /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = window.h; path = ../../../include/vorbis/lib/window.h; sourceTree = ""; }; + 0944F5662F6B251896721BA6 /* bitrate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bitrate.c; path = ../../../include/vorbis/lib/bitrate.c; sourceTree = ""; }; + 0C6D4B2032937AD2999A7160 /* smallft.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = smallft.h; path = ../../../include/vorbis/lib/smallft.h; sourceTree = ""; }; + 0D82D8FD2F4E862F6C03AF3D /* psych_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_8.h; path = ../../../include/vorbis/lib/modes/psych_8.h; sourceTree = ""; }; + 13C8DC265C39C058A0D89266 /* codebook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codebook.h; path = ../../../include/vorbis/lib/codebook.h; sourceTree = ""; }; + 14D8424C5D49267EA1E7F88C /* envelope.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = envelope.c; path = ../../../include/vorbis/lib/envelope.c; sourceTree = ""; }; + 15F93858BA4BD60ACC841E98 /* lsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lsp.h; path = ../../../include/vorbis/lib/lsp.h; sourceTree = ""; }; + 16DFB5041A5087369BBD2B44 /* res0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = res0.c; path = ../../../include/vorbis/lib/res0.c; sourceTree = ""; }; + 16F680C77237D43945921F07 /* codec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codec.h; path = ../../../include/vorbis/include/vorbis/codec.h; sourceTree = ""; }; + 175A5978BBACF72ACDE53FB8 /* lpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lpc.h; path = ../../../include/vorbis/lib/lpc.h; sourceTree = ""; }; + 1F836091517CAB43CB5BE6D1 /* residue_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44.h; path = ../../../include/vorbis/lib/modes/residue_44.h; sourceTree = ""; }; + 2740402E4D666FE0B46D666E /* masking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = masking.h; path = ../../../include/vorbis/lib/masking.h; sourceTree = ""; }; + 285CE11ECBA86A50E679375E /* os.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = os.h; path = ../../../include/vorbis/lib/os.h; sourceTree = ""; }; + 2A6247DC72D32C0EB771FE1C /* codebook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = codebook.c; path = ../../../include/vorbis/lib/codebook.c; sourceTree = ""; }; + 2AAE7645EE1A37F72CBDDC85 /* setup_11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_11.h; path = ../../../include/vorbis/lib/modes/setup_11.h; sourceTree = ""; }; + 35CF7AFDF93B3CAF37DEE13D /* psych_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_44.h; path = ../../../include/vorbis/lib/modes/psych_44.h; sourceTree = ""; }; + 35F064C44D02FFF63D1EFB04 /* lookup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lookup.c; path = ../../../include/vorbis/lib/lookup.c; sourceTree = ""; }; + 374A6BCA5F85247C4720B20A /* highlevel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = highlevel.h; path = ../../../include/vorbis/lib/highlevel.h; sourceTree = ""; }; + 379713488007F77AC4A6C988 /* mapping0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mapping0.c; path = ../../../include/vorbis/lib/mapping0.c; sourceTree = ""; }; + 386FE2DA60AA9B8C4846291A /* openmpt-ogg.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "ogg.xcodeproj"; path = ogg.xcodeproj; sourceTree = SOURCE_ROOT; }; + 3A6CA00462A758B64A42E644 /* synthesis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = synthesis.c; path = ../../../include/vorbis/lib/synthesis.c; sourceTree = ""; }; + 3AED1EF451FFBA26421BB534 /* floor0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = floor0.c; path = ../../../include/vorbis/lib/floor0.c; sourceTree = ""; }; + 3B10AC6A3E817E9CBFEE22AA /* mdct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mdct.h; path = ../../../include/vorbis/lib/mdct.h; sourceTree = ""; }; + 3BA7A5A17FF64B13C21D83E1 /* vorbisenc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisenc.h; path = ../../../include/vorbis/include/vorbis/vorbisenc.h; sourceTree = ""; }; + 450CC03BDA837F6D491FD67B /* residue_44u.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44u.h; path = ../../../include/vorbis/lib/modes/residue_44u.h; sourceTree = ""; }; + 46FCE5106D2314C2D42A0B50 /* bitrate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bitrate.h; path = ../../../include/vorbis/lib/bitrate.h; sourceTree = ""; }; + 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = analysis.c; path = ../../../include/vorbis/lib/analysis.c; sourceTree = ""; }; + 501CFA76672F95A8574B90B6 /* floor1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = floor1.c; path = ../../../include/vorbis/lib/floor1.c; sourceTree = ""; }; + 5BED095DF163C88F60001F9D /* setup_44p51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44p51.h; path = ../../../include/vorbis/lib/modes/setup_44p51.h; sourceTree = ""; }; + 63614891852CF5C3C1E21ED1 /* setup_X.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_X.h; path = ../../../include/vorbis/lib/modes/setup_X.h; sourceTree = ""; }; + 6B3067A02E9C29526D3FCDE0 /* lookup_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lookup_data.h; path = ../../../include/vorbis/lib/lookup_data.h; sourceTree = ""; }; + 6B6795D0827A310272962C10 /* scales.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scales.h; path = ../../../include/vorbis/lib/scales.h; sourceTree = ""; }; + 6CCD7211303933C36EDCD851 /* setup_44.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44.h; path = ../../../include/vorbis/lib/modes/setup_44.h; sourceTree = ""; }; + 6E91170FA08A61C11A699D4F /* residue_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_16.h; path = ../../../include/vorbis/lib/modes/residue_16.h; sourceTree = ""; }; + 6F30132E1382B0E025BAF96E /* lsp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lsp.c; path = ../../../include/vorbis/lib/lsp.c; sourceTree = ""; }; + 7091344E14E3D200271C1A8E /* lpc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lpc.c; path = ../../../include/vorbis/lib/lpc.c; sourceTree = ""; }; + 72232FC08935CAF27951C600 /* window.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = window.c; path = ../../../include/vorbis/lib/window.c; sourceTree = ""; }; + 72897ED494552C06D10A5514 /* sharedbook.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sharedbook.c; path = ../../../include/vorbis/lib/sharedbook.c; sourceTree = ""; }; + 746BBDBB37D77F6D767B23FB /* psych_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_16.h; path = ../../../include/vorbis/lib/modes/psych_16.h; sourceTree = ""; }; + 777077261A5E9DD8A9847D66 /* block.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = block.c; path = ../../../include/vorbis/lib/block.c; sourceTree = ""; }; + 7EC1E432F2AA5BE414F80A72 /* res_books_stereo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_stereo.h; path = ../../../include/vorbis/lib/books/coupled/res_books_stereo.h; sourceTree = ""; }; + 90EE3C51B2B9E983EF6F1291 /* setup_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_8.h; path = ../../../include/vorbis/lib/modes/setup_8.h; sourceTree = ""; }; + 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = vorbisenc.c; path = ../../../include/vorbis/lib/vorbisenc.c; sourceTree = ""; }; + 94C8EB12391B88C44B53D152 /* psy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psy.h; path = ../../../include/vorbis/lib/psy.h; sourceTree = ""; }; + 960E1F895979E13B981D85C9 /* setup_22.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_22.h; path = ../../../include/vorbis/lib/modes/setup_22.h; sourceTree = ""; }; + AB69B4CF6ED57681AD791B0F /* setup_16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_16.h; path = ../../../include/vorbis/lib/modes/setup_16.h; sourceTree = ""; }; + B9289C7B068B92AD7CAA92BB /* setup_44u.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_44u.h; path = ../../../include/vorbis/lib/modes/setup_44u.h; sourceTree = ""; }; + B980BE8E4EF77DC0BD93D4CE /* codec_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = codec_internal.h; path = ../../../include/vorbis/lib/codec_internal.h; sourceTree = ""; }; + BB48DACC03B9BEFE4858910C /* registry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = registry.h; path = ../../../include/vorbis/lib/registry.h; sourceTree = ""; }; + C38A75AF76807F61C7A2DBEF /* res_books_uncoupled.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_uncoupled.h; path = ../../../include/vorbis/lib/books/uncoupled/res_books_uncoupled.h; sourceTree = ""; }; + C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = vorbisfile.c; path = ../../../include/vorbis/lib/vorbisfile.c; sourceTree = ""; }; + C67232A0C9E304D24B4FA8E0 /* mdct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdct.c; path = ../../../include/vorbis/lib/mdct.c; sourceTree = ""; }; + C97DEB5A61CAD10C9011D19A /* res_books_51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = res_books_51.h; path = ../../../include/vorbis/lib/books/coupled/res_books_51.h; sourceTree = ""; }; + CB8BC3CEE29E5F00D2BA5A0E /* lookup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = lookup.h; path = ../../../include/vorbis/lib/lookup.h; sourceTree = ""; }; + CEB55B76F4DB8B285BE281B6 /* smallft.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = smallft.c; path = ../../../include/vorbis/lib/smallft.c; sourceTree = ""; }; + D1E246821A532AB45EF1FCC2 /* registry.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = registry.c; path = ../../../include/vorbis/lib/registry.c; sourceTree = ""; }; + D90D21756B9AEB67D4738FB5 /* vorbisfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisfile.h; path = ../../../include/vorbis/include/vorbis/vorbisfile.h; sourceTree = ""; }; + DAF247F2DE631A245FCFBE32 /* misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = misc.h; path = ../../../include/vorbis/lib/misc.h; sourceTree = ""; }; + DBC5215DC00C298F43F9579D /* residue_44p51.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_44p51.h; path = ../../../include/vorbis/lib/modes/residue_44p51.h; sourceTree = ""; }; + E03CFA68E3ADCC9A651A70A8 /* info.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = info.c; path = ../../../include/vorbis/lib/info.c; sourceTree = ""; }; + E7AEBC4BAB1A7DFDE9BE228B /* setup_32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = setup_32.h; path = ../../../include/vorbis/lib/modes/setup_32.h; sourceTree = ""; }; + EABBD3D0332CB80277CB8A10 /* backends.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = backends.h; path = ../../../include/vorbis/lib/backends.h; sourceTree = ""; }; + EDFFC5E89252639AA48AAC28 /* psy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = psy.c; path = ../../../include/vorbis/lib/psy.c; sourceTree = ""; }; + EE56303600800CE83470F676 /* floor_books.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = floor_books.h; path = ../../../include/vorbis/lib/books/floor/floor_books.h; sourceTree = ""; }; + F1CF92D13F328903B5518911 /* residue_8.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = residue_8.h; path = ../../../include/vorbis/lib/modes/residue_8.h; sourceTree = ""; }; + F3B07F31B71C40E3F5BFE571 /* psych_11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = psych_11.h; path = ../../../include/vorbis/lib/modes/psych_11.h; sourceTree = ""; }; + FB9FDEF54902D527BF21D535 /* floor_all.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = floor_all.h; path = ../../../include/vorbis/lib/modes/floor_all.h; sourceTree = ""; }; + FE3ED69646AFBAC88B4E8CD6 /* envelope.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = envelope.h; path = ../../../include/vorbis/lib/envelope.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7C0E12287574139A690F7068 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DBA06C398F9C856B714EC279 /* openmpt-ogg.lib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DA68C947892B286C0787AD4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 26717C15041C7EC7D7C10255 /* vorbis */ = { + isa = PBXGroup; + children = ( + 5E8C725002DF100215175890 /* include */, + 8D815E5679726A08CBAA0496 /* lib */, + A6C936B49B3FADE6EA134CF4 /* Products */, + 9D968EAA920D05DCE0E0A4EA /* Projects */, + ); + name = vorbis; + sourceTree = ""; + }; + 5A1F78C5713213F7614E0F05 /* vorbis */ = { + isa = PBXGroup; + children = ( + 16F680C77237D43945921F07 /* codec.h */, + 3BA7A5A17FF64B13C21D83E1 /* vorbisenc.h */, + D90D21756B9AEB67D4738FB5 /* vorbisfile.h */, + ); + name = vorbis; + sourceTree = ""; + }; + 5E8C725002DF100215175890 /* include */ = { + isa = PBXGroup; + children = ( + 5A1F78C5713213F7614E0F05 /* vorbis */, + ); + name = include; + sourceTree = ""; + }; + 77671A33BFD7FE650476D073 /* coupled */ = { + isa = PBXGroup; + children = ( + C97DEB5A61CAD10C9011D19A /* res_books_51.h */, + 7EC1E432F2AA5BE414F80A72 /* res_books_stereo.h */, + ); + name = coupled; + sourceTree = ""; + }; + 80C578BF97D813F187F40EFF /* Products */ = { + isa = PBXGroup; + children = ( + E03059217A8A4213B6C2A761 /* openmpt-ogg.lib */, + ); + name = Products; + sourceTree = ""; + }; + 8D815E5679726A08CBAA0496 /* lib */ = { + isa = PBXGroup; + children = ( + 4AAD1098931DF4CAD7BCC6D8 /* analysis.c */, + EABBD3D0332CB80277CB8A10 /* backends.h */, + 0944F5662F6B251896721BA6 /* bitrate.c */, + 46FCE5106D2314C2D42A0B50 /* bitrate.h */, + 777077261A5E9DD8A9847D66 /* block.c */, + EE14CC2A926769DCA49FB26A /* books */, + 2A6247DC72D32C0EB771FE1C /* codebook.c */, + 13C8DC265C39C058A0D89266 /* codebook.h */, + B980BE8E4EF77DC0BD93D4CE /* codec_internal.h */, + 14D8424C5D49267EA1E7F88C /* envelope.c */, + FE3ED69646AFBAC88B4E8CD6 /* envelope.h */, + 3AED1EF451FFBA26421BB534 /* floor0.c */, + 501CFA76672F95A8574B90B6 /* floor1.c */, + 374A6BCA5F85247C4720B20A /* highlevel.h */, + E03CFA68E3ADCC9A651A70A8 /* info.c */, + 35F064C44D02FFF63D1EFB04 /* lookup.c */, + CB8BC3CEE29E5F00D2BA5A0E /* lookup.h */, + 6B3067A02E9C29526D3FCDE0 /* lookup_data.h */, + 7091344E14E3D200271C1A8E /* lpc.c */, + 175A5978BBACF72ACDE53FB8 /* lpc.h */, + 6F30132E1382B0E025BAF96E /* lsp.c */, + 15F93858BA4BD60ACC841E98 /* lsp.h */, + 379713488007F77AC4A6C988 /* mapping0.c */, + 2740402E4D666FE0B46D666E /* masking.h */, + C67232A0C9E304D24B4FA8E0 /* mdct.c */, + 3B10AC6A3E817E9CBFEE22AA /* mdct.h */, + DAF247F2DE631A245FCFBE32 /* misc.h */, + 9547E85E399A86104BD2CE9E /* modes */, + 285CE11ECBA86A50E679375E /* os.h */, + EDFFC5E89252639AA48AAC28 /* psy.c */, + 94C8EB12391B88C44B53D152 /* psy.h */, + D1E246821A532AB45EF1FCC2 /* registry.c */, + BB48DACC03B9BEFE4858910C /* registry.h */, + 16DFB5041A5087369BBD2B44 /* res0.c */, + 6B6795D0827A310272962C10 /* scales.h */, + 72897ED494552C06D10A5514 /* sharedbook.c */, + CEB55B76F4DB8B285BE281B6 /* smallft.c */, + 0C6D4B2032937AD2999A7160 /* smallft.h */, + 3A6CA00462A758B64A42E644 /* synthesis.c */, + 92BA4166BAF4FA18A29087A6 /* vorbisenc.c */, + C39AD0BAE5667DEC221BA6FA /* vorbisfile.c */, + 72232FC08935CAF27951C600 /* window.c */, + 07BE8ECA1ED129FC0EED250A /* window.h */, + ); + name = lib; + sourceTree = ""; + }; + 9547E85E399A86104BD2CE9E /* modes */ = { + isa = PBXGroup; + children = ( + FB9FDEF54902D527BF21D535 /* floor_all.h */, + F3B07F31B71C40E3F5BFE571 /* psych_11.h */, + 746BBDBB37D77F6D767B23FB /* psych_16.h */, + 35CF7AFDF93B3CAF37DEE13D /* psych_44.h */, + 0D82D8FD2F4E862F6C03AF3D /* psych_8.h */, + 6E91170FA08A61C11A699D4F /* residue_16.h */, + 1F836091517CAB43CB5BE6D1 /* residue_44.h */, + DBC5215DC00C298F43F9579D /* residue_44p51.h */, + 450CC03BDA837F6D491FD67B /* residue_44u.h */, + F1CF92D13F328903B5518911 /* residue_8.h */, + 2AAE7645EE1A37F72CBDDC85 /* setup_11.h */, + AB69B4CF6ED57681AD791B0F /* setup_16.h */, + 960E1F895979E13B981D85C9 /* setup_22.h */, + E7AEBC4BAB1A7DFDE9BE228B /* setup_32.h */, + 6CCD7211303933C36EDCD851 /* setup_44.h */, + 5BED095DF163C88F60001F9D /* setup_44p51.h */, + B9289C7B068B92AD7CAA92BB /* setup_44u.h */, + 90EE3C51B2B9E983EF6F1291 /* setup_8.h */, + 63614891852CF5C3C1E21ED1 /* setup_X.h */, + ); + name = modes; + sourceTree = ""; + }; + 9D968EAA920D05DCE0E0A4EA /* Projects */ = { + isa = PBXGroup; + children = ( + 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */, + ); + name = Projects; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */, + ); + name = Products; + sourceTree = ""; + }; + E272DBD9043E890B40F3B219 /* uncoupled */ = { + isa = PBXGroup; + children = ( + C38A75AF76807F61C7A2DBEF /* res_books_uncoupled.h */, + ); + name = uncoupled; + sourceTree = ""; + }; + EE14CC2A926769DCA49FB26A /* books */ = { + isa = PBXGroup; + children = ( + 77671A33BFD7FE650476D073 /* coupled */, + FCE62BDF13F8C7110414C21F /* floor */, + E272DBD9043E890B40F3B219 /* uncoupled */, + ); + name = books; + sourceTree = ""; + }; + FCE62BDF13F8C7110414C21F /* floor */ = { + isa = PBXGroup; + children = ( + EE56303600800CE83470F676 /* floor_books.h */, + ); + name = floor; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6EE3599EB7543DD0FBF30FDE /* vorbis */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6A495A8763AF5BF9574AB8C7 /* Build configuration list for PBXNativeTarget "vorbis" */; + buildPhases = ( + EBF592C8E55B943AD8F6F108 /* Resources */, + 55A2AC1F4F08AD9142A40A5F /* Sources */, + 7C0E12287574139A690F7068 /* Frameworks */, + 8DA68C947892B286C0787AD4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */, + ); + name = vorbis; + productName = vorbis; + productReference = 058BB8B85C19232A349236F8 /* openmpt-vorbis.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "vorbis" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 26717C15041C7EC7D7C10255 /* vorbis */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 80C578BF97D813F187F40EFF /* Products */; + ProjectRef = 386FE2DA60AA9B8C4846291A /* ogg.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 6EE3599EB7543DD0FBF30FDE /* openmpt-vorbis.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + E03059217A8A4213B6C2A761 /* openmpt-ogg.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-ogg.lib"; + remoteRef = EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + EBF592C8E55B943AD8F6F108 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 55A2AC1F4F08AD9142A40A5F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BC748D10B6364982F0354B50 /* analysis.c in Sources */, + E77EFABE1862F2B02B7B28FE /* bitrate.c in Sources */, + 16716A7E46033970211078BE /* block.c in Sources */, + 412482943AE63F0674E540D4 /* codebook.c in Sources */, + B1D3BC04AB957876E5947A44 /* envelope.c in Sources */, + A4B9FD2CFFFB509ED3559B6C /* floor0.c in Sources */, + 571301CEB254554085AEA00E /* floor1.c in Sources */, + 3EA9B7E0953722526DB03620 /* info.c in Sources */, + 63BC07FCBEFD5B6E9257A63C /* lookup.c in Sources */, + 7C34482667206E18AF063666 /* lpc.c in Sources */, + D5E5E506C0D20AF808B7D346 /* lsp.c in Sources */, + 665EF2C06020AF329A1FB100 /* mapping0.c in Sources */, + 66F0DF98BD7E4A0A95F75DD8 /* mdct.c in Sources */, + 16B25260019E7852498440A0 /* psy.c in Sources */, + 42BABA9A3C7C770C767B78DA /* registry.c in Sources */, + FC4D923C52DAFCAE2B54107C /* res0.c in Sources */, + E344DF0C2793847E69BABD4C /* sharedbook.c in Sources */, + 650BD9CE95EFD1C0A908080E /* smallft.c in Sources */, + 55E0C63CC703672E7CCA147C /* synthesis.c in Sources */, + D85CD4BE497F75B0FF4622FE /* vorbisenc.c in Sources */, + A7912A52EBDFCFC42E070892 /* vorbisfile.c in Sources */, + BDB5A0B818F6F42AEC513EF8 /* window.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-ogg.lib"; + targetProxy = 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1FD85444725E7F3644A2E284 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug/vorbis; + ONLY_ACTIVE_ARCH = YES; + SYMROOT = "../../../bin/debug/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../../../include/vorbis/include, + ../../../include/vorbis/lib, + ); + }; + name = Debug; + }; + 6BA64F7E7862FEF0ED4D6DBE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release/vorbis; + ONLY_ACTIVE_ARCH = NO; + SYMROOT = "../../../bin/release/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../../include/ogg/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../../../include/vorbis/include, + ../../../include/vorbis/lib, + ); + }; + name = Release; + }; + AC0271CDA5C42E3FDFC3300D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/debug/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-vorbis"; + }; + name = Debug; + }; + FD2934076E4BD4F924128247 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../../bin/release/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "openmpt-vorbis"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "vorbis" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1FD85444725E7F3644A2E284 /* Debug */, + 6BA64F7E7862FEF0ED4D6DBE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 6A495A8763AF5BF9574AB8C7 /* Build configuration list for PBXNativeTarget "openmpt-vorbis.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AC0271CDA5C42E3FDFC3300D /* Debug */, + FD2934076E4BD4F924128247 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcodeproj/project.pbxproj new file mode 100644 index 000000000..efd80cdf0 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcodeproj/project.pbxproj @@ -0,0 +1,1851 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00BB926F99087821C74F78AF /* Load_xm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */; }; + 00CD0D05B3C316B704E57345 /* DMOPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E0923A2DD491839F597C986D /* DMOPlugin.cpp */; }; + 03096A39B5FF73EB0721D079 /* libopenmpt_cxx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */; }; + 0BABF0E5544B2F177776E725 /* Distortion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */; }; + 0CEBFC05EC091637C8127245 /* Load_psm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */; }; + 0D8FA4E7F326AC19B66BBB27 /* SampleFormatVorbis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */; }; + 0ED9B165EDF6CB97CA0027A5 /* Load_mod.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */; }; + 119C6E37113F51694B940477 /* RowVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */; }; + 14522B09AC9F10BBDAE61149 /* Tagging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */; }; + 1452C745AC9FACF7DAE6AD85 /* Dlsbank.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */; }; + 1553F71F02BB89D19FB57D5F /* WavesReverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */; }; + 168C3C51AED92203DD202291 /* Message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */; }; + 18C62C9BF7E346CDD3ECA2DB /* SampleIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78CAB4630B587E55743122A3 /* SampleIO.cpp */; }; + 1CD4D902FBF1F334D7FB4F42 /* mptFileIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */; }; + 1CE1B0B6B52E9668E37596F6 /* Profiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F52A05ED3A145D015C87E9E /* Profiler.cpp */; }; + 1E48E6EB2E2E131D1AA19D2B /* Gargle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */; }; + 1F7082161F13654859681856 /* mptFileType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */; }; + 247D3937039A5369DFA3AF77 /* Load_plm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */; }; + 281FA911C06C8EC3EEB38F51 /* Sndfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */; }; + 2837D1CEECED2840A15BD00E /* openmpt-ogg.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DFCA7B6A69BE5E8C9C79DF6 /* openmpt-ogg.lib */; }; + 2B1F4A030A3C6435E645C043 /* Load_mo3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */; }; + 30BE965074D2678268A3EC90 /* mptTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B176D8582299794AD8602698 /* mptTime.cpp */; }; + 30C4FED93067E20B6ABC9519 /* ModChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */; }; + 31268193410BADC52D7F37D3 /* ContainerXPK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */; }; + 31B9FE03CF9AFEB5A7194443 /* UpgradeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */; }; + 32925EA3CADF4455F92644E3 /* pattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB4660EB0F95065D51BC3F2B /* pattern.cpp */; }; + 32D83065D0B93117A83776A5 /* ITCompression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */; }; + 33DB2DAD46050A5F79F5F3ED /* Paula.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A09A55A16256C7DB615895 /* Paula.cpp */; }; + 370352EC246AE59EC164D92C /* PluginManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE32D5B4DABD882655A253F4 /* PluginManager.cpp */; }; + 393D72CF5409E18157DA790F /* MPEGFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */; }; + 39B7C99F18D4E3D1F4DE3FDF /* Load_mdl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2052C727B2E091191BB93567 /* Load_mdl.cpp */; }; + 3C92F25FD4DFD8110326D89F /* Fastmix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1054EEE754A3945996CACD27 /* Fastmix.cpp */; }; + 3EF604A50D1958579427AAE5 /* DSP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E2066CCD3D47C03F10A20B0D /* DSP.cpp */; }; + 3F8606FDF27C10AF439E6D3D /* SampleFormatMP3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */; }; + 40F236CF2E59C981CB53BD0F /* I3DL2Reverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */; }; + 4174F40120920E33FC9B6A41 /* Load_uax.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */; }; + 44F9DD452416F77700205385 /* Load_c67.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B99E396D4C2C035FB504A7AD /* Load_c67.cpp */; }; + 46A543E1568A701342FDFA21 /* ContainerUMX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */; }; + 49C7038128E41DB304ED79C1 /* Load_okt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AE995E9FD775FDB66500429 /* Load_okt.cpp */; }; + 49F242A9929180DBB5BD38E9 /* SampleFormatFLAC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */; }; + 4E13C16F2D30DBA1093A37AF /* Load_669.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B569F9F747F7C3E9B0D06837 /* Load_669.cpp */; }; + 4FD75379AB22A3AB995489B9 /* InstrumentExtensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */; }; + 50BD34A3E633F3D554D04AE3 /* EQ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */; }; + 527E833E969254708A63D97E /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 830F3566F431D658A9F883A6 /* Logging.cpp */; }; + 537472DD32918D0F0E9AE91D /* Load_imf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34D45985C7622377303AC7C5 /* Load_imf.cpp */; }; + 56DD54C135FA6EF31203CB01 /* Load_mtm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */; }; + 574F1261366C2C93127588A1 /* load_j2b.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A33106C935BED0BB9E977509 /* load_j2b.cpp */; }; + 5EE7936B3E04AD9D1A0E09AB /* Load_667.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB46E6335DD4B025C6AD5473 /* Load_667.cpp */; }; + 63B0011DD79878CFF9E6275D /* Load_mus_km.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */; }; + 6600F8E10024EE13B04ACF21 /* ContainerMMCMP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */; }; + 689E270C1013C2BEB8D8CD4C /* DigiBoosterEcho.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */; }; + 69AC6475078D6527DF0BAAB5 /* ParamEq.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */; }; + 6A44FDD1AE58CF03A22A5411 /* tuning.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 48199D39B93C3E2B6F02EB79 /* tuning.cpp */; }; + 707EA3954F9BBDC72BA519D5 /* Load_gdm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */; }; + 70AEC26880FBA65A7EE870A8 /* openmpt-mpg123.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = 91C69AB0393C3662E20140F0 /* openmpt-mpg123.lib */; }; + 7744F34756620D79326B6987 /* Load_ptm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */; }; + 77A73F692A9D491B7BBFA5A9 /* SampleFormatBRR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */; }; + 7A5E5DAB8A4389DD76B713EB /* MixFuncTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */; }; + 7B65168B5A8230BD368B8CCB /* Load_dbm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */; }; + 7DDE7A6B76A93A1D011DA0AB /* SampleFormatMediaFoundation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */; }; + 7FDA539F18273951466E39DF /* Load_it.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62235C27A6720199E8993A67 /* Load_it.cpp */; }; + 80EEA677809189A9BAE63CB7 /* MIDIMacros.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */; }; + 8479AC1F9F461AD1A316B25F /* Load_digi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D14936A73E714519400434E7 /* Load_digi.cpp */; }; + 84A9E60B844CC93DBEA17C4B /* MixerLoops.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */; }; + 8676CA3F6593E471419D407F /* Load_gt2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */; }; + 8751165421750B86D19AEC94 /* mptStringBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C510221C396A670EB74DF05C /* mptStringBuffer.cpp */; }; + 8B4D81ED6A6A9C1F4673F82D /* Load_dsm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */; }; + 8D04F5E56C221017482B6C25 /* WAVTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */; }; + 90C3E5D96FE1000B4BEA5C19 /* Load_mid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC1456C17EA220B3E77AC501 /* Load_mid.cpp */; }; + 926864F471857F264D8EDB34 /* mptRandom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */; }; + 9715CA0B7632E43D523C404B /* Load_s3m.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */; }; + 976568F7F2B0B929E0E29F37 /* libopenmpt_ext_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */; }; + 97AC91CD76C9ABFF52D3080D /* Load_stm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */; }; + 97B1A0C5975483F7D1A93705 /* Echo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C9696EDF3FC09DFA60A252D /* Echo.cpp */; }; + 9F1029ABB9DC985DBDAD2FEB /* ModSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A32EC1731056CFE511E9BFB3 /* ModSample.cpp */; }; + 9F2D020A8C9494BC298E884A /* PlugInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D89E49F2E528FC64600DC832 /* PlugInterface.cpp */; }; + 9FC1BA253DA2BAD715210065 /* Flanger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3286C74DF54727BF527C058D /* Flanger.cpp */; }; + A0E13DD3392E238567752413 /* XMTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */; }; + A5815DFEB5CE41F0B3BB0C3E /* openmpt-vorbis.lib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7CD47E68F42E3983807EE26 /* openmpt-vorbis.lib */; }; + A5DAFA6B19C3721D3C1120AB /* WindowedFIR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14715833DAFF4FA549017673 /* WindowedFIR.cpp */; }; + A7B576CD86D290FF62DBED0D /* Load_amf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37F80675CA85D067335E74B5 /* Load_amf.cpp */; }; + A896F1F84677F2AA1DF63838 /* LFOPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */; }; + A9C7C28B051312BDF344F8CB /* AudioCriticalSection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */; }; + A9D47C71514A1823FA0F22B1 /* SoundFilePlayConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */; }; + AB7FFC4D9117037F545C128D /* mod_specifications.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */; }; + ABC5779D79E8CB4F00F71DDD /* OPL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3A14F450EE2A2B7E23CED85 /* OPL.cpp */; }; + B17E84D14F5F858326DDCB11 /* ContainerPP20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */; }; + B5220D6D8345611F0A53B3AD /* AGC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BFC43D151B059087EE5FDB55 /* AGC.cpp */; }; + B591ED4C6887F6FEB9AA538C /* ComponentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */; }; + B5D9190DF9ECEA3FEDBE6F4D /* Sndmix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */; }; + BA54A1E79971BC19757B1827 /* Load_ams.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29DC06EFBC69D0E12542752F /* Load_ams.cpp */; }; + BB65D2D86E5BDC8ABF7E3918 /* mptFileTemporary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */; }; + BBC2281DFFD5F94FF3A77E5D /* Tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */; }; + BC15882904B4C65B27E07E69 /* patternContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */; }; + BCC110A956E505DB070AE6E9 /* DMOUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */; }; + BD3885019C559F33785EFB41 /* Load_wav.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */; }; + BD4216739C5F30A578688CB3 /* Load_fmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */; }; + BE9B2A6B02AEFB9DF68080AB /* Snd_fx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */; }; + C0082C03041BFD35F7ED8243 /* Reverb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B50C144B262EB53DDBF5628B /* Reverb.cpp */; }; + C55C8AFDA479A52F8083013D /* UMXTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */; }; + C746074BA663217D826C7D8B /* Load_mt2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */; }; + C79768571036A68933625E97 /* libopenmpt_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */; }; + C81D1553A73A2F8583438B93 /* Load_dmf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */; }; + CB31B3AF3F1A2B616167D9EF /* modsmp_ctrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */; }; + CC12FBA114B239D337DDF1E1 /* Compressor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9334A009842C0DFBF02F8E49 /* Compressor.cpp */; }; + CCEFFE57CC92E18906E79497 /* MIDIEvents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */; }; + CEDA1F2FDEBF4B61CB32D56F /* Chorus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84A787B7269123A91DB835F7 /* Chorus.cpp */; }; + CF000469179F429B3ACAFAA9 /* tuningCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */; }; + CF116C1742F9E3C965479257 /* Load_symmod.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7D070D1F43950491B1972B5F /* Load_symmod.cpp */; }; + D1EA5157B1076B898D10C797 /* Load_far.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BB2E75F2E40B1519719559F /* Load_far.cpp */; }; + D2EFC1DFEDBC3091F18CC81F /* Load_dsym.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */; }; + D309698B1BA8A7BD3ED45FCB /* SampleFormatOpus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */; }; + D443016FB3601BA18F6977AF /* S3MTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */; }; + D83D74BB708A5A6D9ED15AFB /* Snd_flt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */; }; + D86AE3F94C535BAB6EA10A39 /* ModSequence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEC583E195537B530355A221 /* ModSequence.cpp */; }; + DC9752537A78530551F69893 /* MixerSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */; }; + DEB582A5DE5865D718AD18E5 /* modcommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */; }; + DEBC9FDC22D0710E16A1F61C /* version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FDF24AF52801665192D64 /* version.cpp */; }; + DF08AE5AEEEDDA8CDB61649A /* mptPathString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */; }; + E6583D037EA522B5ACEC2343 /* ITTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 778D494BBBDBEEBDFE03278B /* ITTools.cpp */; }; + E76008D1C67D2303A2867F11 /* Load_med.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F093E392197082B8A6FAC79 /* Load_med.cpp */; }; + E79434E3857535955CF37B23 /* SampleFormats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */; }; + E7C01BBFC6DD35F1A2E691FF /* Load_itp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A572747FCE4F13965BD9587 /* Load_itp.cpp */; }; + E9363E2F818323E1AFCA246F /* TinyFFT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */; }; + EA420947C95F2379A5687F87 /* Load_sfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C950084F5BDDD241C4B6768F /* Load_sfx.cpp */; }; + EDE4FB2CD37C025E96C1116C /* serialization_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */; }; + F0D031F98EB132AB662F7839 /* ModInstrument.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */; }; + F4EF37CFD40C5201B015AE0F /* Load_ult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FD19A57125F64497B380897 /* Load_ult.cpp */; }; + F57A8B7BD497A5ADB0A101BB /* Load_xmf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */; }; + F59363E88FB7591A3FDD3A28 /* SymMODEcho.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */; }; + F5A6792FD4C39361B0CCEF6F /* Load_dtm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */; }; + F65565599436660B6BB4AB99 /* libopenmpt_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */; }; + FD083C9917D4AB4B1BA542D9 /* OggStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */; }; + FD572F63B04D3915016F95A3 /* SampleFormatSFZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */; }; + FE6ED6D3DD8BF105B9954D13 /* Load_stp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 35790BDC7DE9F00EC288C21C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 04155894998C17C608286ED4 /* ext/mpg123.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = C6BCBF7D1D4A29EFF5C33DBD; + remoteInfo = "openmpt-mpg123.dll"; + }; + 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E64FF33AA9BBB4ECE85F597A /* ext/ogg.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 886C6A4681D26BB8756DC886; + remoteInfo = "openmpt-ogg.dll"; + }; + 7BC1F4B7C432D8E908D1AAF7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 41BBEA4AD732A97C45CF008A /* ext/vorbis.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 058BB8B85C19232A349236F8; + remoteInfo = "openmpt-vorbis.dll"; + }; + 87B37E75D02462A714C334B5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 04155894998C17C608286ED4 /* ext/mpg123.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 6CFC1BC3B56CFFF5FA0BD203; + remoteInfo = "openmpt-mpg123.dll"; + }; + CDFC6750166D4B825B0C1D90 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 41BBEA4AD732A97C45CF008A /* ext/vorbis.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 6EE3599EB7543DD0FBF30FDE; + remoteInfo = "openmpt-vorbis.dll"; + }; + EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E64FF33AA9BBB4ECE85F597A /* ext/ogg.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5036DE60765D0E12DD6404A0; + remoteInfo = "openmpt-ogg.dll"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00114BD59DF24C8775709215 /* callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = callbackstream.hpp; path = ../../src/mpt/io_read/callbackstream.hpp; sourceTree = ""; }; + 01230426588877180A969266 /* buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = buffer.hpp; path = ../../src/mpt/io_write/buffer.hpp; sourceTree = ""; }; + 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Distortion.cpp; path = ../../soundlib/plugins/dmo/Distortion.cpp; sourceTree = ""; }; + 01D708ED277F035F45AF872D /* libopenmpt_stream_callbacks_buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_buffer.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_buffer.h; sourceTree = ""; }; + 021DA33D0EA855AF898D217D /* constexpr_throw.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = constexpr_throw.hpp; path = ../../src/mpt/base/constexpr_throw.hpp; sourceTree = ""; }; + 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mus_km.cpp; path = ../../soundlib/Load_mus_km.cpp; sourceTree = ""; }; + 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TinyFFT.cpp; path = ../../soundlib/TinyFFT.cpp; sourceTree = ""; }; + 04155894998C17C608286ED4 /* openmpt-mpg123.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "mpg123.xcodeproj"; path = ext/mpg123.xcodeproj; sourceTree = SOURCE_ROOT; }; + 046F30B171973F23732A2EF1 /* numeric.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = numeric.hpp; path = ../../src/mpt/base/numeric.hpp; sourceTree = ""; }; + 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = EQ.cpp; path = ../../sounddsp/EQ.cpp; sourceTree = ""; }; + 04EAEC77C7AB4CE924E02AB7 /* DMOPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DMOPlugin.h; path = ../../soundlib/plugins/dmo/DMOPlugin.h; sourceTree = ""; }; + 06C40A24C9846A9626B94864 /* io_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_stdstream.hpp; path = ../../src/mpt/io/io_stdstream.hpp; sourceTree = ""; }; + 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_stm.cpp; path = ../../soundlib/Load_stm.cpp; sourceTree = ""; }; + 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatSFZ.cpp; path = ../../soundlib/SampleFormatSFZ.cpp; sourceTree = ""; }; + 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileType.cpp; path = ../../common/mptFileType.cpp; sourceTree = ""; }; + 07580841CEBCC33359749681 /* tests_string_utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_utility.hpp; path = ../../src/mpt/string/tests/tests_string_utility.hpp; sourceTree = ""; }; + 079DA5A7A1C19AD951E77BE7 /* filedata_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_memory.hpp; path = ../../src/mpt/io_read/filedata_memory.hpp; sourceTree = ""; }; + 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ptm.cpp; path = ../../soundlib/Load_ptm.cpp; sourceTree = ""; }; + 09387CD815C32F4A90A7FB18 /* PluginMixBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginMixBuffer.h; path = ../../soundlib/plugins/PluginMixBuffer.h; sourceTree = ""; }; + 09573FAA7A79E09C30408DEA /* arch.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = arch.hpp; path = ../../src/mpt/arch/arch.hpp; sourceTree = ""; }; + 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mtm.cpp; path = ../../soundlib/Load_mtm.cpp; sourceTree = ""; }; + 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = modsmp_ctrl.cpp; path = ../../soundlib/modsmp_ctrl.cpp; sourceTree = ""; }; + 0A20B0FECCE111702A15EF3E /* ComponentManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ComponentManager.h; path = ../../common/ComponentManager.h; sourceTree = ""; }; + 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerXPK.cpp; path = ../../soundlib/ContainerXPK.cpp; sourceTree = ""; }; + 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dtm.cpp; path = ../../soundlib/Load_dtm.cpp; sourceTree = ""; }; + 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mt2.cpp; path = ../../soundlib/Load_mt2.cpp; sourceTree = ""; }; + 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mo3.cpp; path = ../../soundlib/Load_mo3.cpp; sourceTree = ""; }; + 0F8105B483DB4AA601BED3F4 /* dos_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dos_version.hpp; path = ../../src/mpt/osinfo/dos_version.hpp; sourceTree = ""; }; + 0FDA8FB11C654223974A0DF1 /* libopenmpt_version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_version.h; path = ../../libopenmpt/libopenmpt_version.h; sourceTree = ""; }; + 1054EEE754A3945996CACD27 /* Fastmix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Fastmix.cpp; path = ../../soundlib/Fastmix.cpp; sourceTree = ""; }; + 107683B90475CD2B8960E1F9 /* detect_quirks.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_quirks.hpp; path = ../../src/mpt/base/detect_quirks.hpp; sourceTree = ""; }; + 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_gt2.cpp; path = ../../soundlib/Load_gt2.cpp; sourceTree = ""; }; + 1197459E05968F108A81A3DE /* feature_flags.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = feature_flags.hpp; path = ../../src/mpt/arch/feature_flags.hpp; sourceTree = ""; }; + 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerMMCMP.cpp; path = ../../soundlib/ContainerMMCMP.cpp; sourceTree = ""; }; + 12DCF57C800503EE8197F3BC /* mptBaseUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseUtils.h; path = ../../common/mptBaseUtils.h; sourceTree = ""; }; + 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileIO.cpp; path = ../../common/mptFileIO.cpp; sourceTree = ""; }; + 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ComponentManager.cpp; path = ../../common/ComponentManager.cpp; sourceTree = ""; }; + 14715833DAFF4FA549017673 /* WindowedFIR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WindowedFIR.cpp; path = ../../soundlib/WindowedFIR.cpp; sourceTree = ""; }; + 159B6F7E099AB8F08E85CDBE /* PluginManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginManager.h; path = ../../soundlib/plugins/PluginManager.h; sourceTree = ""; }; + 15A918AF09A862218E9376EF /* aligned_array.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = aligned_array.hpp; path = ../../src/mpt/base/aligned_array.hpp; sourceTree = ""; }; + 1679D9615AC87ED39CEFB7A1 /* alloc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = alloc.hpp; path = ../../src/mpt/base/alloc.hpp; sourceTree = ""; }; + 175234BFDDE02C314BE252FF /* detect_os.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_os.hpp; path = ../../src/mpt/base/detect_os.hpp; sourceTree = ""; }; + 178BC3E3DA4C245537810223 /* native_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = native_path.hpp; path = ../../src/mpt/path/native_path.hpp; sourceTree = ""; }; + 17F58A2FDAB5EAA137EAC86F /* detect_libc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_libc.hpp; path = ../../src/mpt/base/detect_libc.hpp; sourceTree = ""; }; + 18A72A335CF5CFA59F1D0873 /* seed.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = seed.hpp; path = ../../src/mpt/random/seed.hpp; sourceTree = ""; }; + 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Sndmix.cpp; path = ../../soundlib/Sndmix.cpp; sourceTree = ""; }; + 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RowVisitor.cpp; path = ../../soundlib/RowVisitor.cpp; sourceTree = ""; }; + 1A94BBC4BC7E57B6B3A56A04 /* mptStringFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptStringFormat.h; path = ../../common/mptStringFormat.h; sourceTree = ""; }; + 1AA25C6F0B99CA61779D4AAF /* check_platform.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = check_platform.hpp; path = ../../src/mpt/base/check_platform.hpp; sourceTree = ""; }; + 1AD54F9F7616A3114970EDDF /* Paula.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Paula.h; path = ../../soundlib/Paula.h; sourceTree = ""; }; + 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Tagging.cpp; path = ../../soundlib/Tagging.cpp; sourceTree = ""; }; + 1C2F81B7DEEFE2293C24BFF7 /* detect_arch.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_arch.hpp; path = ../../src/mpt/base/detect_arch.hpp; sourceTree = ""; }; + 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatOpus.cpp; path = ../../soundlib/SampleFormatOpus.cpp; sourceTree = ""; }; + 1CE2C4318A0AD2A38B9DC271 /* device.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = device.hpp; path = ../../src/mpt/random/device.hpp; sourceTree = ""; }; + 1E7AA06D8BA2AEDF8D359EAD /* simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple.hpp; path = ../../src/mpt/format/simple.hpp; sourceTree = ""; }; + 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_s3m.cpp; path = ../../soundlib/Load_s3m.cpp; sourceTree = ""; }; + 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WAVTools.cpp; path = ../../soundlib/WAVTools.cpp; sourceTree = ""; }; + 2052C727B2E091191BB93567 /* Load_mdl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mdl.cpp; path = ../../soundlib/Load_mdl.cpp; sourceTree = ""; }; + 209166838DB974F58F4C64C3 /* numbers.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = numbers.hpp; path = ../../src/mpt/base/numbers.hpp; sourceTree = ""; }; + 20B693A5E7448B175546B1E5 /* MixerSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerSettings.h; path = ../../soundlib/MixerSettings.h; sourceTree = ""; }; + 212A36FD7B2B4DEF4272453D /* semantic_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = semantic_version.hpp; path = ../../src/mpt/base/semantic_version.hpp; sourceTree = ""; }; + 2151B0037C9303754FED4E43 /* Mixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Mixer.h; path = ../../soundlib/Mixer.h; sourceTree = ""; }; + 22594181666D12B35A3E97C1 /* fileref.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fileref.hpp; path = ../../src/mpt/io_file/fileref.hpp; sourceTree = ""; }; + 2323E4A5944685974A0D32E5 /* Snd_defs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Snd_defs.h; path = ../../soundlib/Snd_defs.h; sourceTree = ""; }; + 236E8DFB1D304A6D572F4C3B /* Tagging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tagging.h; path = ../../soundlib/Tagging.h; sourceTree = ""; }; + 23EF16CF7F4F3B81C192DD0F /* filedata_base_buffered.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_buffered.hpp; path = ../../src/mpt/io_read/filedata_base_buffered.hpp; sourceTree = ""; }; + 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerUMX.cpp; path = ../../soundlib/ContainerUMX.cpp; sourceTree = ""; }; + 25EAC3A1C044AC93FC7D11E1 /* unique_basename.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = unique_basename.hpp; path = ../../src/mpt/io_file_unique/unique_basename.hpp; sourceTree = ""; }; + 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mod_specifications.cpp; path = ../../soundlib/mod_specifications.cpp; sourceTree = ""; }; + 27B40A4D98D6AB3F4E9D588D /* SampleIO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleIO.h; path = ../../soundlib/SampleIO.h; sourceTree = ""; }; + 2810796521D235D75BD137A5 /* XMTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = XMTools.h; path = ../../soundlib/XMTools.h; sourceTree = ""; }; + 28D2F38195FB01F3978DF1C1 /* modsmp_ctrl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = modsmp_ctrl.h; path = ../../soundlib/modsmp_ctrl.h; sourceTree = ""; }; + 29DC06EFBC69D0E12542752F /* Load_ams.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ams.cpp; path = ../../soundlib/Load_ams.cpp; sourceTree = ""; }; + 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_xm.cpp; path = ../../soundlib/Load_xm.cpp; sourceTree = ""; }; + 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixerSettings.cpp; path = ../../soundlib/MixerSettings.cpp; sourceTree = ""; }; + 2BF8C6379D1B672952E21477 /* WAVTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WAVTools.h; path = ../../soundlib/WAVTools.h; sourceTree = ""; }; + 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ITCompression.cpp; path = ../../soundlib/ITCompression.cpp; sourceTree = ""; }; + 2C28EA4338B39CB5B3986883 /* wrapping_divide.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = wrapping_divide.hpp; path = ../../src/mpt/base/wrapping_divide.hpp; sourceTree = ""; }; + 2D02F4CF9E2595C153EC430F /* UMXTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = UMXTools.h; path = ../../soundlib/UMXTools.h; sourceTree = ""; }; + 2E1DD07ED0076C70C72E7EBE /* tests_io.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_io.hpp; path = ../../src/mpt/io/tests/tests_io.hpp; sourceTree = ""; }; + 2E2F32DF9F51D3D15518811F /* hex.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = hex.hpp; path = ../../src/mpt/binary/hex.hpp; sourceTree = ""; }; + 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_xmf.cpp; path = ../../soundlib/Load_xmf.cpp; sourceTree = ""; }; + 2F3B0AD7F5C9024963CB2917 /* ITCompression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITCompression.h; path = ../../soundlib/ITCompression.h; sourceTree = ""; }; + 321030713E9AE2E3B97FAEB1 /* detect_compiler.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_compiler.hpp; path = ../../src/mpt/base/detect_compiler.hpp; sourceTree = ""; }; + 3286C74DF54727BF527C058D /* Flanger.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Flanger.cpp; path = ../../soundlib/plugins/dmo/Flanger.cpp; sourceTree = ""; }; + 32BAAF6B89D057DDB618EDAB /* tests_base_saturate_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_saturate_cast.hpp; path = ../../src/mpt/base/tests/tests_base_saturate_cast.hpp; sourceTree = ""; }; + 338C775D77DB1CCFBA02559D /* BitReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BitReader.h; path = ../../soundlib/BitReader.h; sourceTree = ""; }; + 34D45985C7622377303AC7C5 /* Load_imf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_imf.cpp; path = ../../soundlib/Load_imf.cpp; sourceTree = ""; }; + 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_c.cpp; path = ../../libopenmpt/libopenmpt_c.cpp; sourceTree = ""; }; + 36619CBCFDC657AE887E2AFC /* inputfile_filecursor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = inputfile_filecursor.hpp; path = ../../src/mpt/io_file_read/inputfile_filecursor.hpp; sourceTree = ""; }; + 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dmf.cpp; path = ../../soundlib/Load_dmf.cpp; sourceTree = ""; }; + 37064A799107616B584E58B9 /* tests_random.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_random.hpp; path = ../../src/mpt/random/tests/tests_random.hpp; sourceTree = ""; }; + 37F80675CA85D067335E74B5 /* Load_amf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_amf.cpp; path = ../../soundlib/Load_amf.cpp; sourceTree = ""; }; + 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ContainerPP20.cpp; path = ../../soundlib/ContainerPP20.cpp; sourceTree = ""; }; + 392551FD7D73F76FBF9B303D /* ModSample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSample.h; path = ../../soundlib/ModSample.h; sourceTree = ""; }; + 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AudioCriticalSection.cpp; path = ../../soundlib/AudioCriticalSection.cpp; sourceTree = ""; }; + 39C1318B738BE83D28E737CB /* filecursor_filename_traits.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_filename_traits.hpp; path = ../../src/mpt/io_read/filecursor_filename_traits.hpp; sourceTree = ""; }; + 39CF376FCC5D01613535A5AF /* FloatMixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FloatMixer.h; path = ../../soundlib/FloatMixer.h; sourceTree = ""; }; + 3A4473F97E93196BC0BA5239 /* join.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = join.hpp; path = ../../src/mpt/format/join.hpp; sourceTree = ""; }; + 3AADECCD91C3953FBE0C2B0D /* libopenmpt_stream_callbacks_fd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_fd.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_fd.h; sourceTree = ""; }; + 3AC37DA5015175176F539BE5 /* namespace.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = namespace.hpp; path = ../../src/mpt/base/namespace.hpp; sourceTree = ""; }; + 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = S3MTools.cpp; path = ../../soundlib/S3MTools.cpp; sourceTree = ""; }; + 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UpgradeModule.cpp; path = ../../soundlib/UpgradeModule.cpp; sourceTree = ""; }; + 3C628FD12D59FDC3995D7E11 /* nlohmann_json.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = nlohmann_json.hpp; path = ../../src/mpt/detect/nlohmann_json.hpp; sourceTree = ""; }; + 3CC72D5B942CA04D463ABB9B /* integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = integer.hpp; path = ../../src/mpt/endian/integer.hpp; sourceTree = ""; }; + 3D34478136F603F370F505C1 /* TinyFFT.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TinyFFT.h; path = ../../soundlib/TinyFFT.h; sourceTree = ""; }; + 3E2FDF24AF52801665192D64 /* version.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = version.cpp; path = ../../common/version.cpp; sourceTree = ""; }; + 3EEBB71B8158038D397E755B /* libopenmpt_stream_callbacks_file_mingw.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_mingw.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_mingw.h; sourceTree = ""; }; + 3F5591FF83A43771C5CB703F /* Container.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Container.h; path = ../../soundlib/Container.h; sourceTree = ""; }; + 406A557CF3605F2E4482BBBC /* out_of_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = out_of_memory.hpp; path = ../../src/mpt/out_of_memory/out_of_memory.hpp; sourceTree = ""; }; + 40C5E675B1E8876767AF34B5 /* uuid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = uuid.hpp; path = ../../src/mpt/uuid/uuid.hpp; sourceTree = ""; }; + 417FE082D6F69FB44592F6C2 /* libc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libc.hpp; path = ../../src/mpt/check/libc.hpp; sourceTree = ""; }; + 41BBBCC5DBDFB1F78C059305 /* exception_text.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = exception_text.hpp; path = ../../src/mpt/exception/exception_text.hpp; sourceTree = ""; }; + 41BBEA4AD732A97C45CF008A /* openmpt-vorbis.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "vorbis.xcodeproj"; path = ext/vorbis.xcodeproj; sourceTree = SOURCE_ROOT; }; + 41DFAAC7AF07B939B09AA907 /* libopenmpt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt.h; path = ../../libopenmpt/libopenmpt.h; sourceTree = ""; }; + 43B7419134AEAF83A0B22FD1 /* libopenmpt_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_config.h; path = ../../libopenmpt/libopenmpt_config.h; sourceTree = ""; }; + 43CBFB4A068C5BBC63C1398A /* mptFileTemporary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileTemporary.h; path = ../../common/mptFileTemporary.h; sourceTree = ""; }; + 44E6E1C323897D35D86B8003 /* tests_base_bit.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_bit.hpp; path = ../../src/mpt/base/tests/tests_base_bit.hpp; sourceTree = ""; }; + 45D0E0DE525B9350CD405F1E /* DigiBoosterEcho.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DigiBoosterEcho.h; path = ../../soundlib/plugins/DigiBoosterEcho.h; sourceTree = ""; }; + 45DBF5F73F9DB269799CB437 /* Dlsbank.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Dlsbank.h; path = ../../soundlib/Dlsbank.h; sourceTree = ""; }; + 4614D43FB73775316CFE227F /* math.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = math.hpp; path = ../../src/mpt/base/math.hpp; sourceTree = ""; }; + 46877D383A86C6AABF71DB78 /* PluginStructs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PluginStructs.h; path = ../../soundlib/plugins/PluginStructs.h; sourceTree = ""; }; + 46BE019F097E621166B33FDF /* SampleNormalize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleNormalize.h; path = ../../soundlib/SampleNormalize.h; sourceTree = ""; }; + 473316F00DC10E627BC33530 /* x86_amd64.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = x86_amd64.hpp; path = ../../src/mpt/arch/x86_amd64.hpp; sourceTree = ""; }; + 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatMP3.cpp; path = ../../soundlib/SampleFormatMP3.cpp; sourceTree = ""; }; + 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SymMODEcho.cpp; path = ../../soundlib/plugins/SymMODEcho.cpp; sourceTree = ""; }; + 4756C54F9DE42FC1765D438F /* OPL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OPL.h; path = ../../soundlib/OPL.h; sourceTree = ""; }; + 48199D39B93C3E2B6F02EB79 /* tuning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = tuning.cpp; path = ../../soundlib/tuning.cpp; sourceTree = ""; }; + 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Tables.cpp; path = ../../soundlib/Tables.cpp; sourceTree = ""; }; + 49E264470CA2C4B969D7A287 /* engine_lcg.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = engine_lcg.hpp; path = ../../src/mpt/random/engine_lcg.hpp; sourceTree = ""; }; + 4AECD572BC0F766471D623B2 /* mptString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptString.h; path = ../../common/mptString.h; sourceTree = ""; }; + 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptPathString.cpp; path = ../../common/mptPathString.cpp; sourceTree = ""; }; + 4CDD73CDC0C5EB7FE3139A0D /* logic_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = logic_error.hpp; path = ../../src/mpt/exception/logic_error.hpp; sourceTree = ""; }; + 4D1485535F373B4538387393 /* tests_base_arithmetic_shift.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_arithmetic_shift.hpp; path = ../../src/mpt/base/tests/tests_base_arithmetic_shift.hpp; sourceTree = ""; }; + 4DFC0969924AAEDBD471E7A9 /* ltdl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = ltdl.hpp; path = ../../src/mpt/detect/ltdl.hpp; sourceTree = ""; }; + 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_plm.cpp; path = ../../soundlib/Load_plm.cpp; sourceTree = ""; }; + 4E96BB31E124852349FD2971 /* types.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = types.hpp; path = ../../src/mpt/string/types.hpp; sourceTree = ""; }; + 4FB7A50743B6EE79C8A20347 /* floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = floatingpoint.hpp; path = ../../src/mpt/base/floatingpoint.hpp; sourceTree = ""; }; + 50318A59BD5998CBBEEC8899 /* os_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = os_path.hpp; path = ../../src/mpt/path/os_path.hpp; sourceTree = ""; }; + 50CF7EB4C1F21FA677B8CCF4 /* mptFileIO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileIO.h; path = ../../common/mptFileIO.h; sourceTree = ""; }; + 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MIDIMacros.cpp; path = ../../soundlib/MIDIMacros.cpp; sourceTree = ""; }; + 5178AA15C29B4B077861F855 /* mfc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mfc.hpp; path = ../../src/mpt/detect/mfc.hpp; sourceTree = ""; }; + 51E2F9635E6DABD5D95277A3 /* SoundFilePlayConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SoundFilePlayConfig.h; path = ../../soundlib/SoundFilePlayConfig.h; sourceTree = ""; }; + 51EB7985F3D51577EAFC27C5 /* base64url.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base64url.hpp; path = ../../src/mpt/binary/base64url.hpp; sourceTree = ""; }; + 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_uax.cpp; path = ../../soundlib/Load_uax.cpp; sourceTree = ""; }; + 54F2D0191B80C78B8982EE59 /* algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = algorithm.hpp; path = ../../src/mpt/base/algorithm.hpp; sourceTree = ""; }; + 55356226EAAC215859487866 /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/audio/span.hpp; sourceTree = ""; }; + 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Dlsbank.cpp; path = ../../soundlib/Dlsbank.cpp; sourceTree = ""; }; + 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_int24.hpp; path = ../../src/mpt/endian/tests/tests_endian_int24.hpp; sourceTree = ""; }; + 5609DBF3C331EA65C4C4DA33 /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/base/utility.hpp; sourceTree = ""; }; + 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentExtensions.cpp; path = ../../soundlib/InstrumentExtensions.cpp; sourceTree = ""; }; + 57E617F588CA0FE79BE24635 /* Reverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Reverb.h; path = ../../sounddsp/Reverb.h; sourceTree = ""; }; + 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_cxx.cpp; path = ../../libopenmpt/libopenmpt_cxx.cpp; sourceTree = ""; }; + 5AF83E8DC8204CFFC9B33CCD /* pointer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = pointer.hpp; path = ../../src/mpt/base/pointer.hpp; sourceTree = ""; }; + 5BE26A37EE7034295748D877 /* modcommand.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = modcommand.h; path = ../../soundlib/modcommand.h; sourceTree = ""; }; + 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatVorbis.cpp; path = ../../soundlib/SampleFormatVorbis.cpp; sourceTree = ""; }; + 5CFFC0612B231413B23166A1 /* parse.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = parse.hpp; path = ../../src/mpt/parse/parse.hpp; sourceTree = ""; }; + 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptRandom.cpp; path = ../../common/mptRandom.cpp; sourceTree = ""; }; + 5E8119A76B0BCC19E5F097E7 /* simple_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_integer.hpp; path = ../../src/mpt/format/simple_integer.hpp; sourceTree = ""; }; + 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModChannel.cpp; path = ../../soundlib/ModChannel.cpp; sourceTree = ""; }; + 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixFuncTable.cpp; path = ../../soundlib/MixFuncTable.cpp; sourceTree = ""; }; + 6058487C545791EED942A6BC /* PlugInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PlugInterface.h; path = ../../soundlib/plugins/PlugInterface.h; sourceTree = ""; }; + 62235C27A6720199E8993A67 /* Load_it.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_it.cpp; path = ../../soundlib/Load_it.cpp; sourceTree = ""; }; + 62E32DEB72C85A1D5F3BE42B /* filedata_base.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base.hpp; path = ../../src/mpt/io_read/filedata_base.hpp; sourceTree = ""; }; + 6303157093E70D62A6FF43B0 /* Logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../common/Logging.h; sourceTree = ""; }; + 632A109AF5B7DA8C5E907EDA /* io_span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_span.hpp; path = ../../src/mpt/io/io_span.hpp; sourceTree = ""; }; + 63FDD8AF94E1D0A1A7FA06EF /* Tables.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Tables.h; path = ../../soundlib/Tables.h; sourceTree = ""; }; + 64377F84A84B50B69C1CD5C4 /* compiler.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = compiler.hpp; path = ../../src/mpt/check/compiler.hpp; sourceTree = ""; }; + 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DMOUtils.cpp; path = ../../soundlib/plugins/dmo/DMOUtils.cpp; sourceTree = ""; }; + 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_stp.cpp; path = ../../soundlib/Load_stp.cpp; sourceTree = ""; }; + 6687823BDAE1C72D58C5507B /* tuningcollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuningcollection.h; path = ../../soundlib/tuningcollection.h; sourceTree = ""; }; + 66CA3B04BE2FADF6703DC944 /* mptBaseMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseMacros.h; path = ../../common/mptBaseMacros.h; sourceTree = ""; }; + 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Message.cpp; path = ../../soundlib/Message.cpp; sourceTree = ""; }; + 6858F8CA2EE6F03C9CE9170A /* LFOPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LFOPlugin.h; path = ../../soundlib/plugins/LFOPlugin.h; sourceTree = ""; }; + 68FC5709D624657BD7B75549 /* concat.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = concat.hpp; path = ../../src/mpt/format/concat.hpp; sourceTree = ""; }; + 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_wav.cpp; path = ../../soundlib/Load_wav.cpp; sourceTree = ""; }; + 6A572747FCE4F13965BD9587 /* Load_itp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_itp.cpp; path = ../../soundlib/Load_itp.cpp; sourceTree = ""; }; + 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dbm.cpp; path = ../../soundlib/Load_dbm.cpp; sourceTree = ""; }; + 6AE995E9FD775FDB66500429 /* Load_okt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_okt.cpp; path = ../../soundlib/Load_okt.cpp; sourceTree = ""; }; + 6AF57E36C636D1A899911C76 /* stdafx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stdafx.h; path = ../../common/stdafx.h; sourceTree = ""; }; + 6B9C8BDDC301FECF75101A1D /* Gargle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Gargle.h; path = ../../soundlib/plugins/dmo/Gargle.h; sourceTree = ""; }; + 6C67B7D97E1EF7CBF38CE619 /* tests_base_math.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_math.hpp; path = ../../src/mpt/base/tests/tests_base_math.hpp; sourceTree = ""; }; + 6D2350A8B171F61AF3992EE8 /* FileReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FileReader.h; path = ../../common/FileReader.h; sourceTree = ""; }; + 6E84090F7E6935416ADCBF4F /* environment.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = environment.hpp; path = ../../src/mpt/environment/environment.hpp; sourceTree = ""; }; + 6F3A912F8923F36144AA076F /* filecursor_callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_callbackstream.hpp; path = ../../src/mpt/io_read/filecursor_callbackstream.hpp; sourceTree = ""; }; + 70644035FF1571275A9F8E75 /* libopenmpt_stream_callbacks_file_msvcrt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_msvcrt.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h; sourceTree = ""; }; + 712230EFB9C16F21DCED272F /* filecursor_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_memory.hpp; path = ../../src/mpt/io_read/filecursor_memory.hpp; sourceTree = ""; }; + 7154B71FCB55CE11929CC55F /* libopenmpt_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_internal.h; path = ../../libopenmpt/libopenmpt_internal.h; sourceTree = ""; }; + 7159D71DCB5AEE0F92A1E55D /* default_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_integer.hpp; path = ../../src/mpt/format/default_integer.hpp; sourceTree = ""; }; + 7214DF31A1A6AE237CB3ED71 /* opal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = opal.h; path = ../../soundlib/opal.h; sourceTree = ""; }; + 721CEF1FC98262117B907D5F /* helpers.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = helpers.hpp; path = ../../src/mpt/format/helpers.hpp; sourceTree = ""; }; + 73262ABB150FC6AD0C36D8FB /* DMOUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DMOUtils.h; path = ../../soundlib/plugins/dmo/DMOUtils.h; sourceTree = ""; }; + 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_ext_impl.cpp; path = ../../libopenmpt/libopenmpt_ext_impl.cpp; sourceTree = ""; }; + 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Snd_flt.cpp; path = ../../soundlib/Snd_flt.cpp; sourceTree = ""; }; + 73A52C155E915207A6771A55 /* EQ.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EQ.h; path = ../../sounddsp/EQ.h; sourceTree = ""; }; + 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = modcommand.cpp; path = ../../soundlib/modcommand.cpp; sourceTree = ""; }; + 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Snd_fx.cpp; path = ../../soundlib/Snd_fx.cpp; sourceTree = ""; }; + 74D96CA8E5FC0D9A9BC2BAE8 /* mptAssert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptAssert.h; path = ../../common/mptAssert.h; sourceTree = ""; }; + 74DCDADDCC424DCF7E50691D /* MixFuncTable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixFuncTable.h; path = ../../soundlib/MixFuncTable.h; sourceTree = ""; }; + 7523D3EEA607CBE0B920022E /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = version.h; path = ../../common/version.h; sourceTree = ""; }; + 755174CF6950BE41EE3BD30F /* detect_libcxx.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect_libcxx.hpp; path = ../../src/mpt/base/detect_libcxx.hpp; sourceTree = ""; }; + 75EFCB7913D0CC2BEB4F11B9 /* runtime_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = runtime_error.hpp; path = ../../src/mpt/exception/runtime_error.hpp; sourceTree = ""; }; + 778D494BBBDBEEBDFE03278B /* ITTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ITTools.cpp; path = ../../soundlib/ITTools.cpp; sourceTree = ""; }; + 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mod.cpp; path = ../../soundlib/Load_mod.cpp; sourceTree = ""; }; + 787945A7E5A15419E73443E7 /* integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = integer.hpp; path = ../../src/mpt/base/integer.hpp; sourceTree = ""; }; + 788395FAAA7CE0AC245C1C3A /* mfc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mfc.hpp; path = ../../src/mpt/check/mfc.hpp; sourceTree = ""; }; + 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Gargle.cpp; path = ../../soundlib/plugins/dmo/Gargle.cpp; sourceTree = ""; }; + 78CAB4630B587E55743122A3 /* SampleIO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleIO.cpp; path = ../../soundlib/SampleIO.cpp; sourceTree = ""; }; + 793E301E72FFEC90ACFEEE5E /* base.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base.hpp; path = ../../src/mpt/io/base.hpp; sourceTree = ""; }; + 7A6823C37429E035AE28E203 /* Message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Message.h; path = ../../soundlib/Message.h; sourceTree = ""; }; + 7C15603DE93D6EAFEAD05E7D /* engine.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = engine.hpp; path = ../../src/mpt/random/engine.hpp; sourceTree = ""; }; + 7C2DCED7ED506FC9A3171D17 /* path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = path.hpp; path = ../../src/mpt/path/path.hpp; sourceTree = ""; }; + 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMTools.cpp; path = ../../soundlib/XMTools.cpp; sourceTree = ""; }; + 7D070D1F43950491B1972B5F /* Load_symmod.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_symmod.cpp; path = ../../soundlib/Load_symmod.cpp; sourceTree = ""; }; + 7D6EAF1E983B1DD09C0BB55E /* tests_crc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_crc.hpp; path = ../../src/mpt/crc/tests/tests_crc.hpp; sourceTree = ""; }; + 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = WavesReverb.cpp; path = ../../soundlib/plugins/dmo/WavesReverb.cpp; sourceTree = ""; }; + 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = libopenmpt_impl.cpp; path = ../../libopenmpt/libopenmpt_impl.cpp; sourceTree = ""; }; + 7FD19A57125F64497B380897 /* Load_ult.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_ult.cpp; path = ../../soundlib/Load_ult.cpp; sourceTree = ""; }; + 80C993CB8D54463D0839120B /* message_macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = message_macros.hpp; path = ../../src/mpt/format/message_macros.hpp; sourceTree = ""; }; + 80F9D5FD1722E7EFD889443D /* default_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_floatingpoint.hpp; path = ../../src/mpt/format/default_floatingpoint.hpp; sourceTree = ""; }; + 82EA4C5D44A2DDCFEBBDAA9D /* tests_base_wrapping_divide.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_wrapping_divide.hpp; path = ../../src/mpt/base/tests/tests_base_wrapping_divide.hpp; sourceTree = ""; }; + 830F3566F431D658A9F883A6 /* Logging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Logging.cpp; path = ../../common/Logging.cpp; sourceTree = ""; }; + 84A787B7269123A91DB835F7 /* Chorus.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Chorus.cpp; path = ../../soundlib/plugins/dmo/Chorus.cpp; sourceTree = ""; }; + 85812219180EEC0B80E79059 /* secure.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = secure.hpp; path = ../../src/mpt/base/secure.hpp; sourceTree = ""; }; + 85A36D37F9FDB22977E13B77 /* os_path_long.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = os_path_long.hpp; path = ../../src/mpt/path/os_path_long.hpp; sourceTree = ""; }; + 86260AE5E2AD0F576B4FC925 /* compiletime_warning.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = compiletime_warning.hpp; path = ../../src/mpt/base/compiletime_warning.hpp; sourceTree = ""; }; + 87A62ABDE1A741AFA8EE38FD /* AudioCriticalSection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioCriticalSection.h; path = ../../soundlib/AudioCriticalSection.h; sourceTree = ""; }; + 8856685FF57E76D1F711669F /* base64.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = base64.hpp; path = ../../src/mpt/binary/base64.hpp; sourceTree = ""; }; + 8876678BE2777E7DA9BE75CB /* default_engines.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_engines.hpp; path = ../../src/mpt/random/default_engines.hpp; sourceTree = ""; }; + 8A87EA73FEE22F657CC5B8B3 /* macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = macros.hpp; path = ../../src/mpt/string_transcode/macros.hpp; sourceTree = ""; }; + 8ABDA3472E24D0F9455A8987 /* filedata_base_unseekable.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_unseekable.hpp; path = ../../src/mpt/io_read/filedata_base_unseekable.hpp; sourceTree = ""; }; + 8ABF23E958E2779BDFF0CA29 /* mutex.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = mutex.hpp; path = ../../src/mpt/mutex/mutex.hpp; sourceTree = ""; }; + 8B1AB3CB32904F7DDB555A0B /* filecursor_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_stdstream.hpp; path = ../../src/mpt/io_read/filecursor_stdstream.hpp; sourceTree = ""; }; + 8BE3D4DDCE50214F8676931D /* libopenmpt_stream_callbacks_file_posix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_posix.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_posix.h; sourceTree = ""; }; + 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = patternContainer.cpp; path = ../../soundlib/patternContainer.cpp; sourceTree = ""; }; + 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ParamEq.cpp; path = ../../soundlib/plugins/dmo/ParamEq.cpp; sourceTree = ""; }; + 8C8CA6B3531A9E25C11CC4F3 /* ModSampleCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSampleCopy.h; path = ../../soundlib/ModSampleCopy.h; sourceTree = ""; }; + 8CA9A5C72521933951088407 /* simple_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_floatingpoint.hpp; path = ../../src/mpt/format/simple_floatingpoint.hpp; sourceTree = ""; }; + 8DE932C12076FCB3894FA101 /* crand.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = crand.hpp; path = ../../src/mpt/random/crand.hpp; sourceTree = ""; }; + 8DF141A2BED53994D1ED6FE2 /* mptTime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptTime.h; path = ../../common/mptTime.h; sourceTree = ""; }; + 8EA1F2E35357495507C5F123 /* tests_format_simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_format_simple.hpp; path = ../../src/mpt/format/tests/tests_format_simple.hpp; sourceTree = ""; }; + 8F093E392197082B8A6FAC79 /* Load_med.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_med.cpp; path = ../../soundlib/Load_med.cpp; sourceTree = ""; }; + 8F52A05ED3A145D015C87E9E /* Profiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Profiler.cpp; path = ../../common/Profiler.cpp; sourceTree = ""; }; + 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatBRR.cpp; path = ../../soundlib/SampleFormatBRR.cpp; sourceTree = ""; }; + 90E45EE632CDFAD829F50D26 /* mptStringBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptStringBuffer.h; path = ../../common/mptStringBuffer.h; sourceTree = ""; }; + 9133E604FE5BF476FFEEE444 /* OpCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OpCodes.h; path = ../../soundlib/plugins/OpCodes.h; sourceTree = ""; }; + 915D6003E8C2D2F59AD0EE43 /* message.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = message.hpp; path = ../../src/mpt/format/message.hpp; sourceTree = ""; }; + 91AA522185A99B930A94B061 /* I3DL2Reverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = I3DL2Reverb.h; path = ../../soundlib/plugins/dmo/I3DL2Reverb.h; sourceTree = ""; }; + 91EC613953A4F2ABFABFBF79 /* libopenmpt_stream_callbacks_file.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file.h; sourceTree = ""; }; + 92AB21E22B230F54570A0022 /* windows_wine_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows_wine_version.hpp; path = ../../src/mpt/osinfo/windows_wine_version.hpp; sourceTree = ""; }; + 9334A009842C0DFBF02F8E49 /* Compressor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Compressor.cpp; path = ../../soundlib/plugins/dmo/Compressor.cpp; sourceTree = ""; }; + 9469EF975BCEAA89E6867DD7 /* unique_tempfilename.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = unique_tempfilename.hpp; path = ../../src/mpt/io_file_unique/unique_tempfilename.hpp; sourceTree = ""; }; + 949CE444733F7FB628218284 /* io_virtual_wrapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io_virtual_wrapper.hpp; path = ../../src/mpt/io/io_virtual_wrapper.hpp; sourceTree = ""; }; + 94CA18088E8BD47AC88AD648 /* Profiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Profiler.h; path = ../../common/Profiler.h; sourceTree = ""; }; + 9620F5BDA843ABAF8144E3FD /* tests_endian_floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_floatingpoint.hpp; path = ../../src/mpt/endian/tests/tests_endian_floatingpoint.hpp; sourceTree = ""; }; + 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = serialization_utils.cpp; path = ../../common/serialization_utils.cpp; sourceTree = ""; }; + 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OggStream.cpp; path = ../../soundlib/OggStream.cpp; sourceTree = ""; }; + 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_gdm.cpp; path = ../../soundlib/Load_gdm.cpp; sourceTree = ""; }; + 995821ED5E0D785F127C202D /* tests_string_buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_buffer.hpp; path = ../../src/mpt/string/tests/tests_string_buffer.hpp; sourceTree = ""; }; + 9B1917A761A70F19CFA935E7 /* ParamEq.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ParamEq.h; path = ../../soundlib/plugins/dmo/ParamEq.h; sourceTree = ""; }; + 9B95674D94FB68BF8896C58D /* libopenmpt.dll */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = libopenmpt.dll; path = libopenmpt.dll; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BB2E75F2E40B1519719559F /* Load_far.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_far.cpp; path = ../../soundlib/Load_far.cpp; sourceTree = ""; }; + 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dsym.cpp; path = ../../soundlib/Load_dsym.cpp; sourceTree = ""; }; + 9BE4DE898CDC4C7BF8DFCCC9 /* libopenmpt_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_impl.hpp; path = ../../libopenmpt/libopenmpt_impl.hpp; sourceTree = ""; }; + 9C9696EDF3FC09DFA60A252D /* Echo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Echo.cpp; path = ../../soundlib/plugins/dmo/Echo.cpp; sourceTree = ""; }; + 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_fmt.cpp; path = ../../soundlib/Load_fmt.cpp; sourceTree = ""; }; + 9E091D790F2BBE6BC4F26BB9 /* IntMixer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IntMixer.h; path = ../../soundlib/IntMixer.h; sourceTree = ""; }; + 9E11C9D7F49F3449CD184817 /* DSP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DSP.h; path = ../../sounddsp/DSP.h; sourceTree = ""; }; + 9E737DF712CDC2E990B14C37 /* Distortion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Distortion.h; path = ../../soundlib/plugins/dmo/Distortion.h; sourceTree = ""; }; + 9E8AC865F88BDF57BFD2D6A5 /* tests_binary.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_binary.hpp; path = ../../src/mpt/binary/tests/tests_binary.hpp; sourceTree = ""; }; + 9EB0D073130B156590EE9EB3 /* Compressor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Compressor.h; path = ../../soundlib/plugins/dmo/Compressor.h; sourceTree = ""; }; + 9F187E69B9E4ED1BBDB584A9 /* outputfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = outputfile.hpp; path = ../../src/mpt/io_file/outputfile.hpp; sourceTree = ""; }; + 9FCB791A628BD98CBFC0B75A /* dos_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dos_memory.hpp; path = ../../src/mpt/osinfo/dos_memory.hpp; sourceTree = ""; }; + A0ADCD61E4FC72D32723ABA1 /* MPEGFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MPEGFrame.h; path = ../../soundlib/MPEGFrame.h; sourceTree = ""; }; + A105879DAD903A0F287505DD /* source_location.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = source_location.hpp; path = ../../src/mpt/base/source_location.hpp; sourceTree = ""; }; + A235F524F99B6816ABA98364 /* BuildSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BuildSettings.h; path = ../../common/BuildSettings.h; sourceTree = ""; }; + A2D7595A44C0F54C3BE8079A /* SymMODEcho.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SymMODEcho.h; path = ../../soundlib/plugins/SymMODEcho.h; sourceTree = ""; }; + A32EC1731056CFE511E9BFB3 /* ModSample.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModSample.cpp; path = ../../soundlib/ModSample.cpp; sourceTree = ""; }; + A33106C935BED0BB9E977509 /* load_j2b.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = load_j2b.cpp; path = ../../soundlib/load_j2b.cpp; sourceTree = ""; }; + A34959973B963F4969DD3FD7 /* filedata.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata.hpp; path = ../../src/mpt/io_read/filedata.hpp; sourceTree = ""; }; + A527626137B52C53A08DD0A1 /* int24.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = int24.hpp; path = ../../src/mpt/endian/int24.hpp; sourceTree = ""; }; + A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MIDIEvents.cpp; path = ../../soundlib/MIDIEvents.cpp; sourceTree = ""; }; + A7A09A55A16256C7DB615895 /* Paula.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Paula.cpp; path = ../../soundlib/Paula.cpp; sourceTree = ""; }; + A998D521CF40CF93ED715361 /* tests_string_transcode.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_string_transcode.hpp; path = ../../src/mpt/string_transcode/tests/tests_string_transcode.hpp; sourceTree = ""; }; + A9BD0A251CDE97177DA3D865 /* tests_base_saturate_round.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_base_saturate_round.hpp; path = ../../src/mpt/base/tests/tests_base_saturate_round.hpp; sourceTree = ""; }; + AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = I3DL2Reverb.cpp; path = ../../soundlib/plugins/dmo/I3DL2Reverb.cpp; sourceTree = ""; }; + AA79D3BB9E791D2D236431FB /* tests_uuid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_uuid.hpp; path = ../../src/mpt/uuid/tests/tests_uuid.hpp; sourceTree = ""; }; + AA915D236D51BD95CA869B63 /* AudioReadTarget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AudioReadTarget.h; path = ../../soundlib/AudioReadTarget.h; sourceTree = ""; }; + AB10601718386E8919CB5E57 /* version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = version.hpp; path = ../../src/mpt/base/version.hpp; sourceTree = ""; }; + AC5DD2341D807326D3472074 /* misc_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = misc_util.h; path = ../../common/misc_util.h; sourceTree = ""; }; + AED9469B1C01550D1D9444DB /* buffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = buffer.hpp; path = ../../src/mpt/string/buffer.hpp; sourceTree = ""; }; + AFFB10484288DA3AAB617E88 /* mptFileType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptFileType.h; path = ../../common/mptFileType.h; sourceTree = ""; }; + B05C5FEF07C1D2E1B9CFEE2F /* utility.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = utility.hpp; path = ../../src/mpt/string/utility.hpp; sourceTree = ""; }; + B0E5D2B80C27262ADF8170F8 /* io.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = io.hpp; path = ../../src/mpt/io/io.hpp; sourceTree = ""; }; + B176D8582299794AD8602698 /* mptTime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptTime.cpp; path = ../../common/mptTime.cpp; sourceTree = ""; }; + B30D8BC554F727B74C1E3A05 /* MixerInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerInterface.h; path = ../../soundlib/MixerInterface.h; sourceTree = ""; }; + B3975CD927F1A1CBA5D52B19 /* preprocessor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = preprocessor.hpp; path = ../../src/mpt/base/preprocessor.hpp; sourceTree = ""; }; + B3A14F450EE2A2B7E23CED85 /* OPL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OPL.cpp; path = ../../soundlib/OPL.cpp; sourceTree = ""; }; + B50C144B262EB53DDBF5628B /* Reverb.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Reverb.cpp; path = ../../sounddsp/Reverb.cpp; sourceTree = ""; }; + B517EB3DCFE459EFD3B4F17D /* exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = exception.hpp; path = ../../src/mpt/exception/exception.hpp; sourceTree = ""; }; + B5449C6B226CAADD23FF9AAB /* ModSequence.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModSequence.h; path = ../../soundlib/ModSequence.h; sourceTree = ""; }; + B547A5AF29A1EAA1A78573EF /* type_traits.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = type_traits.hpp; path = ../../src/mpt/endian/type_traits.hpp; sourceTree = ""; }; + B569F9F747F7C3E9B0D06837 /* Load_669.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_669.cpp; path = ../../soundlib/Load_669.cpp; sourceTree = ""; }; + B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MixerLoops.cpp; path = ../../soundlib/MixerLoops.cpp; sourceTree = ""; }; + B99E396D4C2C035FB504A7AD /* Load_c67.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_c67.cpp; path = ../../soundlib/Load_c67.cpp; sourceTree = ""; }; + B9B7FE84CBE1DB36FFD2C4C4 /* windows.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows.hpp; path = ../../src/mpt/check/windows.hpp; sourceTree = ""; }; + BA171099817BCB8B0C339ED9 /* tests_format_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_format_message.hpp; path = ../../src/mpt/format/tests/tests_format_message.hpp; sourceTree = ""; }; + BA5BA85780E99FC9EEEBC697 /* Flanger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Flanger.h; path = ../../soundlib/plugins/dmo/Flanger.h; sourceTree = ""; }; + BA99A2F415DAF666E9354134 /* mptCPU.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptCPU.h; path = ../../common/mptCPU.h; sourceTree = ""; }; + BAA825C62BCAC6B8E1917406 /* mptRandom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptRandom.h; path = ../../common/mptRandom.h; sourceTree = ""; }; + BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Sndfile.cpp; path = ../../soundlib/Sndfile.cpp; sourceTree = ""; }; + BBEF0B95B5B0C807EFAFC9D5 /* ITTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ITTools.h; path = ../../soundlib/ITTools.h; sourceTree = ""; }; + BD023BA1315C8093AF4009E1 /* simple_spec.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = simple_spec.hpp; path = ../../src/mpt/format/simple_spec.hpp; sourceTree = ""; }; + BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = MPEGFrame.cpp; path = ../../soundlib/MPEGFrame.cpp; sourceTree = ""; }; + BFC43D151B059087EE5FDB55 /* AGC.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AGC.cpp; path = ../../sounddsp/AGC.cpp; sourceTree = ""; }; + C0B331FD5340FBEFBC19A03D /* MixerLoops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MixerLoops.h; path = ../../soundlib/MixerLoops.h; sourceTree = ""; }; + C10B2BDD886FE6CF1327BA1D /* tests_endian_integer.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_endian_integer.hpp; path = ../../src/mpt/endian/tests/tests_endian_integer.hpp; sourceTree = ""; }; + C183253A1B843C2CE2CB337A /* system_error.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = system_error.hpp; path = ../../src/mpt/system_error/system_error.hpp; sourceTree = ""; }; + C34D6D67860DCDD9E342ABA7 /* libopenmpt_ext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_ext.h; path = ../../libopenmpt/libopenmpt_ext.h; sourceTree = ""; }; + C3E634155673FE07BF4CA255 /* macros.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = macros.hpp; path = ../../src/mpt/base/macros.hpp; sourceTree = ""; }; + C3FAC67D5688906FBF6134BD /* detect.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = detect.hpp; path = ../../src/mpt/base/detect.hpp; sourceTree = ""; }; + C510221C396A670EB74DF05C /* mptStringBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptStringBuffer.cpp; path = ../../common/mptStringBuffer.cpp; sourceTree = ""; }; + C6F2110A1E5783FCD0659F4A /* FileReaderFwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FileReaderFwd.h; path = ../../common/FileReaderFwd.h; sourceTree = ""; }; + C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UMXTools.cpp; path = ../../soundlib/UMXTools.cpp; sourceTree = ""; }; + C875E7BBB96D55AD2570D5FB /* floatingpoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = floatingpoint.hpp; path = ../../src/mpt/endian/floatingpoint.hpp; sourceTree = ""; }; + C885A07E2286B770E9CDAEBE /* windows_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = windows_version.hpp; path = ../../src/mpt/osinfo/windows_version.hpp; sourceTree = ""; }; + C950084F5BDDD241C4B6768F /* Load_sfx.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_sfx.cpp; path = ../../soundlib/Load_sfx.cpp; sourceTree = ""; }; + C9545B192355720BEA9C6959 /* arithmetic_shift.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = arithmetic_shift.hpp; path = ../../src/mpt/base/arithmetic_shift.hpp; sourceTree = ""; }; + C9DD180C21428AFED350A64C /* mptPathString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptPathString.h; path = ../../common/mptPathString.h; sourceTree = ""; }; + CA2995890E783AFB509F73C9 /* array.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = array.hpp; path = ../../src/mpt/base/array.hpp; sourceTree = ""; }; + CA67A8613B8A4953F150F6A1 /* S3MTools.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = S3MTools.h; path = ../../soundlib/S3MTools.h; sourceTree = ""; }; + CB4660EB0F95065D51BC3F2B /* pattern.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pattern.cpp; path = ../../soundlib/pattern.cpp; sourceTree = ""; }; + CB46E6335DD4B025C6AD5473 /* Load_667.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_667.cpp; path = ../../soundlib/Load_667.cpp; sourceTree = ""; }; + CB69F5BB3FC43AADBDA7C3FB /* patternContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = patternContainer.h; path = ../../soundlib/patternContainer.h; sourceTree = ""; }; + CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModInstrument.cpp; path = ../../soundlib/ModInstrument.cpp; sourceTree = ""; }; + CE0AB78B121E88BD05F00DCB /* fstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fstream.hpp; path = ../../src/mpt/io_file/fstream.hpp; sourceTree = ""; }; + CE271C83BB8EAF355888A2C3 /* filedata_stdstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_stdstream.hpp; path = ../../src/mpt/io_read/filedata_stdstream.hpp; sourceTree = ""; }; + CE32D5B4DABD882655A253F4 /* PluginManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PluginManager.cpp; path = ../../soundlib/plugins/PluginManager.cpp; sourceTree = ""; }; + CE6385639C86D91523952BA3 /* split.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = split.hpp; path = ../../src/mpt/parse/split.hpp; sourceTree = ""; }; + CEC583E195537B530355A221 /* ModSequence.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ModSequence.cpp; path = ../../soundlib/ModSequence.cpp; sourceTree = ""; }; + CF52BC181CB5B24A92D4B258 /* crc.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = crc.hpp; path = ../../src/mpt/crc/crc.hpp; sourceTree = ""; }; + CF8AA7E9C94C645B034B6629 /* dl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = dl.hpp; path = ../../src/mpt/detect/dl.hpp; sourceTree = ""; }; + D030DC83C9F298F503F19AC3 /* Sndfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Sndfile.h; path = ../../soundlib/Sndfile.h; sourceTree = ""; }; + D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DigiBoosterEcho.cpp; path = ../../soundlib/plugins/DigiBoosterEcho.cpp; sourceTree = ""; }; + D14936A73E714519400434E7 /* Load_digi.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_digi.cpp; path = ../../soundlib/Load_digi.cpp; sourceTree = ""; }; + D1D7F649CB99B2BB0598B489 /* bit.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = bit.hpp; path = ../../src/mpt/base/bit.hpp; sourceTree = ""; }; + D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatMediaFoundation.cpp; path = ../../soundlib/SampleFormatMediaFoundation.cpp; sourceTree = ""; }; + D35A7771C759C0E34C44D5B1 /* WavesReverb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WavesReverb.h; path = ../../soundlib/plugins/dmo/WavesReverb.h; sourceTree = ""; }; + D37D7529660B3F1BCEE3E369 /* MIDIMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MIDIMacros.h; path = ../../soundlib/MIDIMacros.h; sourceTree = ""; }; + D432AEE7E417DB19D08B6527 /* tests_parse.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = tests_parse.hpp; path = ../../src/mpt/parse/tests/tests_parse.hpp; sourceTree = ""; }; + D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LFOPlugin.cpp; path = ../../soundlib/plugins/LFOPlugin.cpp; sourceTree = ""; }; + D89E49F2E528FC64600DC832 /* PlugInterface.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = PlugInterface.cpp; path = ../../soundlib/plugins/PlugInterface.cpp; sourceTree = ""; }; + D941724BCA38E03D363C608B /* saturate_round.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = saturate_round.hpp; path = ../../src/mpt/base/saturate_round.hpp; sourceTree = ""; }; + DA41BBEFE6CC6E6161B13A2F /* transcode.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = transcode.hpp; path = ../../src/mpt/string_transcode/transcode.hpp; sourceTree = ""; }; + DAAB5DFD47D36C6F49665C3D /* WindowedFIR.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WindowedFIR.h; path = ../../soundlib/WindowedFIR.h; sourceTree = ""; }; + DC234F403388C232E596DD80 /* versionNumber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = versionNumber.h; path = ../../common/versionNumber.h; sourceTree = ""; }; + DC3C845FF708F311FAD98A9F /* filecursor.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor.hpp; path = ../../src/mpt/io_read/filecursor.hpp; sourceTree = ""; }; + DD3070EFE9BB2361649FEF2F /* default_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_string.hpp; path = ../../src/mpt/format/default_string.hpp; sourceTree = ""; }; + DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormats.cpp; path = ../../soundlib/SampleFormats.cpp; sourceTree = ""; }; + DFABF246C3F2FA7847E02886 /* sample.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = sample.hpp; path = ../../src/mpt/audio/sample.hpp; sourceTree = ""; }; + DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = tuningCollection.cpp; path = ../../soundlib/tuningCollection.cpp; sourceTree = ""; }; + E0244DAB72B2179DDB8ABBEB /* ModChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModChannel.h; path = ../../soundlib/ModChannel.h; sourceTree = ""; }; + E047D7E9F1FF17DB676D0629 /* default_formatter.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = default_formatter.hpp; path = ../../src/mpt/format/default_formatter.hpp; sourceTree = ""; }; + E0923A2DD491839F597C986D /* DMOPlugin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DMOPlugin.cpp; path = ../../soundlib/plugins/dmo/DMOPlugin.cpp; sourceTree = ""; }; + E0CF51E794CB6B19767DA827 /* filedata_callbackstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_callbackstream.hpp; path = ../../src/mpt/io_read/filedata_callbackstream.hpp; sourceTree = ""; }; + E2066CCD3D47C03F10A20B0D /* DSP.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DSP.cpp; path = ../../sounddsp/DSP.cpp; sourceTree = ""; }; + E276AB813DD6D033801A71C1 /* filedata_base_seekable.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filedata_base_seekable.hpp; path = ../../src/mpt/io_read/filedata_base_seekable.hpp; sourceTree = ""; }; + E2B3BCB34FDBCB25516EBAF3 /* random.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = random.hpp; path = ../../src/mpt/random/random.hpp; sourceTree = ""; }; + E438935FD53001514133819F /* mod_specifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mod_specifications.h; path = ../../soundlib/mod_specifications.h; sourceTree = ""; }; + E4C0ABA9F677EB9B6BE5D9E9 /* libopenmpt_ext_impl.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_ext_impl.hpp; path = ../../libopenmpt/libopenmpt_ext_impl.hpp; sourceTree = ""; }; + E59C6F4DDF5E2BBF195D2D8D /* Loaders.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Loaders.h; path = ../../soundlib/Loaders.h; sourceTree = ""; }; + E64FF33AA9BBB4ECE85F597A /* openmpt-ogg.lib */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "ogg.xcodeproj"; path = ext/ogg.xcodeproj; sourceTree = SOURCE_ROOT; }; + E6905433791E1E25E1F6C273 /* SampleCopy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SampleCopy.h; path = ../../soundlib/SampleCopy.h; sourceTree = ""; }; + E7811C8A7A0EE67CE2E78ACA /* class.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = class.hpp; path = ../../src/mpt/osinfo/class.hpp; sourceTree = ""; }; + E898D5ABAF26CD1D1D28F3EB /* ModInstrument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ModInstrument.h; path = ../../soundlib/ModInstrument.h; sourceTree = ""; }; + EABA2F1F4147999119C0AD5F /* AGC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AGC.h; path = ../../sounddsp/AGC.h; sourceTree = ""; }; + EC1456C17EA220B3E77AC501 /* Load_mid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_mid.cpp; path = ../../soundlib/Load_mid.cpp; sourceTree = ""; }; + ED3DBD7D7FCB876FE8A42BBD /* memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = memory.hpp; path = ../../src/mpt/base/memory.hpp; sourceTree = ""; }; + EEC8D9B98156A3ABEA2F47F9 /* tuningbase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuningbase.h; path = ../../soundlib/tuningbase.h; sourceTree = ""; }; + EF78F5224ABA48941E149362 /* Dither.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Dither.h; path = ../../common/Dither.h; sourceTree = ""; }; + F06C78E982FA42DBEBD2E729 /* RowVisitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RowVisitor.h; path = ../../soundlib/RowVisitor.h; sourceTree = ""; }; + F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_psm.cpp; path = ../../soundlib/Load_psm.cpp; sourceTree = ""; }; + F18CD1F1E58C1B636A773031 /* saturate_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = saturate_cast.hpp; path = ../../src/mpt/base/saturate_cast.hpp; sourceTree = ""; }; + F19C0735EB5DC3A7255CC575 /* pattern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pattern.h; path = ../../soundlib/pattern.h; sourceTree = ""; }; + F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SoundFilePlayConfig.cpp; path = ../../soundlib/SoundFilePlayConfig.cpp; sourceTree = ""; }; + F1E743CB3635E93D785D220B /* OggStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OggStream.h; path = ../../soundlib/OggStream.h; sourceTree = ""; }; + F1F533090CC1A1BB10923949 /* filereader.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filereader.hpp; path = ../../src/mpt/io_read/filereader.hpp; sourceTree = ""; }; + F244B139942E4D2B8B555F79 /* basic_path.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = basic_path.hpp; path = ../../src/mpt/path/basic_path.hpp; sourceTree = ""; }; + F42AAB0986B874FBEF911949 /* MIDIEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MIDIEvents.h; path = ../../soundlib/MIDIEvents.h; sourceTree = ""; }; + F4775C614BDCCF53FDEAEAA1 /* Chorus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Chorus.h; path = ../../soundlib/plugins/dmo/Chorus.h; sourceTree = ""; }; + F48DAABB97F4D86DAF2A90FB /* filecursor_traits_memory.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_traits_memory.hpp; path = ../../src/mpt/io_read/filecursor_traits_memory.hpp; sourceTree = ""; }; + F5D2F247BC60E9B92A631087 /* libopenmpt.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt.hpp; path = ../../libopenmpt/libopenmpt.hpp; sourceTree = ""; }; + F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Load_dsm.cpp; path = ../../soundlib/Load_dsm.cpp; sourceTree = ""; }; + F61229996734CA8B1CFB77D9 /* guid.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = guid.hpp; path = ../../src/mpt/uuid/guid.hpp; sourceTree = ""; }; + F6F37E8F68161F811DDCCCCF /* span.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = span.hpp; path = ../../src/mpt/base/span.hpp; sourceTree = ""; }; + F78A378464B245F6664535C4 /* mptBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mptBaseTypes.h; path = ../../common/mptBaseTypes.h; sourceTree = ""; }; + F7B5558991D94ABB41FF2BC9 /* fileadapter.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = fileadapter.hpp; path = ../../src/mpt/io_file_adapter/fileadapter.hpp; sourceTree = ""; }; + F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFormatFLAC.cpp; path = ../../soundlib/SampleFormatFLAC.cpp; sourceTree = ""; }; + FB5FB0E7EF5EFA59744A0F27 /* libopenmpt_ext.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = libopenmpt_ext.hpp; path = ../../libopenmpt/libopenmpt_ext.hpp; sourceTree = ""; }; + FB635E3D352E14EFEA89647D /* filecursor_traits_filedata.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = filecursor_traits_filedata.hpp; path = ../../src/mpt/io_read/filecursor_traits_filedata.hpp; sourceTree = ""; }; + FBE197BEECD905B058DC85FE /* serialization_utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = serialization_utils.h; path = ../../common/serialization_utils.h; sourceTree = ""; }; + FBF22E79CF82B5EBC2544CB9 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libopenmpt_stream_callbacks_file_posix_lfs64.h; path = ../../libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h; sourceTree = ""; }; + FC85D407DBA2EE39B7AC4A47 /* inputfile.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = inputfile.hpp; path = ../../src/mpt/io_file/inputfile.hpp; sourceTree = ""; }; + FED01DA32FB4159542CC4BE3 /* tuning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = tuning.h; path = ../../soundlib/tuning.h; sourceTree = ""; }; + FEDB3A1791690409FA41A857 /* Echo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Echo.h; path = ../../soundlib/plugins/dmo/Echo.h; sourceTree = ""; }; + FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mptFileTemporary.cpp; path = ../../common/mptFileTemporary.cpp; sourceTree = ""; }; + FFB3088F4401AE018628E6CF /* Resampler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Resampler.h; path = ../../soundlib/Resampler.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 74A5BE3DE630D6AF9531FC7D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 70AEC26880FBA65A7EE870A8 /* openmpt-mpg123.lib in Frameworks */, + A5815DFEB5CE41F0B3BB0C3E /* openmpt-vorbis.lib in Frameworks */, + 2837D1CEECED2840A15BD00E /* openmpt-ogg.lib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0AD991E90B8C8EDB7F6E6029 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXGroup section */ + 02978A9119AA25C309C620D1 /* detect */ = { + isa = PBXGroup; + children = ( + CF8AA7E9C94C645B034B6629 /* dl.hpp */, + 4DFC0969924AAEDBD471E7A9 /* ltdl.hpp */, + 5178AA15C29B4B077861F855 /* mfc.hpp */, + 3C628FD12D59FDC3995D7E11 /* nlohmann_json.hpp */, + ); + name = detect; + sourceTree = ""; + }; + 0317FD4359A567B5321E7B83 /* tests */ = { + isa = PBXGroup; + children = ( + 9620F5BDA843ABAF8144E3FD /* tests_endian_floatingpoint.hpp */, + 55EF6B83EC187D75AD7ED9C3 /* tests_endian_int24.hpp */, + C10B2BDD886FE6CF1327BA1D /* tests_endian_integer.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 06E88D9CF1D4B38E39BA7BDC /* Products */ = { + isa = PBXGroup; + children = ( + 91C69AB0393C3662E20140F0 /* openmpt-mpg123.lib */, + ); + name = Products; + sourceTree = ""; + }; + 1063AA8FB3AF33C1CE8000CF /* io */ = { + isa = PBXGroup; + children = ( + 793E301E72FFEC90ACFEEE5E /* base.hpp */, + B0E5D2B80C27262ADF8170F8 /* io.hpp */, + 632A109AF5B7DA8C5E907EDA /* io_span.hpp */, + 06C40A24C9846A9626B94864 /* io_stdstream.hpp */, + 949CE444733F7FB628218284 /* io_virtual_wrapper.hpp */, + 4B6DA50C44D3A67E386F034C /* tests */, + ); + name = io; + sourceTree = ""; + }; + 11F2BC8C3818EC3E9F1FE2CC /* tests */ = { + isa = PBXGroup; + children = ( + 7D6EAF1E983B1DD09C0BB55E /* tests_crc.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 1B3CA80DE95FFBBF706E4E4D /* io_file_adapter */ = { + isa = PBXGroup; + children = ( + F7B5558991D94ABB41FF2BC9 /* fileadapter.hpp */, + ); + name = io_file_adapter; + sourceTree = ""; + }; + 2AB619BD41C8B4EF31E4AFFD /* endian */ = { + isa = PBXGroup; + children = ( + C875E7BBB96D55AD2570D5FB /* floatingpoint.hpp */, + A527626137B52C53A08DD0A1 /* int24.hpp */, + 3CC72D5B942CA04D463ABB9B /* integer.hpp */, + 0317FD4359A567B5321E7B83 /* tests */, + B547A5AF29A1EAA1A78573EF /* type_traits.hpp */, + ); + name = endian; + sourceTree = ""; + }; + 30779B89F3E35D3B328701C9 /* environment */ = { + isa = PBXGroup; + children = ( + 6E84090F7E6935416ADCBF4F /* environment.hpp */, + ); + name = environment; + sourceTree = ""; + }; + 31DC889B1CC8AE8D64AE76DB /* plugins */ = { + isa = PBXGroup; + children = ( + D078EDD4AF1B894663FD8C14 /* DigiBoosterEcho.cpp */, + 45D0E0DE525B9350CD405F1E /* DigiBoosterEcho.h */, + D6BBDE00997C3E72F6B11C40 /* LFOPlugin.cpp */, + 6858F8CA2EE6F03C9CE9170A /* LFOPlugin.h */, + 9133E604FE5BF476FFEEE444 /* OpCodes.h */, + D89E49F2E528FC64600DC832 /* PlugInterface.cpp */, + 6058487C545791EED942A6BC /* PlugInterface.h */, + CE32D5B4DABD882655A253F4 /* PluginManager.cpp */, + 159B6F7E099AB8F08E85CDBE /* PluginManager.h */, + 09387CD815C32F4A90A7FB18 /* PluginMixBuffer.h */, + 46877D383A86C6AABF71DB78 /* PluginStructs.h */, + 4738D7F0BB931CE23976A630 /* SymMODEcho.cpp */, + A2D7595A44C0F54C3BE8079A /* SymMODEcho.h */, + 47207888320C9E7A79F266C8 /* dmo */, + ); + name = plugins; + sourceTree = ""; + }; + 3C7CE88D62A3183FC9AA0ECD /* io_file */ = { + isa = PBXGroup; + children = ( + 22594181666D12B35A3E97C1 /* fileref.hpp */, + CE0AB78B121E88BD05F00DCB /* fstream.hpp */, + FC85D407DBA2EE39B7AC4A47 /* inputfile.hpp */, + 9F187E69B9E4ED1BBDB584A9 /* outputfile.hpp */, + ); + name = io_file; + sourceTree = ""; + }; + 42C3CDB59951382771CA4BF5 /* tests */ = { + isa = PBXGroup; + children = ( + 37064A799107616B584E58B9 /* tests_random.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 47207888320C9E7A79F266C8 /* dmo */ = { + isa = PBXGroup; + children = ( + 84A787B7269123A91DB835F7 /* Chorus.cpp */, + F4775C614BDCCF53FDEAEAA1 /* Chorus.h */, + 9334A009842C0DFBF02F8E49 /* Compressor.cpp */, + 9EB0D073130B156590EE9EB3 /* Compressor.h */, + E0923A2DD491839F597C986D /* DMOPlugin.cpp */, + 04EAEC77C7AB4CE924E02AB7 /* DMOPlugin.h */, + 664DAA91DAA7EF83588B78D1 /* DMOUtils.cpp */, + 73262ABB150FC6AD0C36D8FB /* DMOUtils.h */, + 0199EF0DF2915CFF5E94DD4D /* Distortion.cpp */, + 9E737DF712CDC2E990B14C37 /* Distortion.h */, + 9C9696EDF3FC09DFA60A252D /* Echo.cpp */, + FEDB3A1791690409FA41A857 /* Echo.h */, + 3286C74DF54727BF527C058D /* Flanger.cpp */, + BA5BA85780E99FC9EEEBC697 /* Flanger.h */, + 78BD15B31AA6B1A511CDC3F3 /* Gargle.cpp */, + 6B9C8BDDC301FECF75101A1D /* Gargle.h */, + AA3E0E57B6C8C0C931AD8C97 /* I3DL2Reverb.cpp */, + 91AA522185A99B930A94B061 /* I3DL2Reverb.h */, + 8C3D549D4EFDB50FAC3292DD /* ParamEq.cpp */, + 9B1917A761A70F19CFA935E7 /* ParamEq.h */, + 7E0A11A78A94C41905798FE7 /* WavesReverb.cpp */, + D35A7771C759C0E34C44D5B1 /* WavesReverb.h */, + ); + name = dmo; + sourceTree = ""; + }; + 477F53A3EA6D7A55799359E3 /* audio */ = { + isa = PBXGroup; + children = ( + DFABF246C3F2FA7847E02886 /* sample.hpp */, + 55356226EAAC215859487866 /* span.hpp */, + ); + name = audio; + sourceTree = ""; + }; + 4B6DA50C44D3A67E386F034C /* tests */ = { + isa = PBXGroup; + children = ( + 2E1DD07ED0076C70C72E7EBE /* tests_io.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 4DC01D3DA44D87AF7CC69B7D /* tests */ = { + isa = PBXGroup; + children = ( + BA171099817BCB8B0C339ED9 /* tests_format_message.hpp */, + 8EA1F2E35357495507C5F123 /* tests_format_simple.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 4ECA2D3165DCC86355F8C371 /* format */ = { + isa = PBXGroup; + children = ( + 68FC5709D624657BD7B75549 /* concat.hpp */, + 80F9D5FD1722E7EFD889443D /* default_floatingpoint.hpp */, + E047D7E9F1FF17DB676D0629 /* default_formatter.hpp */, + 7159D71DCB5AEE0F92A1E55D /* default_integer.hpp */, + DD3070EFE9BB2361649FEF2F /* default_string.hpp */, + 721CEF1FC98262117B907D5F /* helpers.hpp */, + 3A4473F97E93196BC0BA5239 /* join.hpp */, + 915D6003E8C2D2F59AD0EE43 /* message.hpp */, + 80C993CB8D54463D0839120B /* message_macros.hpp */, + 1E7AA06D8BA2AEDF8D359EAD /* simple.hpp */, + 8CA9A5C72521933951088407 /* simple_floatingpoint.hpp */, + 5E8119A76B0BCC19E5F097E7 /* simple_integer.hpp */, + BD023BA1315C8093AF4009E1 /* simple_spec.hpp */, + 4DC01D3DA44D87AF7CC69B7D /* tests */, + ); + name = format; + sourceTree = ""; + }; + 5288703955F9426BD765E679 /* path */ = { + isa = PBXGroup; + children = ( + F244B139942E4D2B8B555F79 /* basic_path.hpp */, + 178BC3E3DA4C245537810223 /* native_path.hpp */, + 50318A59BD5998CBBEEC8899 /* os_path.hpp */, + 85A36D37F9FDB22977E13B77 /* os_path_long.hpp */, + 7C2DCED7ED506FC9A3171D17 /* path.hpp */, + ); + name = path; + sourceTree = ""; + }; + 54C514A39D35F8D5E1D4CAE3 /* io_write */ = { + isa = PBXGroup; + children = ( + 01230426588877180A969266 /* buffer.hpp */, + ); + name = io_write; + sourceTree = ""; + }; + 5691D14D5A02A37FDB6F478D /* uuid */ = { + isa = PBXGroup; + children = ( + F61229996734CA8B1CFB77D9 /* guid.hpp */, + B62CF44BA1191A3DE8FEE28B /* tests */, + 40C5E675B1E8876767AF34B5 /* uuid.hpp */, + ); + name = uuid; + sourceTree = ""; + }; + 570A99913B51A1C3BF3ECFD1 /* string_transcode */ = { + isa = PBXGroup; + children = ( + 8A87EA73FEE22F657CC5B8B3 /* macros.hpp */, + ADB520ED1ED7C1DFD49E6F2D /* tests */, + DA41BBEFE6CC6E6161B13A2F /* transcode.hpp */, + ); + name = string_transcode; + sourceTree = ""; + }; + 5775D4184366DFCA959E7A58 /* src */ = { + isa = PBXGroup; + children = ( + 88A413A1D8B7A8535B35D9E1 /* mpt */, + ); + name = src; + sourceTree = ""; + }; + 59D7B3BB70EA4EED610649FB /* osinfo */ = { + isa = PBXGroup; + children = ( + E7811C8A7A0EE67CE2E78ACA /* class.hpp */, + 9FCB791A628BD98CBFC0B75A /* dos_memory.hpp */, + 0F8105B483DB4AA601BED3F4 /* dos_version.hpp */, + C885A07E2286B770E9CDAEBE /* windows_version.hpp */, + 92AB21E22B230F54570A0022 /* windows_wine_version.hpp */, + ); + name = osinfo; + sourceTree = ""; + }; + 5D4AB94D745D547F64794F8D /* string */ = { + isa = PBXGroup; + children = ( + AED9469B1C01550D1D9444DB /* buffer.hpp */, + 9602920BEC8FFC7DC509104B /* tests */, + 4E96BB31E124852349FD2971 /* types.hpp */, + B05C5FEF07C1D2E1B9CFEE2F /* utility.hpp */, + ); + name = string; + sourceTree = ""; + }; + 63D3103B06C136ED95E7167B /* check */ = { + isa = PBXGroup; + children = ( + 64377F84A84B50B69C1CD5C4 /* compiler.hpp */, + 417FE082D6F69FB44592F6C2 /* libc.hpp */, + 788395FAAA7CE0AC245C1C3A /* mfc.hpp */, + B9B7FE84CBE1DB36FFD2C4C4 /* windows.hpp */, + ); + name = check; + sourceTree = ""; + }; + 651C6428688D365AE9F9DA68 /* sounddsp */ = { + isa = PBXGroup; + children = ( + BFC43D151B059087EE5FDB55 /* AGC.cpp */, + EABA2F1F4147999119C0AD5F /* AGC.h */, + E2066CCD3D47C03F10A20B0D /* DSP.cpp */, + 9E11C9D7F49F3449CD184817 /* DSP.h */, + 04D4FEEB3466CDDD0F740D2B /* EQ.cpp */, + 73A52C155E915207A6771A55 /* EQ.h */, + B50C144B262EB53DDBF5628B /* Reverb.cpp */, + 57E617F588CA0FE79BE24635 /* Reverb.h */, + ); + name = sounddsp; + sourceTree = ""; + }; + 7EC25859D54FC2CBADC8D699 /* tests */ = { + isa = PBXGroup; + children = ( + 9E8AC865F88BDF57BFD2D6A5 /* tests_binary.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 80C578BF97D813F187F40EFF /* Products */ = { + isa = PBXGroup; + children = ( + 5DFCA7B6A69BE5E8C9C79DF6 /* openmpt-ogg.lib */, + ); + name = Products; + sourceTree = ""; + }; + 83E18D7BD14483AD476383BB /* system_error */ = { + isa = PBXGroup; + children = ( + C183253A1B843C2CE2CB337A /* system_error.hpp */, + ); + name = system_error; + sourceTree = ""; + }; + 88A413A1D8B7A8535B35D9E1 /* mpt */ = { + isa = PBXGroup; + children = ( + FE13EC1B0184BE4D82F1625B /* arch */, + 477F53A3EA6D7A55799359E3 /* audio */, + ADCB9F55B13C718732A91595 /* base */, + B88D0869CF9FA39BBFBB9EA9 /* binary */, + 63D3103B06C136ED95E7167B /* check */, + A3AF43EF4801E1A15A3A2A2F /* crc */, + 02978A9119AA25C309C620D1 /* detect */, + 2AB619BD41C8B4EF31E4AFFD /* endian */, + 30779B89F3E35D3B328701C9 /* environment */, + CA56FDBDF291B66FDA2D43FD /* exception */, + 4ECA2D3165DCC86355F8C371 /* format */, + 1063AA8FB3AF33C1CE8000CF /* io */, + 3C7CE88D62A3183FC9AA0ECD /* io_file */, + 1B3CA80DE95FFBBF706E4E4D /* io_file_adapter */, + B9911C4306F412757D131283 /* io_file_read */, + C86808B95DDEC7EBCC7B1EF9 /* io_file_unique */, + FB1C5B4521428AF788498185 /* io_read */, + 54C514A39D35F8D5E1D4CAE3 /* io_write */, + 8FB69E0532A4C4B7C1CAA445 /* mutex */, + 59D7B3BB70EA4EED610649FB /* osinfo */, + CF94F547018E3FF97B6D7B87 /* out_of_memory */, + EB3711558E2538071D4B1795 /* parse */, + 5288703955F9426BD765E679 /* path */, + F76908210E7BA353FE979E61 /* random */, + 5D4AB94D745D547F64794F8D /* string */, + 570A99913B51A1C3BF3ECFD1 /* string_transcode */, + 83E18D7BD14483AD476383BB /* system_error */, + 5691D14D5A02A37FDB6F478D /* uuid */, + ); + name = mpt; + sourceTree = ""; + }; + 8BDA4A4F76C67041BEAC388F /* tests */ = { + isa = PBXGroup; + children = ( + 4D1485535F373B4538387393 /* tests_base_arithmetic_shift.hpp */, + 44E6E1C323897D35D86B8003 /* tests_base_bit.hpp */, + 6C67B7D97E1EF7CBF38CE619 /* tests_base_math.hpp */, + 32BAAF6B89D057DDB618EDAB /* tests_base_saturate_cast.hpp */, + A9BD0A251CDE97177DA3D865 /* tests_base_saturate_round.hpp */, + 82EA4C5D44A2DDCFEBBDAA9D /* tests_base_wrapping_divide.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 8FB69E0532A4C4B7C1CAA445 /* mutex */ = { + isa = PBXGroup; + children = ( + 8ABF23E958E2779BDFF0CA29 /* mutex.hpp */, + ); + name = mutex; + sourceTree = ""; + }; + 9320911A7F119CCCD149375A /* libopenmpt */ = { + isa = PBXGroup; + children = ( + 9660399A39ABC2CC547C8FDA /* common */, + C5150E7CDC27A9AECC43A4BC /* libopenmpt */, + 651C6428688D365AE9F9DA68 /* sounddsp */, + E6A8DD88EA19AFBA6B8653C8 /* soundlib */, + 5775D4184366DFCA959E7A58 /* src */, + A6C936B49B3FADE6EA134CF4 /* Products */, + 9D968EAA920D05DCE0E0A4EA /* Projects */, + ); + name = libopenmpt; + sourceTree = ""; + }; + 9602920BEC8FFC7DC509104B /* tests */ = { + isa = PBXGroup; + children = ( + 995821ED5E0D785F127C202D /* tests_string_buffer.hpp */, + 07580841CEBCC33359749681 /* tests_string_utility.hpp */, + ); + name = tests; + sourceTree = ""; + }; + 9660399A39ABC2CC547C8FDA /* common */ = { + isa = PBXGroup; + children = ( + A235F524F99B6816ABA98364 /* BuildSettings.h */, + 13F9789407F8C2068CE3D6D4 /* ComponentManager.cpp */, + 0A20B0FECCE111702A15EF3E /* ComponentManager.h */, + EF78F5224ABA48941E149362 /* Dither.h */, + 6D2350A8B171F61AF3992EE8 /* FileReader.h */, + C6F2110A1E5783FCD0659F4A /* FileReaderFwd.h */, + 830F3566F431D658A9F883A6 /* Logging.cpp */, + 6303157093E70D62A6FF43B0 /* Logging.h */, + 8F52A05ED3A145D015C87E9E /* Profiler.cpp */, + 94CA18088E8BD47AC88AD648 /* Profiler.h */, + AC5DD2341D807326D3472074 /* misc_util.h */, + 74D96CA8E5FC0D9A9BC2BAE8 /* mptAssert.h */, + 66CA3B04BE2FADF6703DC944 /* mptBaseMacros.h */, + F78A378464B245F6664535C4 /* mptBaseTypes.h */, + 12DCF57C800503EE8197F3BC /* mptBaseUtils.h */, + BA99A2F415DAF666E9354134 /* mptCPU.h */, + 13F63AEAA68404DC0F5CA92A /* mptFileIO.cpp */, + 50CF7EB4C1F21FA677B8CCF4 /* mptFileIO.h */, + FF7F8F60F37ED8D27869EDA0 /* mptFileTemporary.cpp */, + 43CBFB4A068C5BBC63C1398A /* mptFileTemporary.h */, + 074C76BE5EB1E9B010C004FE /* mptFileType.cpp */, + AFFB10484288DA3AAB617E88 /* mptFileType.h */, + 4B406AC2ED2A06B4E4511902 /* mptPathString.cpp */, + C9DD180C21428AFED350A64C /* mptPathString.h */, + 5D6A74BCEFF83EAE58D0E2FC /* mptRandom.cpp */, + BAA825C62BCAC6B8E1917406 /* mptRandom.h */, + 4AECD572BC0F766471D623B2 /* mptString.h */, + C510221C396A670EB74DF05C /* mptStringBuffer.cpp */, + 90E45EE632CDFAD829F50D26 /* mptStringBuffer.h */, + 1A94BBC4BC7E57B6B3A56A04 /* mptStringFormat.h */, + B176D8582299794AD8602698 /* mptTime.cpp */, + 8DF141A2BED53994D1ED6FE2 /* mptTime.h */, + 96E89174F0E9A866B8309FB4 /* serialization_utils.cpp */, + FBE197BEECD905B058DC85FE /* serialization_utils.h */, + 6AF57E36C636D1A899911C76 /* stdafx.h */, + 3E2FDF24AF52801665192D64 /* version.cpp */, + 7523D3EEA607CBE0B920022E /* version.h */, + DC234F403388C232E596DD80 /* versionNumber.h */, + ); + name = common; + sourceTree = ""; + }; + 9D968EAA920D05DCE0E0A4EA /* Projects */ = { + isa = PBXGroup; + children = ( + 04155894998C17C608286ED4 /* mpg123.xcodeproj */, + 41BBEA4AD732A97C45CF008A /* vorbis.xcodeproj */, + E64FF33AA9BBB4ECE85F597A /* ogg.xcodeproj */, + ); + name = Projects; + sourceTree = ""; + }; + A3AF43EF4801E1A15A3A2A2F /* crc */ = { + isa = PBXGroup; + children = ( + CF52BC181CB5B24A92D4B258 /* crc.hpp */, + 11F2BC8C3818EC3E9F1FE2CC /* tests */, + ); + name = crc; + sourceTree = ""; + }; + A6C936B49B3FADE6EA134CF4 /* Products */ = { + isa = PBXGroup; + children = ( + 9B95674D94FB68BF8896C58D /* libopenmpt.dll */, + ); + name = Products; + sourceTree = ""; + }; + ADB520ED1ED7C1DFD49E6F2D /* tests */ = { + isa = PBXGroup; + children = ( + A998D521CF40CF93ED715361 /* tests_string_transcode.hpp */, + ); + name = tests; + sourceTree = ""; + }; + ADCB9F55B13C718732A91595 /* base */ = { + isa = PBXGroup; + children = ( + 54F2D0191B80C78B8982EE59 /* algorithm.hpp */, + 15A918AF09A862218E9376EF /* aligned_array.hpp */, + 1679D9615AC87ED39CEFB7A1 /* alloc.hpp */, + C9545B192355720BEA9C6959 /* arithmetic_shift.hpp */, + CA2995890E783AFB509F73C9 /* array.hpp */, + D1D7F649CB99B2BB0598B489 /* bit.hpp */, + 1AA25C6F0B99CA61779D4AAF /* check_platform.hpp */, + 86260AE5E2AD0F576B4FC925 /* compiletime_warning.hpp */, + 021DA33D0EA855AF898D217D /* constexpr_throw.hpp */, + C3FAC67D5688906FBF6134BD /* detect.hpp */, + 1C2F81B7DEEFE2293C24BFF7 /* detect_arch.hpp */, + 321030713E9AE2E3B97FAEB1 /* detect_compiler.hpp */, + 17F58A2FDAB5EAA137EAC86F /* detect_libc.hpp */, + 755174CF6950BE41EE3BD30F /* detect_libcxx.hpp */, + 175234BFDDE02C314BE252FF /* detect_os.hpp */, + 107683B90475CD2B8960E1F9 /* detect_quirks.hpp */, + 4FB7A50743B6EE79C8A20347 /* floatingpoint.hpp */, + 787945A7E5A15419E73443E7 /* integer.hpp */, + C3E634155673FE07BF4CA255 /* macros.hpp */, + 4614D43FB73775316CFE227F /* math.hpp */, + ED3DBD7D7FCB876FE8A42BBD /* memory.hpp */, + 3AC37DA5015175176F539BE5 /* namespace.hpp */, + 209166838DB974F58F4C64C3 /* numbers.hpp */, + 046F30B171973F23732A2EF1 /* numeric.hpp */, + 5AF83E8DC8204CFFC9B33CCD /* pointer.hpp */, + B3975CD927F1A1CBA5D52B19 /* preprocessor.hpp */, + F18CD1F1E58C1B636A773031 /* saturate_cast.hpp */, + D941724BCA38E03D363C608B /* saturate_round.hpp */, + 85812219180EEC0B80E79059 /* secure.hpp */, + 212A36FD7B2B4DEF4272453D /* semantic_version.hpp */, + A105879DAD903A0F287505DD /* source_location.hpp */, + F6F37E8F68161F811DDCCCCF /* span.hpp */, + 8BDA4A4F76C67041BEAC388F /* tests */, + 5609DBF3C331EA65C4C4DA33 /* utility.hpp */, + AB10601718386E8919CB5E57 /* version.hpp */, + 2C28EA4338B39CB5B3986883 /* wrapping_divide.hpp */, + ); + name = base; + sourceTree = ""; + }; + B62CF44BA1191A3DE8FEE28B /* tests */ = { + isa = PBXGroup; + children = ( + AA79D3BB9E791D2D236431FB /* tests_uuid.hpp */, + ); + name = tests; + sourceTree = ""; + }; + B88D0869CF9FA39BBFBB9EA9 /* binary */ = { + isa = PBXGroup; + children = ( + 8856685FF57E76D1F711669F /* base64.hpp */, + 51EB7985F3D51577EAFC27C5 /* base64url.hpp */, + 2E2F32DF9F51D3D15518811F /* hex.hpp */, + 7EC25859D54FC2CBADC8D699 /* tests */, + ); + name = binary; + sourceTree = ""; + }; + B9911C4306F412757D131283 /* io_file_read */ = { + isa = PBXGroup; + children = ( + 36619CBCFDC657AE887E2AFC /* inputfile_filecursor.hpp */, + ); + name = io_file_read; + sourceTree = ""; + }; + C5150E7CDC27A9AECC43A4BC /* libopenmpt */ = { + isa = PBXGroup; + children = ( + 41DFAAC7AF07B939B09AA907 /* libopenmpt.h */, + F5D2F247BC60E9B92A631087 /* libopenmpt.hpp */, + 352908E1F7E96953551E4721 /* libopenmpt_c.cpp */, + 43B7419134AEAF83A0B22FD1 /* libopenmpt_config.h */, + 597941C14D788B33D263A001 /* libopenmpt_cxx.cpp */, + C34D6D67860DCDD9E342ABA7 /* libopenmpt_ext.h */, + FB5FB0E7EF5EFA59744A0F27 /* libopenmpt_ext.hpp */, + 7355A89F850CE891FA7AD6DF /* libopenmpt_ext_impl.cpp */, + E4C0ABA9F677EB9B6BE5D9E9 /* libopenmpt_ext_impl.hpp */, + 7F22B5FF701A23F1DC1DA43F /* libopenmpt_impl.cpp */, + 9BE4DE898CDC4C7BF8DFCCC9 /* libopenmpt_impl.hpp */, + 7154B71FCB55CE11929CC55F /* libopenmpt_internal.h */, + 01D708ED277F035F45AF872D /* libopenmpt_stream_callbacks_buffer.h */, + 3AADECCD91C3953FBE0C2B0D /* libopenmpt_stream_callbacks_fd.h */, + 91EC613953A4F2ABFABFBF79 /* libopenmpt_stream_callbacks_file.h */, + 3EEBB71B8158038D397E755B /* libopenmpt_stream_callbacks_file_mingw.h */, + 70644035FF1571275A9F8E75 /* libopenmpt_stream_callbacks_file_msvcrt.h */, + 8BE3D4DDCE50214F8676931D /* libopenmpt_stream_callbacks_file_posix.h */, + FBF22E79CF82B5EBC2544CB9 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */, + 0FDA8FB11C654223974A0DF1 /* libopenmpt_version.h */, + ); + name = libopenmpt; + sourceTree = ""; + }; + C86808B95DDEC7EBCC7B1EF9 /* io_file_unique */ = { + isa = PBXGroup; + children = ( + 25EAC3A1C044AC93FC7D11E1 /* unique_basename.hpp */, + 9469EF975BCEAA89E6867DD7 /* unique_tempfilename.hpp */, + ); + name = io_file_unique; + sourceTree = ""; + }; + CA56FDBDF291B66FDA2D43FD /* exception */ = { + isa = PBXGroup; + children = ( + B517EB3DCFE459EFD3B4F17D /* exception.hpp */, + 41BBBCC5DBDFB1F78C059305 /* exception_text.hpp */, + 4CDD73CDC0C5EB7FE3139A0D /* logic_error.hpp */, + 75EFCB7913D0CC2BEB4F11B9 /* runtime_error.hpp */, + ); + name = exception; + sourceTree = ""; + }; + CAFA4717B5E66D09FDCC3557 /* Products */ = { + isa = PBXGroup; + children = ( + E7CD47E68F42E3983807EE26 /* openmpt-vorbis.lib */, + ); + name = Products; + sourceTree = ""; + }; + CF94F547018E3FF97B6D7B87 /* out_of_memory */ = { + isa = PBXGroup; + children = ( + 406A557CF3605F2E4482BBBC /* out_of_memory.hpp */, + ); + name = out_of_memory; + sourceTree = ""; + }; + E6A8DD88EA19AFBA6B8653C8 /* soundlib */ = { + isa = PBXGroup; + children = ( + 3947FF534AFF3F45C06D2D93 /* AudioCriticalSection.cpp */, + 87A62ABDE1A741AFA8EE38FD /* AudioCriticalSection.h */, + AA915D236D51BD95CA869B63 /* AudioReadTarget.h */, + 338C775D77DB1CCFBA02559D /* BitReader.h */, + 3F5591FF83A43771C5CB703F /* Container.h */, + 124C374986A67C3B048A0589 /* ContainerMMCMP.cpp */, + 38019939FAC1F9AB57F6D779 /* ContainerPP20.cpp */, + 25972C49C780C83BBEA7DA89 /* ContainerUMX.cpp */, + 0BC4F1DBADAE8DCDA4D5A01B /* ContainerXPK.cpp */, + 55C6E46D9A1589DFDC3CC2AD /* Dlsbank.cpp */, + 45DBF5F73F9DB269799CB437 /* Dlsbank.h */, + 1054EEE754A3945996CACD27 /* Fastmix.cpp */, + 39CF376FCC5D01613535A5AF /* FloatMixer.h */, + 2C1F658DEEDFC5FF4C14A3CD /* ITCompression.cpp */, + 2F3B0AD7F5C9024963CB2917 /* ITCompression.h */, + 778D494BBBDBEEBDFE03278B /* ITTools.cpp */, + BBEF0B95B5B0C807EFAFC9D5 /* ITTools.h */, + 567D9E616834DE53DDA2CCA1 /* InstrumentExtensions.cpp */, + 9E091D790F2BBE6BC4F26BB9 /* IntMixer.h */, + CB46E6335DD4B025C6AD5473 /* Load_667.cpp */, + B569F9F747F7C3E9B0D06837 /* Load_669.cpp */, + 37F80675CA85D067335E74B5 /* Load_amf.cpp */, + 29DC06EFBC69D0E12542752F /* Load_ams.cpp */, + B99E396D4C2C035FB504A7AD /* Load_c67.cpp */, + 6A66E753FCF4B14565CD5593 /* Load_dbm.cpp */, + D14936A73E714519400434E7 /* Load_digi.cpp */, + 36CAA59BC9586F8D323113DB /* Load_dmf.cpp */, + F5D60F958863D987F13C7DD5 /* Load_dsm.cpp */, + 9BE2D067090ADED90A9DCEA7 /* Load_dsym.cpp */, + 0D18D5B79FA69FA9087F43F7 /* Load_dtm.cpp */, + 9BB2E75F2E40B1519719559F /* Load_far.cpp */, + 9CF744BB2F850EAD985DB2FB /* Load_fmt.cpp */, + 97BF12BD2A4CDCAF932580FD /* Load_gdm.cpp */, + 10E0ADC7A36E77B90C471C07 /* Load_gt2.cpp */, + 34D45985C7622377303AC7C5 /* Load_imf.cpp */, + 62235C27A6720199E8993A67 /* Load_it.cpp */, + 6A572747FCE4F13965BD9587 /* Load_itp.cpp */, + 2052C727B2E091191BB93567 /* Load_mdl.cpp */, + 8F093E392197082B8A6FAC79 /* Load_med.cpp */, + EC1456C17EA220B3E77AC501 /* Load_mid.cpp */, + 0F49974BA1D7613D0AB0058B /* Load_mo3.cpp */, + 77A4FB8D0A32C57F730B69CD /* Load_mod.cpp */, + 0E85EC13A113B60509EC5A53 /* Load_mt2.cpp */, + 0990B3299C1E7D1B04F72169 /* Load_mtm.cpp */, + 02F4B8C5C982B0373784D705 /* Load_mus_km.cpp */, + 6AE995E9FD775FDB66500429 /* Load_okt.cpp */, + 4E4D213FE0DAEB3149B38F7F /* Load_plm.cpp */, + F1208C2D83AE561FEC86FA6D /* Load_psm.cpp */, + 0863524F9AF11C4103C9C08F /* Load_ptm.cpp */, + 1F41A2D3B1CF6CC51AA81113 /* Load_s3m.cpp */, + C950084F5BDDD241C4B6768F /* Load_sfx.cpp */, + 0735F17599C3BB67029C5FB5 /* Load_stm.cpp */, + 666A8F1BF8F8590D61D0FD5B /* Load_stp.cpp */, + 7D070D1F43950491B1972B5F /* Load_symmod.cpp */, + 54393E69E6C7085B4F9FACA9 /* Load_uax.cpp */, + 7FD19A57125F64497B380897 /* Load_ult.cpp */, + 694D3F69FBDB095B64B3ADA9 /* Load_wav.cpp */, + 2A6435F76EB2DB69B0DA1437 /* Load_xm.cpp */, + 2EF17543C17F3F352A57E383 /* Load_xmf.cpp */, + E59C6F4DDF5E2BBF195D2D8D /* Loaders.h */, + A78B5E5FFEF0D151B0FEEC9F /* MIDIEvents.cpp */, + F42AAB0986B874FBEF911949 /* MIDIEvents.h */, + 50FB747FA860E7715A6F02BF /* MIDIMacros.cpp */, + D37D7529660B3F1BCEE3E369 /* MIDIMacros.h */, + BF406A572C6878C92DFB6897 /* MPEGFrame.cpp */, + A0ADCD61E4FC72D32723ABA1 /* MPEGFrame.h */, + 681E06B9AC6CAC2BEE93E4F9 /* Message.cpp */, + 7A6823C37429E035AE28E203 /* Message.h */, + 60245073020DEC65F934FEB3 /* MixFuncTable.cpp */, + 74DCDADDCC424DCF7E50691D /* MixFuncTable.h */, + 2151B0037C9303754FED4E43 /* Mixer.h */, + B30D8BC554F727B74C1E3A05 /* MixerInterface.h */, + B810F0D30F7663C5C1847F13 /* MixerLoops.cpp */, + C0B331FD5340FBEFBC19A03D /* MixerLoops.h */, + 2BD4379BEE94980D4BC975DB /* MixerSettings.cpp */, + 20B693A5E7448B175546B1E5 /* MixerSettings.h */, + 5FDB15C1B74088B3694EA401 /* ModChannel.cpp */, + E0244DAB72B2179DDB8ABBEB /* ModChannel.h */, + CC1927E18ED98853EC0E6621 /* ModInstrument.cpp */, + E898D5ABAF26CD1D1D28F3EB /* ModInstrument.h */, + A32EC1731056CFE511E9BFB3 /* ModSample.cpp */, + 392551FD7D73F76FBF9B303D /* ModSample.h */, + 8C8CA6B3531A9E25C11CC4F3 /* ModSampleCopy.h */, + CEC583E195537B530355A221 /* ModSequence.cpp */, + B5449C6B226CAADD23FF9AAB /* ModSequence.h */, + B3A14F450EE2A2B7E23CED85 /* OPL.cpp */, + 4756C54F9DE42FC1765D438F /* OPL.h */, + 97B8EC8104E0FAF30673EAC1 /* OggStream.cpp */, + F1E743CB3635E93D785D220B /* OggStream.h */, + A7A09A55A16256C7DB615895 /* Paula.cpp */, + 1AD54F9F7616A3114970EDDF /* Paula.h */, + FFB3088F4401AE018628E6CF /* Resampler.h */, + 1A88E03F71EE533123FC6E7F /* RowVisitor.cpp */, + F06C78E982FA42DBEBD2E729 /* RowVisitor.h */, + 3B8539F7CE1303E936EBA837 /* S3MTools.cpp */, + CA67A8613B8A4953F150F6A1 /* S3MTools.h */, + E6905433791E1E25E1F6C273 /* SampleCopy.h */, + 9061AC518460F5C3094C0A91 /* SampleFormatBRR.cpp */, + F9D67691EACDE48356D164D1 /* SampleFormatFLAC.cpp */, + 4737ECA53B373617C0224AE5 /* SampleFormatMP3.cpp */, + D2D268330651A7A51E4B8673 /* SampleFormatMediaFoundation.cpp */, + 1C6D52530D64C04579684093 /* SampleFormatOpus.cpp */, + 073F0DABFB3E571D80296BEB /* SampleFormatSFZ.cpp */, + 5CDA3BEFB6DB52E17E224A2F /* SampleFormatVorbis.cpp */, + DD65792BA025D99DFD5AB76B /* SampleFormats.cpp */, + 78CAB4630B587E55743122A3 /* SampleIO.cpp */, + 27B40A4D98D6AB3F4E9D588D /* SampleIO.h */, + 46BE019F097E621166B33FDF /* SampleNormalize.h */, + 2323E4A5944685974A0D32E5 /* Snd_defs.h */, + 73781183B7C6B6F5F9EDEFC3 /* Snd_flt.cpp */, + 74D7DB33E5FA7C259BC12973 /* Snd_fx.cpp */, + BAF08779FF3F2CEB416665B9 /* Sndfile.cpp */, + D030DC83C9F298F503F19AC3 /* Sndfile.h */, + 1A0FD6B58B3277A740F924F5 /* Sndmix.cpp */, + F19DB8D9D040544B85225719 /* SoundFilePlayConfig.cpp */, + 51E2F9635E6DABD5D95277A3 /* SoundFilePlayConfig.h */, + 488AACC5B9AD4DB76F73FB05 /* Tables.cpp */, + 63FDD8AF94E1D0A1A7FA06EF /* Tables.h */, + 1B5F95F15FAE3B63A1D57431 /* Tagging.cpp */, + 236E8DFB1D304A6D572F4C3B /* Tagging.h */, + 03BF85B7480E2B298A3563F7 /* TinyFFT.cpp */, + 3D34478136F603F370F505C1 /* TinyFFT.h */, + C7851FA55A12E997C2EB8DE5 /* UMXTools.cpp */, + 2D02F4CF9E2595C153EC430F /* UMXTools.h */, + 3BC5C04BFE8620BD5BBAFE8B /* UpgradeModule.cpp */, + 1F5AB80DB1E881FF1AC1264D /* WAVTools.cpp */, + 2BF8C6379D1B672952E21477 /* WAVTools.h */, + 14715833DAFF4FA549017673 /* WindowedFIR.cpp */, + DAAB5DFD47D36C6F49665C3D /* WindowedFIR.h */, + 7C6EC51BC0BD6A8D02E4A35B /* XMTools.cpp */, + 2810796521D235D75BD137A5 /* XMTools.h */, + A33106C935BED0BB9E977509 /* load_j2b.cpp */, + 274EB9F5814FD0E74896C835 /* mod_specifications.cpp */, + E438935FD53001514133819F /* mod_specifications.h */, + 746376CDCBC8E9BF7DD7050D /* modcommand.cpp */, + 5BE26A37EE7034295748D877 /* modcommand.h */, + 09E33737D0712EA93E735577 /* modsmp_ctrl.cpp */, + 28D2F38195FB01F3978DF1C1 /* modsmp_ctrl.h */, + 7214DF31A1A6AE237CB3ED71 /* opal.h */, + CB4660EB0F95065D51BC3F2B /* pattern.cpp */, + F19C0735EB5DC3A7255CC575 /* pattern.h */, + 8BE9A4117CE11203E8E49251 /* patternContainer.cpp */, + CB69F5BB3FC43AADBDA7C3FB /* patternContainer.h */, + 31DC889B1CC8AE8D64AE76DB /* plugins */, + 48199D39B93C3E2B6F02EB79 /* tuning.cpp */, + FED01DA32FB4159542CC4BE3 /* tuning.h */, + DFE0BC51D0D82A433CDBAA91 /* tuningCollection.cpp */, + EEC8D9B98156A3ABEA2F47F9 /* tuningbase.h */, + 6687823BDAE1C72D58C5507B /* tuningcollection.h */, + ); + name = soundlib; + sourceTree = ""; + }; + EB3711558E2538071D4B1795 /* parse */ = { + isa = PBXGroup; + children = ( + 5CFFC0612B231413B23166A1 /* parse.hpp */, + CE6385639C86D91523952BA3 /* split.hpp */, + FFE5A7EF48568C218CF55E2F /* tests */, + ); + name = parse; + sourceTree = ""; + }; + F76908210E7BA353FE979E61 /* random */ = { + isa = PBXGroup; + children = ( + 8DE932C12076FCB3894FA101 /* crand.hpp */, + 8876678BE2777E7DA9BE75CB /* default_engines.hpp */, + 1CE2C4318A0AD2A38B9DC271 /* device.hpp */, + 7C15603DE93D6EAFEAD05E7D /* engine.hpp */, + 49E264470CA2C4B969D7A287 /* engine_lcg.hpp */, + E2B3BCB34FDBCB25516EBAF3 /* random.hpp */, + 18A72A335CF5CFA59F1D0873 /* seed.hpp */, + 42C3CDB59951382771CA4BF5 /* tests */, + ); + name = random; + sourceTree = ""; + }; + FB1C5B4521428AF788498185 /* io_read */ = { + isa = PBXGroup; + children = ( + 00114BD59DF24C8775709215 /* callbackstream.hpp */, + DC3C845FF708F311FAD98A9F /* filecursor.hpp */, + 6F3A912F8923F36144AA076F /* filecursor_callbackstream.hpp */, + 39C1318B738BE83D28E737CB /* filecursor_filename_traits.hpp */, + 712230EFB9C16F21DCED272F /* filecursor_memory.hpp */, + 8B1AB3CB32904F7DDB555A0B /* filecursor_stdstream.hpp */, + FB635E3D352E14EFEA89647D /* filecursor_traits_filedata.hpp */, + F48DAABB97F4D86DAF2A90FB /* filecursor_traits_memory.hpp */, + A34959973B963F4969DD3FD7 /* filedata.hpp */, + 62E32DEB72C85A1D5F3BE42B /* filedata_base.hpp */, + 23EF16CF7F4F3B81C192DD0F /* filedata_base_buffered.hpp */, + E276AB813DD6D033801A71C1 /* filedata_base_seekable.hpp */, + 8ABDA3472E24D0F9455A8987 /* filedata_base_unseekable.hpp */, + E0CF51E794CB6B19767DA827 /* filedata_callbackstream.hpp */, + 079DA5A7A1C19AD951E77BE7 /* filedata_memory.hpp */, + CE271C83BB8EAF355888A2C3 /* filedata_stdstream.hpp */, + F1F533090CC1A1BB10923949 /* filereader.hpp */, + ); + name = io_read; + sourceTree = ""; + }; + FE13EC1B0184BE4D82F1625B /* arch */ = { + isa = PBXGroup; + children = ( + 09573FAA7A79E09C30408DEA /* arch.hpp */, + 1197459E05968F108A81A3DE /* feature_flags.hpp */, + 473316F00DC10E627BC33530 /* x86_amd64.hpp */, + ); + name = arch; + sourceTree = ""; + }; + FFE5A7EF48568C218CF55E2F /* tests */ = { + isa = PBXGroup; + children = ( + D432AEE7E417DB19D08B6527 /* tests_parse.hpp */, + ); + name = tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 92770993A989A4C599A59FD3 /* libopenmpt */ = { + isa = PBXNativeTarget; + buildConfigurationList = 62E1069CD46C1F0E836D44DC /* Build configuration list for PBXNativeTarget "libopenmpt" */; + buildPhases = ( + E48D3EDD5618574F05197D1D /* Resources */, + 4E3A5834BFC570A66EC69674 /* Sources */, + 74A5BE3DE630D6AF9531FC7D /* Frameworks */, + 0AD991E90B8C8EDB7F6E6029 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + F4A0CAA5DF8CF0972772B8E5 /* PBXTargetDependency */, + B8B28420A39EAA12EB847260 /* PBXTargetDependency */, + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */, + ); + name = libopenmpt; + productName = libopenmpt; + productReference = 9B95674D94FB68BF8896C58D /* libopenmpt.dll */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "libopenmpt" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = 9320911A7F119CCCD149375A /* libopenmpt */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 06E88D9CF1D4B38E39BA7BDC /* Products */; + ProjectRef = 04155894998C17C608286ED4 /* mpg123.xcodeproj */; + }, + { + ProductGroup = CAFA4717B5E66D09FDCC3557 /* Products */; + ProjectRef = 41BBEA4AD732A97C45CF008A /* vorbis.xcodeproj */; + }, + { + ProductGroup = 80C578BF97D813F187F40EFF /* Products */; + ProjectRef = E64FF33AA9BBB4ECE85F597A /* ogg.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 92770993A989A4C599A59FD3 /* libopenmpt.dll */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 5DFCA7B6A69BE5E8C9C79DF6 /* openmpt-ogg.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-ogg.lib"; + remoteRef = EAF35B5FE4595CD1D7F4B99F /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 91C69AB0393C3662E20140F0 /* openmpt-mpg123.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-mpg123.lib"; + remoteRef = 35790BDC7DE9F00EC288C21C /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E7CD47E68F42E3983807EE26 /* openmpt-vorbis.lib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = "openmpt-vorbis.lib"; + remoteRef = 7BC1F4B7C432D8E908D1AAF7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + E48D3EDD5618574F05197D1D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4E3A5834BFC570A66EC69674 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B591ED4C6887F6FEB9AA538C /* ComponentManager.cpp in Sources */, + 527E833E969254708A63D97E /* Logging.cpp in Sources */, + 1CE1B0B6B52E9668E37596F6 /* Profiler.cpp in Sources */, + 1CD4D902FBF1F334D7FB4F42 /* mptFileIO.cpp in Sources */, + BB65D2D86E5BDC8ABF7E3918 /* mptFileTemporary.cpp in Sources */, + 1F7082161F13654859681856 /* mptFileType.cpp in Sources */, + DF08AE5AEEEDDA8CDB61649A /* mptPathString.cpp in Sources */, + 926864F471857F264D8EDB34 /* mptRandom.cpp in Sources */, + 8751165421750B86D19AEC94 /* mptStringBuffer.cpp in Sources */, + 30BE965074D2678268A3EC90 /* mptTime.cpp in Sources */, + EDE4FB2CD37C025E96C1116C /* serialization_utils.cpp in Sources */, + DEBC9FDC22D0710E16A1F61C /* version.cpp in Sources */, + F65565599436660B6BB4AB99 /* libopenmpt_c.cpp in Sources */, + 03096A39B5FF73EB0721D079 /* libopenmpt_cxx.cpp in Sources */, + 976568F7F2B0B929E0E29F37 /* libopenmpt_ext_impl.cpp in Sources */, + C79768571036A68933625E97 /* libopenmpt_impl.cpp in Sources */, + B5220D6D8345611F0A53B3AD /* AGC.cpp in Sources */, + 3EF604A50D1958579427AAE5 /* DSP.cpp in Sources */, + 50BD34A3E633F3D554D04AE3 /* EQ.cpp in Sources */, + C0082C03041BFD35F7ED8243 /* Reverb.cpp in Sources */, + A9C7C28B051312BDF344F8CB /* AudioCriticalSection.cpp in Sources */, + 6600F8E10024EE13B04ACF21 /* ContainerMMCMP.cpp in Sources */, + B17E84D14F5F858326DDCB11 /* ContainerPP20.cpp in Sources */, + 46A543E1568A701342FDFA21 /* ContainerUMX.cpp in Sources */, + 31268193410BADC52D7F37D3 /* ContainerXPK.cpp in Sources */, + 1452C745AC9FACF7DAE6AD85 /* Dlsbank.cpp in Sources */, + 3C92F25FD4DFD8110326D89F /* Fastmix.cpp in Sources */, + 32D83065D0B93117A83776A5 /* ITCompression.cpp in Sources */, + E6583D037EA522B5ACEC2343 /* ITTools.cpp in Sources */, + 4FD75379AB22A3AB995489B9 /* InstrumentExtensions.cpp in Sources */, + 5EE7936B3E04AD9D1A0E09AB /* Load_667.cpp in Sources */, + 4E13C16F2D30DBA1093A37AF /* Load_669.cpp in Sources */, + A7B576CD86D290FF62DBED0D /* Load_amf.cpp in Sources */, + BA54A1E79971BC19757B1827 /* Load_ams.cpp in Sources */, + 44F9DD452416F77700205385 /* Load_c67.cpp in Sources */, + 7B65168B5A8230BD368B8CCB /* Load_dbm.cpp in Sources */, + 8479AC1F9F461AD1A316B25F /* Load_digi.cpp in Sources */, + C81D1553A73A2F8583438B93 /* Load_dmf.cpp in Sources */, + 8B4D81ED6A6A9C1F4673F82D /* Load_dsm.cpp in Sources */, + D2EFC1DFEDBC3091F18CC81F /* Load_dsym.cpp in Sources */, + F5A6792FD4C39361B0CCEF6F /* Load_dtm.cpp in Sources */, + D1EA5157B1076B898D10C797 /* Load_far.cpp in Sources */, + BD4216739C5F30A578688CB3 /* Load_fmt.cpp in Sources */, + 707EA3954F9BBDC72BA519D5 /* Load_gdm.cpp in Sources */, + 8676CA3F6593E471419D407F /* Load_gt2.cpp in Sources */, + 537472DD32918D0F0E9AE91D /* Load_imf.cpp in Sources */, + 7FDA539F18273951466E39DF /* Load_it.cpp in Sources */, + E7C01BBFC6DD35F1A2E691FF /* Load_itp.cpp in Sources */, + 39B7C99F18D4E3D1F4DE3FDF /* Load_mdl.cpp in Sources */, + E76008D1C67D2303A2867F11 /* Load_med.cpp in Sources */, + 90C3E5D96FE1000B4BEA5C19 /* Load_mid.cpp in Sources */, + 2B1F4A030A3C6435E645C043 /* Load_mo3.cpp in Sources */, + 0ED9B165EDF6CB97CA0027A5 /* Load_mod.cpp in Sources */, + C746074BA663217D826C7D8B /* Load_mt2.cpp in Sources */, + 56DD54C135FA6EF31203CB01 /* Load_mtm.cpp in Sources */, + 63B0011DD79878CFF9E6275D /* Load_mus_km.cpp in Sources */, + 49C7038128E41DB304ED79C1 /* Load_okt.cpp in Sources */, + 247D3937039A5369DFA3AF77 /* Load_plm.cpp in Sources */, + 0CEBFC05EC091637C8127245 /* Load_psm.cpp in Sources */, + 7744F34756620D79326B6987 /* Load_ptm.cpp in Sources */, + 9715CA0B7632E43D523C404B /* Load_s3m.cpp in Sources */, + EA420947C95F2379A5687F87 /* Load_sfx.cpp in Sources */, + 97AC91CD76C9ABFF52D3080D /* Load_stm.cpp in Sources */, + FE6ED6D3DD8BF105B9954D13 /* Load_stp.cpp in Sources */, + CF116C1742F9E3C965479257 /* Load_symmod.cpp in Sources */, + 4174F40120920E33FC9B6A41 /* Load_uax.cpp in Sources */, + F4EF37CFD40C5201B015AE0F /* Load_ult.cpp in Sources */, + BD3885019C559F33785EFB41 /* Load_wav.cpp in Sources */, + 00BB926F99087821C74F78AF /* Load_xm.cpp in Sources */, + F57A8B7BD497A5ADB0A101BB /* Load_xmf.cpp in Sources */, + CCEFFE57CC92E18906E79497 /* MIDIEvents.cpp in Sources */, + 80EEA677809189A9BAE63CB7 /* MIDIMacros.cpp in Sources */, + 393D72CF5409E18157DA790F /* MPEGFrame.cpp in Sources */, + 168C3C51AED92203DD202291 /* Message.cpp in Sources */, + 7A5E5DAB8A4389DD76B713EB /* MixFuncTable.cpp in Sources */, + 84A9E60B844CC93DBEA17C4B /* MixerLoops.cpp in Sources */, + DC9752537A78530551F69893 /* MixerSettings.cpp in Sources */, + 30C4FED93067E20B6ABC9519 /* ModChannel.cpp in Sources */, + F0D031F98EB132AB662F7839 /* ModInstrument.cpp in Sources */, + 9F1029ABB9DC985DBDAD2FEB /* ModSample.cpp in Sources */, + D86AE3F94C535BAB6EA10A39 /* ModSequence.cpp in Sources */, + ABC5779D79E8CB4F00F71DDD /* OPL.cpp in Sources */, + FD083C9917D4AB4B1BA542D9 /* OggStream.cpp in Sources */, + 33DB2DAD46050A5F79F5F3ED /* Paula.cpp in Sources */, + 119C6E37113F51694B940477 /* RowVisitor.cpp in Sources */, + D443016FB3601BA18F6977AF /* S3MTools.cpp in Sources */, + 77A73F692A9D491B7BBFA5A9 /* SampleFormatBRR.cpp in Sources */, + 49F242A9929180DBB5BD38E9 /* SampleFormatFLAC.cpp in Sources */, + 3F8606FDF27C10AF439E6D3D /* SampleFormatMP3.cpp in Sources */, + 7DDE7A6B76A93A1D011DA0AB /* SampleFormatMediaFoundation.cpp in Sources */, + D309698B1BA8A7BD3ED45FCB /* SampleFormatOpus.cpp in Sources */, + FD572F63B04D3915016F95A3 /* SampleFormatSFZ.cpp in Sources */, + 0D8FA4E7F326AC19B66BBB27 /* SampleFormatVorbis.cpp in Sources */, + E79434E3857535955CF37B23 /* SampleFormats.cpp in Sources */, + 18C62C9BF7E346CDD3ECA2DB /* SampleIO.cpp in Sources */, + D83D74BB708A5A6D9ED15AFB /* Snd_flt.cpp in Sources */, + BE9B2A6B02AEFB9DF68080AB /* Snd_fx.cpp in Sources */, + 281FA911C06C8EC3EEB38F51 /* Sndfile.cpp in Sources */, + B5D9190DF9ECEA3FEDBE6F4D /* Sndmix.cpp in Sources */, + A9D47C71514A1823FA0F22B1 /* SoundFilePlayConfig.cpp in Sources */, + BBC2281DFFD5F94FF3A77E5D /* Tables.cpp in Sources */, + 14522B09AC9F10BBDAE61149 /* Tagging.cpp in Sources */, + E9363E2F818323E1AFCA246F /* TinyFFT.cpp in Sources */, + C55C8AFDA479A52F8083013D /* UMXTools.cpp in Sources */, + 31B9FE03CF9AFEB5A7194443 /* UpgradeModule.cpp in Sources */, + 8D04F5E56C221017482B6C25 /* WAVTools.cpp in Sources */, + A5DAFA6B19C3721D3C1120AB /* WindowedFIR.cpp in Sources */, + A0E13DD3392E238567752413 /* XMTools.cpp in Sources */, + 574F1261366C2C93127588A1 /* load_j2b.cpp in Sources */, + AB7FFC4D9117037F545C128D /* mod_specifications.cpp in Sources */, + DEB582A5DE5865D718AD18E5 /* modcommand.cpp in Sources */, + CB31B3AF3F1A2B616167D9EF /* modsmp_ctrl.cpp in Sources */, + 32925EA3CADF4455F92644E3 /* pattern.cpp in Sources */, + BC15882904B4C65B27E07E69 /* patternContainer.cpp in Sources */, + 689E270C1013C2BEB8D8CD4C /* DigiBoosterEcho.cpp in Sources */, + A896F1F84677F2AA1DF63838 /* LFOPlugin.cpp in Sources */, + 9F2D020A8C9494BC298E884A /* PlugInterface.cpp in Sources */, + 370352EC246AE59EC164D92C /* PluginManager.cpp in Sources */, + F59363E88FB7591A3FDD3A28 /* SymMODEcho.cpp in Sources */, + CEDA1F2FDEBF4B61CB32D56F /* Chorus.cpp in Sources */, + CC12FBA114B239D337DDF1E1 /* Compressor.cpp in Sources */, + 00CD0D05B3C316B704E57345 /* DMOPlugin.cpp in Sources */, + BCC110A956E505DB070AE6E9 /* DMOUtils.cpp in Sources */, + 0BABF0E5544B2F177776E725 /* Distortion.cpp in Sources */, + 97B1A0C5975483F7D1A93705 /* Echo.cpp in Sources */, + 9FC1BA253DA2BAD715210065 /* Flanger.cpp in Sources */, + 1E48E6EB2E2E131D1AA19D2B /* Gargle.cpp in Sources */, + 40F236CF2E59C981CB53BD0F /* I3DL2Reverb.cpp in Sources */, + 69AC6475078D6527DF0BAAB5 /* ParamEq.cpp in Sources */, + 1553F71F02BB89D19FB57D5F /* WavesReverb.cpp in Sources */, + 6A44FDD1AE58CF03A22A5411 /* tuning.cpp in Sources */, + CF000469179F429B3ACAFAA9 /* tuningCollection.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 6E7DB5C8859050FA75AC4C08 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-ogg.lib"; + targetProxy = 3D2DCDF83693CF6A2A2F2C38 /* PBXContainerItemProxy */; + }; + B8B28420A39EAA12EB847260 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-vorbis.lib"; + targetProxy = CDFC6750166D4B825B0C1D90 /* PBXContainerItemProxy */; + }; + F4A0CAA5DF8CF0972772B8E5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "openmpt-mpg123.lib"; + targetProxy = 87B37E75D02462A714C334B5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1499E0DC457DD8CE58960F1C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../bin/release/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = libopenmpt; + }; + name = Release; + }; + 185F176389EA2FD538EB55A3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + NDEBUG, + LIBOPENMPT_BUILD, + MPT_WITH_MPG123, + MPT_WITH_OGG, + MPT_WITH_VORBIS, + MPT_WITH_VORBISFILE, + MPT_WITH_ZLIB, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Release; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "-lz", + ); + SYMROOT = "../../bin/release/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../include/mpg123/ports/Xcode, + ../../include/mpg123/src/libmpg123, + ../../include/ogg/include, + ../../include/vorbis/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../.., + ../../src, + ../../common, + ../../soundlib, + "\"$(IntDir)/svn_version\"", + ); + }; + name = Release; + }; + 3383DEE9622A32DBBB6B8D29 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++1z"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + DEBUG, + MPT_BUILD_DEBUG, + LIBOPENMPT_BUILD, + MPT_WITH_MPG123, + MPT_WITH_OGG, + MPT_WITH_VORBIS, + MPT_WITH_VORBISFILE, + MPT_WITH_ZLIB, + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = obj/Debug; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "-lz", + ); + SYMROOT = "../../bin/debug/xcode4-macosx/all"; + SYSTEM_HEADER_SEARCH_PATHS = ( + ../../include/mpg123/ports/Xcode, + ../../include/mpg123/src/libmpg123, + ../../include/ogg/include, + ../../include/vorbis/include, + "$(inherited)", + ); + USER_HEADER_SEARCH_PATHS = ( + ../.., + ../../src, + ../../common, + ../../soundlib, + "\"$(IntDir)/svn_version\"", + ); + }; + name = Debug; + }; + 9C47E562F78938D4CAE383A2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = "../../bin/debug/xcode4-macosx/all"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + EXECUTABLE_EXTENSION = dll; + GCC_DYNAMIC_NO_PIC = NO; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = libopenmpt; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "libopenmpt" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3383DEE9622A32DBBB6B8D29 /* Debug */, + 185F176389EA2FD538EB55A3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 62E1069CD46C1F0E836D44DC /* Build configuration list for PBXNativeTarget "libopenmpt.dll" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9C47E562F78938D4CAE383A2 /* Debug */, + 1499E0DC457DD8CE58960F1C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ +}; +rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcworkspace/contents.xcworkspacedata b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..88cd67a91 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/build/xcode-macosx/libopenmpt.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h index e587b1570..fe08bf76b 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h +++ b/Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h @@ -22,33 +22,6 @@ -// set windows version early so that we can deduce dependencies from SDK version - -#if MPT_OS_WINDOWS - -#if !defined(WINVER) && !defined(_WIN32_WINDOWS) && !defined(_WIN32_WINNT) -#if MPT_COMPILER_CLANG -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif // MPT_COMPILER_CLANG -#define _WIN32_WINNT 0x0601 // _WIN32_WINNT_WIN7 -#if MPT_COMPILER_CLANG -#pragma clang diagnostic pop -#endif // MPT_COMPILER_CLANG -#endif - -#ifndef WINVER -#if defined(_WIN32_WINNT) -#define WINVER _WIN32_WINNT -#elif defined(_WIN32_WINDOWS) -#define WINVER _WIN32_WINDOWS -#endif -#endif - -#endif // MPT_OS_WINDOWS - - - #if defined(MODPLUG_TRACKER) && defined(LIBOPENMPT_BUILD) #error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined" #elif defined(MODPLUG_TRACKER) @@ -63,160 +36,44 @@ -#if defined(LIBOPENMPT_BUILD) - -// Fixup dependencies which are currently not used in libopenmpt itself, -// however might be set by some build systems like autotools anyway for simplicity. -#ifdef MPT_WITH_FLAC -#undef MPT_WITH_FLAC -#endif - -#endif // LIBOPENMPT_BUILD - - - -// Dependencies from the MSVC build system -#if defined(MPT_BUILD_MSVC) - -// This section defines which dependencies are available when building with -// MSVC. Other build systems provide MPT_WITH_* macros via command-line or other -// means. -// OpenMPT and libopenmpt should compile and run successfully (albeit with -// reduced functionality) with any or all dependencies missing/disabled. -// The defaults match the bundled third-party libraries with the addition of -// ASIO and VST SDKs. - #if defined(MODPLUG_TRACKER) -#if MPT_OS_WINDOWS -#if !defined(MPT_BUILD_WINESUPPORT) && !defined(MPT_BUILD_UPDATESIGNTOOL) -#define MPT_WITH_MFC -#endif // !MPT_BUILD_WINESUPPORT && !MPT_BUILD_UPDATESIGNTOOL -#endif // MPT_OS_WINDOWS - -// OpenMPT-only dependencies -#define MPT_WITH_ANCIENT -#if !defined(MPT_BUILD_RETRO) && !MPT_COMPILER_CLANG && !MPT_MSVC_BEFORE(2019,0) -// disabled for VS2017 because of multiple initialization of inline variables -// https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876 -#define MPT_WITH_ASIO -#endif #if defined(MPT_BUILD_RETRO) -#define MPT_WITH_DIRECTSOUND +#define OPENMPT_BUILD_VARIANT "Retro" +#define OPENMPT_BUILD_VARIANT_MONIKER " RETRO" +#else +#if MPT_OS_WINDOWS +#if MPT_WINNT_AT_LEAST(MPT_WIN_10) +#define OPENMPT_BUILD_VARIANT "Standard" +#define OPENMPT_BUILD_VARIANT_MONIKER "" +#else +#define OPENMPT_BUILD_VARIANT "Legacy" +#define OPENMPT_BUILD_VARIANT_MONIKER "" #endif +#else +#define OPENMPT_BUILD_VARIANT "Unknown" +#define OPENMPT_BUILD_VARIANT_MONIKER "" +#endif +#endif + #define MPT_WITH_DMO -#define MPT_WITH_LAME -#define MPT_WITH_LHASA -#define MPT_WITH_MINIZIP -#define MPT_WITH_NLOHMANNJSON -#define MPT_WITH_OPUS -#define MPT_WITH_OPUSENC -#define MPT_WITH_OPUSFILE -#define MPT_WITH_PORTAUDIO -//#define MPT_WITH_PULSEAUDIO -//#define MPT_WITH_PULSEAUDIOSIMPLE -#define MPT_WITH_RTAUDIO -#define MPT_WITH_SMBPITCHSHIFT -#define MPT_WITH_UNRAR -#define MPT_WITH_VORBISENC + #define MPT_WITH_VST -// OpenMPT and libopenmpt dependencies (not for openmp123, player plugins or examples) -//#define MPT_WITH_DL -#define MPT_WITH_FLAC -//#define MPT_WITH_LTDL #if MPT_OS_WINDOWS -#if (_WIN32_WINNT >= 0x0601) +#if MPT_WINNT_AT_LEAST(MPT_WIN_7) #define MPT_WITH_MEDIAFOUNDATION #endif #endif -//#define MPT_WITH_MINIMP3 -//#define MPT_WITH_MINIZ -#define MPT_WITH_MPG123 -#define MPT_WITH_OGG -//#define MPT_WITH_STBVORBIS -#define MPT_WITH_VORBIS -#define MPT_WITH_VORBISFILE + #if MPT_OS_WINDOWS -#if (_WIN32_WINNT >= 0x0A00) +#if MPT_WINNT_AT_LEAST(MPT_WIN_10) #define MPT_WITH_WINDOWS10 #endif #endif -#define MPT_WITH_ZLIB #endif // MODPLUG_TRACKER -#if defined(LIBOPENMPT_BUILD) - -// OpenMPT and libopenmpt dependencies (not for openmp123, player plugins or examples) -#if defined(LIBOPENMPT_BUILD_FULL) && defined(LIBOPENMPT_BUILD_SMALL) -#error "only one of LIBOPENMPT_BUILD_FULL or LIBOPENMPT_BUILD_SMALL can be defined" -#endif // LIBOPENMPT_BUILD_FULL && LIBOPENMPT_BUILD_SMALL - -#if defined(LIBOPENMPT_BUILD_SMALL) - -//#define MPT_WITH_DL -//#define MPT_WITH_FLAC -//#define MPT_WITH_LTDL -//#define MPT_WITH_MEDIAFOUNDATION -#define MPT_WITH_MINIMP3 -#define MPT_WITH_MINIZ -//#define MPT_WITH_MPG123 -//#define MPT_WITH_OGG -#define MPT_WITH_STBVORBIS -//#define MPT_WITH_VORBIS -//#define MPT_WITH_VORBISFILE -//#define MPT_WITH_ZLIB - -#else // !LIBOPENMPT_BUILD_SMALL - -//#define MPT_WITH_DL -//#define MPT_WITH_FLAC -//#define MPT_WITH_LTDL -//#define MPT_WITH_MEDIAFOUNDATION -//#define MPT_WITH_MINIMP3 -//#define MPT_WITH_MINIZ -#define MPT_WITH_MPG123 -#define MPT_WITH_OGG -//#define MPT_WITH_STBVORBIS -#define MPT_WITH_VORBIS -#define MPT_WITH_VORBISFILE -#define MPT_WITH_ZLIB - -#endif // LIBOPENMPT_BUILD_SMALL - -#endif // LIBOPENMPT_BUILD - -#endif // MPT_BUILD_MSVC - - -#if defined(MPT_BUILD_XCODE) - -#if defined(MODPLUG_TRACKER) - -// n/a - -#endif // MODPLUG_TRACKER - -#if defined(LIBOPENMPT_BUILD) - -//#define MPT_WITH_DL -//#define MPT_WITH_FLAC -//#define MPT_WITH_LTDL -//#define MPT_WITH_MEDIAFOUNDATION -//#define MPT_WITH_MINIMP3 -//#define MPT_WITH_MINIZ -#define MPT_WITH_MPG123 -#define MPT_WITH_OGG -//#define MPT_WITH_STBVORBIS -#define MPT_WITH_VORBIS -#define MPT_WITH_VORBISFILE -#define MPT_WITH_ZLIB - -#endif // LIBOPENMPT_BUILD - -#endif // MPT_BUILD_XCODE - #if defined(MODPLUG_TRACKER) @@ -283,6 +140,14 @@ #if defined(LIBOPENMPT_BUILD) +#ifdef MPT_WITH_FLAC +#error "Building libopenmpt with FLAC is useless and not a supported configuration. Please fix your build system to not list libflac as a dependency for libopenmpt itself. It is only a dependency of openmpt123." +#endif + +#ifndef LIBOPENMPT_NO_DEPRECATE +#define LIBOPENMPT_NO_DEPRECATE +#endif + #if (defined(_DEBUG) || defined(DEBUG)) && !defined(MPT_BUILD_DEBUG) #define MPT_BUILD_DEBUG #endif @@ -342,35 +207,8 @@ -#if (MPT_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)) || defined(MODPLUG_TRACKER) - - // Use wide strings for MSVC because this is the native encoding on - // microsoft platforms. - - // mpt::ToWString, mpt::wfmt, ConvertStrTo - // Required by the tracker to ease interfacing with WinAPI. - // Required by MPT_USTRING_MODE_WIDE to ease type tunneling in mpt::format. - #define MPT_WSTRING_FORMAT 1 - -#else - - #define MPT_WSTRING_FORMAT 0 - -#endif - -#if (MPT_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)) || MPT_OS_WINDOWS || MPT_WSTRING_FORMAT - - // mpt::ToWide - // Required on Windows by mpt::PathString. - // Required by MPT_USTRING_MODE_WIDE as they share the conversion functions. - // Required by MPT_WSTRING_FORMAT because of std::string<->std::wstring conversion in mpt::ToAString and mpt::ToWString. - #define MPT_WSTRING_CONVERT 1 - -#else - - #define MPT_WSTRING_CONVERT 0 - -#endif +#define MPT_TIME_UTC_ON_DISK 0 +#define MPT_TIME_UTC_ON_DISK_VERSION MPT_V("1.31.00.13") @@ -490,21 +328,6 @@ // platform configuration -#ifdef MPT_WITH_MFC -//#define MPT_MFC_FULL // use full MFC, including MFC controls -#define _CSTRING_DISABLE_NARROW_WIDE_CONVERSION -#endif // MPT_WITH_MFC - -#if defined(MODPLUG_TRACKER) -#if MPT_OS_WINDOWS -#if !defined(MPT_BUILD_WINESUPPORT) -#ifndef MPT_MFC_FULL -#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Do not include support for MFC controls in dialogs (reduces binary bloat; remove this #define if you want to use MFC controls) -#endif // !MPT_MFC_FULL -#endif // !MPT_BUILD_WINESUPPORT -#endif // MPT_OS_WINDOWS -#endif // MODPLUG_TRACKER - #if MPT_OS_WINDOWS #define WIN32_LEAN_AND_MEAN @@ -545,35 +368,10 @@ -// stdlib configuration - -#if MPT_COMPILER_CLANG -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif - -#define __STDC_CONSTANT_MACROS -#define __STDC_FORMAT_MACROS -#define __STDC_LIMIT_MACROS - -#define _USE_MATH_DEFINES - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 -#endif - -#if MPT_COMPILER_CLANG -#pragma clang diagnostic pop -#endif - - - // compiler configuration #if MPT_COMPILER_MSVC -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - #pragma warning(default:4800) // Implicit conversion from 'int' to bool. Possible information loss #pragma warning(disable:4355) // 'this' : used in base member initializer list @@ -610,47 +408,11 @@ - - -// standard library quirks - - - - - // third-party library configuration -#if MPT_OS_WINDOWS -#ifndef UNICODE -#define MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_UNICODE -#endif // !UNICODE -#endif // MPT_OS_WINDOWS - -#ifdef MPT_WITH_ANCIENT -#ifdef MPT_BUILD_MSVC_SHARED -#define ANCIENT_API_DECLSPEC_DLLIMPORT -#endif -#endif - -#ifdef MPT_WITH_FLAC -#ifdef MPT_BUILD_MSVC_STATIC -#define FLAC__NO_DLL -#endif -#endif - -#ifdef MPT_WITH_SMBPITCHSHIFT -#ifdef MPT_BUILD_MSVC_SHARED -#define SMBPITCHSHIFT_USE_DLL -#endif -#endif - #ifdef MPT_WITH_STBVORBIS +#ifndef STB_VORBIS_HEADER_ONLY #define STB_VORBIS_HEADER_ONLY -#ifndef STB_VORBIS_NO_PULLDATA_API -#define STB_VORBIS_NO_PULLDATA_API -#endif -#ifndef STB_VORBIS_NO_STDIO -#define STB_VORBIS_NO_STDIO #endif #endif @@ -660,12 +422,6 @@ #endif #endif -#ifdef MPT_WITH_ZLIB -#ifdef MPT_BUILD_MSVC_SHARED -#define ZLIB_DLL -#endif -#endif - #ifdef __cplusplus diff --git a/Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h b/Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h index 6733ad07b..201945d79 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h +++ b/Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h @@ -135,7 +135,7 @@ class ComponentLibrary private: - typedef std::map TLibraryMap; + using TLibraryMap = std::map; TLibraryMap m_Libraries; bool m_BindFailed; @@ -237,7 +237,7 @@ public: class ComponentManager; -typedef std::shared_ptr (*ComponentFactoryMethod)(ComponentManager &componentManager); +using ComponentFactoryMethod = std::shared_ptr (*)(ComponentManager &componentManager); class IComponentFactory @@ -361,7 +361,7 @@ private: std::shared_ptr instance; std::weak_ptr weakInstance; }; - typedef std::map TComponentMap; + using TComponentMap = std::map; const IComponentManagerSettings &m_Settings; TComponentMap m_Components; private: diff --git a/Frameworks/OpenMPT/OpenMPT/common/FileReader.h b/Frameworks/OpenMPT/OpenMPT/common/FileReader.h index ca6e253f5..0d3973412 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/FileReader.h +++ b/Frameworks/OpenMPT/OpenMPT/common/FileReader.h @@ -97,7 +97,8 @@ namespace FileReaderExt template bool ReadSizedString(TFileCursor &f, char (&destBuffer)[destSize], const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { - mpt::packed srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs + static_assert(mpt::is_binary_safe::value); + Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; @@ -111,7 +112,8 @@ namespace FileReaderExt template bool ReadSizedString(TFileCursor &f, std::string &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { - mpt::packed srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs + static_assert(mpt::is_binary_safe::value); + Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; @@ -125,7 +127,8 @@ namespace FileReaderExt template bool ReadSizedString(TFileCursor &f, mpt::charbuf &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits::max()) { - mpt::packed srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs + static_assert(mpt::is_binary_safe::value); + Tsize srcSize; if(!mpt::IO::FileReader::Read(f, srcSize)) { return false; diff --git a/Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h b/Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h index decf4aaf3..fc2a1221e 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h +++ b/Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h @@ -15,6 +15,13 @@ namespace mpt { inline namespace MPT_INLINE_NS { + +template +class BasicPathString; +struct NativePathTraits; +struct Utf8PathTraits; +using native_path = BasicPathString; + namespace IO { class FileCursorTraitsMemory; @@ -30,6 +37,7 @@ template class FileCursor; } + } } @@ -50,9 +58,11 @@ class FileReader; } // namespace detail namespace mpt { - -class PathString; - +#if defined(MPT_ENABLE_CHARSET_LOCALE) +using PathString = mpt::native_path; +#else +using PathString = mpt::BasicPathString; +#endif } // namespace mpt using FileCursor = detail::FileCursor>; diff --git a/Frameworks/OpenMPT/OpenMPT/common/Logging.cpp b/Frameworks/OpenMPT/OpenMPT/common/Logging.cpp index 3e4c87c79..2ef1b7bcb 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/Logging.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/Logging.cpp @@ -12,6 +12,7 @@ #include "Logging.h" +#include "mpt/base/macros.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" @@ -42,9 +43,9 @@ namespace log #if !defined(MPT_LOG_GLOBAL_LEVEL_STATIC) #if defined(MPT_LOG_GLOBAL_LEVEL) -int GlobalLogLevel = static_cast(MPT_LOG_GLOBAL_LEVEL); +MPT_CONSTINIT int GlobalLogLevel = static_cast(MPT_LOG_GLOBAL_LEVEL); #else -int GlobalLogLevel = static_cast(LogDebug); +MPT_CONSTINIT int GlobalLogLevel = static_cast(LogDebug); #endif #endif @@ -52,12 +53,12 @@ int GlobalLogLevel = static_cast(LogDebug); #if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED) -bool FileEnabled = false; -bool DebuggerEnabled = true; -bool ConsoleEnabled = false; +MPT_CONSTINIT bool FileEnabled = false; +MPT_CONSTINIT bool DebuggerEnabled = true; +MPT_CONSTINIT bool ConsoleEnabled = false; -static char g_FacilitySolo[1024] = {0}; -static char g_FacilityBlocked[1024] = {0}; +static MPT_CONSTINIT char g_FacilitySolo[1024] = {0}; +static MPT_CONSTINIT char g_FacilityBlocked[1024] = {0}; void SetFacilities(const std::string &solo, const std::string &blocked) { @@ -112,8 +113,8 @@ void GlobalLogger::SendLogMessage(const mpt::source_location &loc, LogLevel leve #endif // MODPLUG_TRACKER // remove eol if already present and add log level prefix const mpt::ustring message = LogLevelToString(level) + U_(": ") + mpt::trim_right(text, U_("\r\n")); - const mpt::ustring file = mpt::ToUnicode(mpt::CharsetSource, loc.file_name() ? loc.file_name() : ""); - const mpt::ustring function = mpt::ToUnicode(mpt::CharsetSource, loc.function_name() ? loc.function_name() : ""); + const mpt::ustring file = mpt::transcode(mpt::source_encoding, loc.file_name() ? loc.file_name() : ""); + const mpt::ustring function = mpt::transcode(mpt::source_encoding, loc.function_name() ? loc.function_name() : ""); const mpt::ustring line = mpt::ufmt::dec(loc.line()); #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) #if MPT_OS_WINDOWS @@ -134,7 +135,7 @@ void GlobalLogger::SendLogMessage(const mpt::source_location &loc, LogLevel leve } if(s_logfile) { - mpt::IO::WriteText(*s_logfile, mpt::ToCharset(mpt::CharsetLogfile, MPT_UFORMAT("{}+{} {}({}): {} [{}]\n") + mpt::IO::WriteText(*s_logfile, mpt::transcode(mpt::logfile_encoding, MPT_UFORMAT("{}+{} {}({}): {} [{}]\n") ( mpt::Date::ANSI::ToUString(cur) , mpt::ufmt::right(6, mpt::ufmt::dec(diff)) , file @@ -170,16 +171,16 @@ void GlobalLogger::SendLogMessage(const mpt::source_location &loc, LogLevel leve #elif defined(MODPLUG_TRACKER) && defined(MPT_BUILD_WINESUPPORT) std::clog << "NativeSupport: " - << mpt::ToCharset(mpt::CharsetStdIO, file) << "(" << mpt::ToCharset(mpt::CharsetStdIO, line) << ")" << ": " - << mpt::ToCharset(mpt::CharsetStdIO, message) - << " [" << mpt::ToCharset(mpt::CharsetStdIO, function) << "]" + << mpt::transcode(mpt::stdio_encoding, file) << "(" << mpt::transcode(mpt::stdio_encoding, line) << ")" << ": " + << mpt::transcode(mpt::stdio_encoding, message) + << " [" << mpt::transcode(mpt::stdio_encoding, function) << "]" << std::endl; #else // !MODPLUG_TRACKER std::clog << "libopenmpt: " - << mpt::ToCharset(mpt::CharsetStdIO, file) << "(" << mpt::ToCharset(mpt::CharsetStdIO, line) << ")" << ": " - << mpt::ToCharset(mpt::CharsetStdIO, message) - << " [" << mpt::ToCharset(mpt::CharsetStdIO, function) << "]" + << mpt::transcode(mpt::stdio_encoding, file) << "(" << mpt::transcode(mpt::stdio_encoding, line) << ")" << ": " + << mpt::transcode(mpt::stdio_encoding, message) + << " [" << mpt::transcode(mpt::stdio_encoding, function) << "]" << std::endl; #endif // MODPLUG_TRACKER #endif // MPT_LOG_IS_DISABLED @@ -195,9 +196,9 @@ namespace Trace { // Debugging functionality will use simple globals. -std::atomic g_Enabled{false}; +MPT_CONSTINIT std::atomic g_Enabled{false}; -static bool g_Sealed = false; +static MPT_CONSTINIT bool g_Sealed = false; struct Entry { uint32 Index; @@ -225,14 +226,19 @@ static MPT_FORCEINLINE bool operator < (const Entry &a, const Entry &b) noexcept ; } -static std::vector Entries; +#if MPT_COMPILER_MSVC +// VS2022 still does nto have constexpr vector default ctor +static /*MPT_CONSTINIT*/ std::vector Entries; +#else +static MPT_CONSTINIT std::vector Entries; +#endif -static std::atomic NextIndex(0); +static MPT_CONSTINIT std::atomic NextIndex(0); -static uint32 ThreadIdGUI = 0; -static uint32 ThreadIdAudio = 0; -static uint32 ThreadIdNotify = 0; -static uint32 ThreadIdWatchdir = 0; +static MPT_CONSTINIT uint32 ThreadIdGUI = 0; +static MPT_CONSTINIT uint32 ThreadIdAudio = 0; +static MPT_CONSTINIT uint32 ThreadIdNotify = 0; +static MPT_CONSTINIT uint32 ThreadIdWatchdir = 0; void Enable(std::size_t numEntries) { @@ -314,7 +320,7 @@ bool Dump(const mpt::PathString &filename) mpt::ofstream f(filename); - f << "Build: OpenMPT " << mpt::ToCharset(mpt::CharsetLogfile, Build::GetVersionStringExtended()) << std::endl; + f << "Build: OpenMPT " << mpt::transcode(mpt::logfile_encoding, Build::GetVersionStringExtended()) << std::endl; bool qpcValid = false; @@ -326,7 +332,7 @@ bool Dump(const mpt::PathString &filename) qpcValid = true; } - f << "Dump: " << mpt::ToCharset(mpt::CharsetLogfile, mpt::Date::ANSI::ToUString(ftNow)) << std::endl; + f << "Dump: " << mpt::transcode(mpt::logfile_encoding, mpt::Date::ANSI::ToUString(ftNow)) << std::endl; f << "Captured events: " << Entries.size() << std::endl; if(qpcValid && (Entries.size() > 0)) { @@ -343,7 +349,7 @@ bool Dump(const mpt::PathString &filename) std::string time; if(qpcValid) { - time = mpt::ToCharset(mpt::CharsetLogfile, mpt::Date::ANSI::ToUString( ftNow - static_cast( static_cast(qpcNow.QuadPart - entry.Timestamp) * (10000000.0 / static_cast(qpcFreq.QuadPart) ) ) ) ); + time = mpt::transcode(mpt::logfile_encoding, mpt::Date::ANSI::ToUString( ftNow - static_cast( static_cast(qpcNow.QuadPart - entry.Timestamp) * (10000000.0 / static_cast(qpcFreq.QuadPart) ) ) ) ); } else { time = MPT_AFORMAT("0x{}")(mpt::afmt::hex0<16>(entry.Timestamp)); diff --git a/Frameworks/OpenMPT/OpenMPT/common/misc_util.h b/Frameworks/OpenMPT/OpenMPT/common/misc_util.h index 4420a9ddd..f1317dbcd 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/misc_util.h +++ b/Frameworks/OpenMPT/OpenMPT/common/misc_util.h @@ -13,7 +13,7 @@ #include "openmpt/all/BuildSettings.hpp" #include "mpt/base/span.hpp" -#include "mpt/exception_text/exception_text.hpp" +#include "mpt/exception/exception_text.hpp" #include "mptAssert.h" #include "mptBaseMacros.h" @@ -24,7 +24,6 @@ // old #include "mptBaseUtils.h" #include "mptStringFormat.h" -#include "mptStringParse.h" #include "mptTime.h" #include diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptCPU.h b/Frameworks/OpenMPT/OpenMPT/common/mptCPU.h new file mode 100644 index 000000000..5ea23d409 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/common/mptCPU.h @@ -0,0 +1,123 @@ +/* + * mptCPU.h + * -------- + * Purpose: CPU feature detection. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include "mpt/base/macros.hpp" +#ifdef MPT_ENABLE_ARCH_INTRINSICS +#include "mpt/arch/arch.hpp" +#endif + + +OPENMPT_NAMESPACE_BEGIN + + +namespace CPU +{ + + +#ifdef MPT_ENABLE_ARCH_INTRINSICS + + + + + +#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) + + +namespace detail +{ + +inline MPT_CONSTINIT mpt::arch::current::feature_flags EnabledFeatures; +inline MPT_CONSTINIT mpt::arch::current::mode_flags EnabledModes; + +} // namespace detail + +inline void EnableAvailableFeatures() noexcept +{ + CPU::detail::EnabledFeatures = mpt::arch::get_cpu_info().get_features(); + CPU::detail::EnabledModes = mpt::arch::get_cpu_info().get_modes(); +} + +// enabled processor features for inline asm and intrinsics +[[nodiscard]] MPT_FORCEINLINE mpt::arch::current::feature_flags GetEnabledFeatures() noexcept +{ + return CPU::detail::EnabledFeatures; +} +[[nodiscard]] MPT_FORCEINLINE mpt::arch::current::mode_flags GetEnabledModes() noexcept +{ + return CPU::detail::EnabledModes; +} + +struct Info +{ + [[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) const noexcept + { + return features == (GetEnabledFeatures() & features); + } + [[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) const noexcept + { + return modes == (GetEnabledModes() & modes); + } +}; + + +#else // !MODPLUG_TRACKER + + +struct Info +{ +private: + const mpt::arch::flags_cache m_flags{mpt::arch::get_cpu_info()}; +public: + [[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) const noexcept + { + return m_flags[features]; + } + [[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) const noexcept + { + return m_flags[modes]; + } +}; + + +#endif // MODPLUG_TRACKER + + + + + +// legacy interface + +namespace feature = mpt::arch::current::feature; +namespace mode = mpt::arch::current::mode; + +[[nodiscard]] MPT_FORCEINLINE bool HasFeatureSet(mpt::arch::current::feature_flags features) noexcept +{ + return CPU::Info{}.HasFeatureSet(features); +} + +[[nodiscard]] MPT_FORCEINLINE bool HasModesEnabled(mpt::arch::current::mode_flags modes) noexcept +{ + return CPU::Info{}.HasModesEnabled(modes); +} + + + + +#endif // MPT_ENABLE_ARCH_INTRINSICS + + +} // namespace CPU + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp index a38dd7790..9cb265eff 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp @@ -11,19 +11,6 @@ #include "stdafx.h" #include "mptFileIO.h" -#if defined(MPT_ENABLE_FILEIO) -#include "mpt/io/io.hpp" -#include "mpt/io/io_stdstream.hpp" -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS -#include "mpt/system_error/system_error.hpp" -#include "FileReader.h" -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS -#endif // MPT_ENABLE_FILEIO - -#if defined(MPT_ENABLE_FILEIO) -#include -#endif // MPT_ENABLE_FILEIO - #ifdef MODPLUG_TRACKER #if MPT_OS_WINDOWS #include @@ -32,14 +19,6 @@ #endif // MPT_OS_WINDOWS #endif // MODPLUG_TRACKER -#if defined(MPT_ENABLE_FILEIO) -#if MPT_COMPILER_MSVC -#include -#include -#endif // MPT_COMPILER_MSVC -#endif // MPT_ENABLE_FILEIO - - OPENMPT_NAMESPACE_BEGIN @@ -47,7 +26,6 @@ OPENMPT_NAMESPACE_BEGIN #if defined(MPT_ENABLE_FILEIO) - #if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS) #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) @@ -59,9 +37,10 @@ MPT_WARNING("Warning: MinGW with GCC earlier than 9.1 detected. Standard library #endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS - #ifdef MODPLUG_TRACKER + #if MPT_OS_WINDOWS + bool SetFilesystemCompression(HANDLE hFile) { if(hFile == INVALID_HANDLE_VALUE) @@ -73,6 +52,7 @@ bool SetFilesystemCompression(HANDLE hFile) BOOL result = DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, (LPVOID)&format, sizeof(format), NULL, 0, &dummy /*required*/ , NULL); return result != FALSE; } + bool SetFilesystemCompression(int fd) { if(fd < 0) @@ -87,9 +67,10 @@ bool SetFilesystemCompression(int fd) } return SetFilesystemCompression(hFile); } + bool SetFilesystemCompression(const mpt::PathString &filename) { - DWORD attributes = GetFileAttributes(filename.AsNativePrefixed().c_str()); + DWORD attributes = GetFileAttributes(mpt::support_long_path(filename.AsNative()).c_str()); if(attributes == INVALID_FILE_ATTRIBUTES) { return false; @@ -98,7 +79,7 @@ bool SetFilesystemCompression(const mpt::PathString &filename) { return true; } - HANDLE hFile = CreateFile(filename.AsNativePrefixed().c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE hFile = CreateFile(mpt::support_long_path(filename.AsNative()).c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if(hFile == INVALID_HANDLE_VALUE) { return false; @@ -107,501 +88,12 @@ bool SetFilesystemCompression(const mpt::PathString &filename) CloseHandle(hFile); return result; } + #endif // MPT_OS_WINDOWS -#endif // MODPLUG_TRACKER - - - -#ifdef MODPLUG_TRACKER - -namespace mpt { - -#if MPT_COMPILER_MSVC - -mpt::tstring SafeOutputFile::convert_mode(std::ios_base::openmode mode, FlushMode flushMode) -{ - mpt::tstring fopen_mode; - switch(mode & ~(std::ios_base::ate | std::ios_base::binary)) - { - case std::ios_base::in: - fopen_mode = _T("r"); - break; - case std::ios_base::out: - [[fallthrough]]; - case std::ios_base::out | std::ios_base::trunc: - fopen_mode = _T("w"); - break; - case std::ios_base::app: - [[fallthrough]]; - case std::ios_base::out | std::ios_base::app: - fopen_mode = _T("a"); - break; - case std::ios_base::out | std::ios_base::in: - fopen_mode = _T("r+"); - break; - case std::ios_base::out | std::ios_base::in | std::ios_base::trunc: - fopen_mode = _T("w+"); - break; - case std::ios_base::out | std::ios_base::in | std::ios_base::app: - [[fallthrough]]; - case std::ios_base::in | std::ios_base::app: - fopen_mode = _T("a+"); - break; - } - if(fopen_mode.empty()) - { - return fopen_mode; - } - if(mode & std::ios_base::binary) - { - fopen_mode += _T("b"); - } - if(flushMode == FlushMode::Full) - { - fopen_mode += _T("c"); // force commit on fflush (MSVC specific) - } - return fopen_mode; -} - -std::FILE * SafeOutputFile::internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode) -{ - m_f = nullptr; - mpt::tstring fopen_mode = convert_mode(mode, flushMode); - if(fopen_mode.empty()) - { - return nullptr; - } - std::FILE *f = - #ifdef UNICODE - _wfopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str()) - #else - std::fopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str()) - #endif - ; - if(!f) - { - return nullptr; - } - if(mode & std::ios_base::ate) - { - if(std::fseek(f, 0, SEEK_END) != 0) - { - std::fclose(f); - f = nullptr; - return nullptr; - } - } - m_f = f; - return f; -} - -#endif // MPT_COMPILER_MSVC - -// cppcheck-suppress exceptThrowInDestructor -SafeOutputFile::~SafeOutputFile() noexcept(false) -{ - const bool mayThrow = (std::uncaught_exceptions() == 0); - if(!stream()) - { - #if MPT_COMPILER_MSVC - if(m_f) - { - std::fclose(m_f); - } - #endif // MPT_COMPILER_MSVC - if(mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) - { - // cppcheck-suppress exceptThrowInDestructor - throw std::ios_base::failure(std::string("Error before flushing file buffers.")); - } - return; - } - if(!stream().rdbuf()) - { - #if MPT_COMPILER_MSVC - if(m_f) - { - std::fclose(m_f); - } - #endif // MPT_COMPILER_MSVC - if(mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) - { - // cppcheck-suppress exceptThrowInDestructor - throw std::ios_base::failure(std::string("Error before flushing file buffers.")); - } - return; - } -#if MPT_COMPILER_MSVC - if(!m_f) - { - return; - } -#endif // MPT_COMPILER_MSVC - bool errorOnFlush = false; - if(m_FlushMode != FlushMode::None) - { - try - { - if(stream().rdbuf()->pubsync() != 0) - { - errorOnFlush = true; - } - } catch(const std::exception &) - { - errorOnFlush = true; -#if MPT_COMPILER_MSVC - if(m_FlushMode != FlushMode::None) - { - if(std::fflush(m_f) != 0) - { - errorOnFlush = true; - } - } - if(std::fclose(m_f) != 0) - { - errorOnFlush = true; - } -#endif // MPT_COMPILER_MSVC - if(mayThrow) - { - // ignore errorOnFlush here, and re-throw the earlier exception - // cppcheck-suppress exceptThrowInDestructor - throw; - } - } - } -#if MPT_COMPILER_MSVC - if(m_FlushMode != FlushMode::None) - { - if(std::fflush(m_f) != 0) - { - errorOnFlush = true; - } - } - if(std::fclose(m_f) != 0) - { - errorOnFlush = true; - } -#endif // MPT_COMPILER_MSVC - if(mayThrow && errorOnFlush && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) - { - // cppcheck-suppress exceptThrowInDestructor - throw std::ios_base::failure(std::string("Error flushing file buffers.")); - } -} - -} // namespace mpt #endif // MODPLUG_TRACKER - -#ifdef MODPLUG_TRACKER - -namespace mpt { - -LazyFileRef & LazyFileRef::operator = (const std::vector &data) -{ - mpt::ofstream file(m_Filename, std::ios::binary); - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::WriteRaw(file, mpt::as_span(data)); - mpt::IO::Flush(file); - return *this; -} - -LazyFileRef & LazyFileRef::operator = (const std::vector &data) -{ - mpt::ofstream file(m_Filename, std::ios::binary); - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::WriteRaw(file, mpt::as_span(data)); - mpt::IO::Flush(file); - return *this; -} - -LazyFileRef & LazyFileRef::operator = (const std::string &data) -{ - mpt::ofstream file(m_Filename, std::ios::binary); - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::WriteRaw(file, mpt::as_span(data)); - mpt::IO::Flush(file); - return *this; -} - -LazyFileRef::operator std::vector () const -{ - mpt::ifstream file(m_Filename, std::ios::binary); - if(!mpt::IO::IsValid(file)) - { - return std::vector(); - } - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::SeekEnd(file); - std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); - mpt::IO::SeekBegin(file); - mpt::IO::ReadRaw(file, mpt::as_span(buf)); - return buf; -} - -LazyFileRef::operator std::vector () const -{ - mpt::ifstream file(m_Filename, std::ios::binary); - if(!mpt::IO::IsValid(file)) - { - return std::vector(); - } - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::SeekEnd(file); - std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); - mpt::IO::SeekBegin(file); - mpt::IO::ReadRaw(file, mpt::as_span(buf)); - return buf; -} - -LazyFileRef::operator std::string () const -{ - mpt::ifstream file(m_Filename, std::ios::binary); - if(!mpt::IO::IsValid(file)) - { - return std::string(); - } - file.exceptions(std::ios_base::failbit | std::ios_base::badbit); - mpt::IO::SeekEnd(file); - std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); - mpt::IO::SeekBegin(file); - mpt::IO::ReadRaw(file, mpt::as_span(buf)); - return mpt::buffer_cast(buf); -} - -} // namespace mpt - -#endif // MODPLUG_TRACKER - - -InputFile::InputFile(const mpt::PathString &filename, bool allowWholeFileCaching) - : m_IsValid(false) - , m_IsCached(false) -{ - MPT_ASSERT(!filename.empty()); - Open(filename, allowWholeFileCaching); -} - -InputFile::~InputFile() -{ - return; -} - - -bool InputFile::Open(const mpt::PathString &filename, bool allowWholeFileCaching) -{ - m_IsCached = false; - m_Cache.resize(0); - m_Cache.shrink_to_fit(); - m_Filename = filename; - m_File.open(m_Filename, std::ios::binary | std::ios::in); - if(allowWholeFileCaching) - { - if(mpt::IO::IsReadSeekable(m_File)) - { - if(!mpt::IO::SeekEnd(m_File)) - { - m_File.close(); - return false; - } - mpt::IO::Offset filesize = mpt::IO::TellRead(m_File); - if(!mpt::IO::SeekBegin(m_File)) - { - m_File.close(); - return false; - } - if(mpt::in_range(filesize)) - { - std::size_t buffersize = mpt::saturate_cast(filesize); - m_Cache.resize(buffersize); - if(mpt::IO::ReadRaw(m_File, mpt::as_span(m_Cache)).size() != mpt::saturate_cast(filesize)) - { - m_File.close(); - return false; - } - if(!mpt::IO::SeekBegin(m_File)) - { - m_File.close(); - return false; - } - m_IsCached = true; - m_IsValid = true; - return true; - } - } - } - m_IsValid = true; - return m_File.good(); -} - - -bool InputFile::IsValid() const -{ - return m_IsValid && m_File.good(); -} - - -bool InputFile::IsCached() const -{ - return m_IsCached; -} - - -mpt::PathString InputFile::GetFilename() const -{ - return m_Filename; -} - - -std::istream& InputFile::GetStream() -{ - MPT_ASSERT(!m_IsCached); - return m_File; -} - - -mpt::const_byte_span InputFile::GetCache() -{ - MPT_ASSERT(m_IsCached); - return mpt::as_span(m_Cache); -} - - - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - - -OnDiskFileWrapper::OnDiskFileWrapper(FileCursor &file, const mpt::PathString &fileNameExtension) - : m_IsTempFile(false) -{ - try - { - file.Rewind(); - if(!file.GetOptionalFileName()) - { - const mpt::PathString tempName = mpt::CreateTempFileName(P_("OpenMPT"), fileNameExtension); - -#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT -#if (_WIN32_WINNT < 0x0602) -#define MPT_ONDISKFILEWRAPPER_NO_CREATEFILE -#endif -#endif - -#ifdef MPT_ONDISKFILEWRAPPER_NO_CREATEFILE - - mpt::ofstream f(tempName, std::ios::binary); - if(!f) - { - throw std::runtime_error("Error creating temporary file."); - } - while(!file.EndOfFile()) - { - FileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); - std::size_t towrite = view.size(); - std::size_t written = 0; - do - { - std::size_t chunkSize = mpt::saturate_cast(towrite); - bool chunkOk = false; - chunkOk = mpt::IO::WriteRaw(f, mpt::const_byte_span(view.data() + written, chunkSize)); - if(!chunkOk) - { - throw std::runtime_error("Incomplete Write."); - } - towrite -= chunkSize; - written += chunkSize; - } while(towrite > 0); - } - f.close(); - -#else // !MPT_ONDISKFILEWRAPPER_NO_CREATEFILE - - HANDLE hFile = NULL; - #if MPT_OS_WINDOWS_WINRT - hFile = mpt::windows::CheckFileHANDLE(CreateFile2(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL)); - #else - hFile = mpt::windows::CheckFileHANDLE(CreateFile(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL)); - #endif - while(!file.EndOfFile()) - { - FileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); - std::size_t towrite = view.size(); - std::size_t written = 0; - do - { - DWORD chunkSize = mpt::saturate_cast(towrite); - DWORD chunkDone = 0; - try - { - mpt::windows::CheckBOOL(WriteFile(hFile, view.data() + written, chunkSize, &chunkDone, NULL)); - } catch(...) - { - CloseHandle(hFile); - hFile = NULL; - throw; - } - if(chunkDone != chunkSize) - { - CloseHandle(hFile); - hFile = NULL; - throw std::runtime_error("Incomplete WriteFile()."); - } - towrite -= chunkDone; - written += chunkDone; - } while(towrite > 0); - } - CloseHandle(hFile); - hFile = NULL; - -#endif // MPT_ONDISKFILEWRAPPER_NO_CREATEFILE - - m_Filename = tempName; - m_IsTempFile = true; - } else - { - m_Filename = file.GetOptionalFileName().value(); - } - } catch (const std::runtime_error &) - { - m_IsTempFile = false; - m_Filename = mpt::PathString(); - } -} - - -OnDiskFileWrapper::~OnDiskFileWrapper() -{ - if(m_IsTempFile) - { - DeleteFile(m_Filename.AsNative().c_str()); - m_IsTempFile = false; - } - m_Filename = mpt::PathString(); -} - - -bool OnDiskFileWrapper::IsValid() const -{ - return !m_Filename.empty(); -} - - -mpt::PathString OnDiskFileWrapper::GetFilename() const -{ - return m_Filename; -} - - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - -#else // !MPT_ENABLE_FILEIO - -MPT_MSVC_WORKAROUND_LNK4221(mptFileIO) - #endif // MPT_ENABLE_FILEIO diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h b/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h index 5c0112ce4..88c658875 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h @@ -13,28 +13,17 @@ #if defined(MPT_ENABLE_FILEIO) -#include "mpt/io_read/filecursor_memory.hpp" -#include "mpt/io_read/filecursor_stdstream.hpp" +#include "mpt/base/detect_libcxx.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/io_file/fstream.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptString.h" #include "../common/mptPathString.h" #include "../common/FileReaderFwd.h" -#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) -#if MPT_GCC_AT_LEAST(9,1,0) -#include -#endif // MPT_GCC_AT_LEAST(9,1,0) -#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR -#include -#include -#include -#include #include -#if MPT_COMPILER_MSVC -#include -#endif // !MPT_COMPILER_MSVC - #ifdef MODPLUG_TRACKER #if MPT_OS_WINDOWS #include @@ -66,331 +55,27 @@ bool SetFilesystemCompression(const mpt::PathString &filename); namespace mpt { -namespace detail -{ - -template -inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::ios_base::openmode mode) -{ - #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) - #if MPT_GCC_AT_LEAST(9,1,0) - base.open(static_cast(filename.AsNative()), mode); - #else // !MPT_GCC_AT_LEAST(9,1,0) - // Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable. - base.open(mpt::ToCharset(mpt::Charset::Locale, filename.AsNative()).c_str(), mode); - #endif // MPT_GCC_AT_LEAST(9,1,0) - #else // !MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR - base.open(filename.AsNativePrefixed().c_str(), mode); - #endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR -} - -} // namespace detail - -// We cannot rely on implicit conversion of mpt::PathString to std::filesystem::path when constructing std::fstream -// because of broken overload implementation in GCC libstdc++ 8, 9, 10. -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95642 -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90704 - -class fstream - : public std::fstream -{ -private: - typedef std::fstream Tbase; -public: - fstream() {} - fstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - { - detail::fstream_open(*this, filename, mode); - } -#if MPT_COMPILER_MSVC -protected: - fstream(std::FILE * file) - : std::fstream(file) - { - } -#endif // MPT_COMPILER_MSVC -public: - void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - { - detail::fstream_open(*this, filename, mode); - } - void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; - void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; -#if MPT_OS_WINDOWS - void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; - void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; -#endif -}; - -class ifstream - : public std::ifstream -{ -private: - typedef std::ifstream Tbase; -public: - ifstream() {} - ifstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in) - { - detail::fstream_open(*this, filename, mode); - } -#if MPT_COMPILER_MSVC -protected: - ifstream(std::FILE * file) - : std::ifstream(file) - { - } -#endif // MPT_COMPILER_MSVC -public: - void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in) - { - detail::fstream_open(*this, filename, mode); - } - void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; - void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; -#if MPT_OS_WINDOWS - void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; - void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; -#endif -}; - -class ofstream - : public std::ofstream -{ -private: - typedef std::ofstream Tbase; -public: - ofstream() {} - ofstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out) - { - detail::fstream_open(*this, filename, mode); - } -#if MPT_COMPILER_MSVC -protected: - ofstream(std::FILE * file) - : std::ofstream(file) - { - } -#endif // MPT_COMPILER_MSVC -public: - void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out) - { - detail::fstream_open(*this, filename, mode); - } - void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; - void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; -#if MPT_OS_WINDOWS - void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; - void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; -#endif -}; - -enum class FlushMode -{ - None = 0, // no explicit flushes at all - Single = 1, // explicitly flush higher-leverl API layers - Full = 2, // explicitly flush *all* layers, up to and including disk write caches -}; - -inline FlushMode FlushModeFromBool(bool flush) -{ - return flush ? FlushMode::Full : FlushMode::None; -} - -#ifdef MODPLUG_TRACKER - -class SafeOutputFile -{ -private: - FlushMode m_FlushMode; -#if MPT_COMPILER_MSVC - std::FILE *m_f = nullptr; -#else // !MPT_COMPILER_MSVC - mpt::ofstream m_s; -#endif // MPT_COMPILER_MSVC -#if MPT_COMPILER_MSVC - class FILEostream - : public mpt::ofstream - { - public: - FILEostream(std::FILE * file) - : mpt::ofstream(file) - { - return; - } - }; - FILEostream m_s; - static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode); - std::FILE * internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode); -#endif // MPT_COMPILER_MSVC -public: - SafeOutputFile() = delete; - explicit SafeOutputFile(const mpt::PathString &filename, std::ios_base::openmode mode = std::ios_base::out, FlushMode flushMode = FlushMode::Full) - : m_FlushMode(flushMode) -#if MPT_COMPILER_MSVC - , m_s(internal_fopen(filename, mode | std::ios_base::out, flushMode)) -#else // !MPT_COMPILER_MSVC - , m_s(filename, mode) -#endif // MPT_COMPILER_MSVC - { - if(!stream().is_open()) - { - stream().setstate(mpt::ofstream::failbit); - } - } - mpt::ofstream& stream() - { - return m_s; - } - operator mpt::ofstream& () - { - return stream(); - } - const mpt::ofstream& stream() const - { - return m_s; - } - operator const mpt::ofstream& () const - { - return stream(); - } - operator bool() const - { - return stream() ? true : false; - } - bool operator!() const - { - return stream().operator!(); - } - ~SafeOutputFile() noexcept(false); -}; - -#endif // MODPLUG_TRACKER - - - -#ifdef MODPLUG_TRACKER - -// LazyFileRef is a simple reference to an on-disk file by the means of a -// filename which allows easy assignment of the whole file contents to and from -// byte buffers. -class LazyFileRef { -private: - const mpt::PathString m_Filename; -public: - LazyFileRef(const mpt::PathString &filename) - : m_Filename(filename) - { - return; - } -public: - LazyFileRef & operator = (const std::vector &data); - LazyFileRef & operator = (const std::vector &data); - LazyFileRef & operator = (const std::string &data); - operator std::vector () const; - operator std::vector () const; - operator std::string () const; -}; - -#endif // MODPLUG_TRACKER - +using fstream = mpt::IO::fstream; +using ifstream = mpt::IO::ifstream; +using ofstream = mpt::IO::ofstream; } // namespace mpt -class InputFile -{ -private: - mpt::PathString m_Filename; - mpt::ifstream m_File; - bool m_IsValid; - bool m_IsCached; - std::vector m_Cache; -public: - InputFile(const mpt::PathString &filename, bool allowWholeFileCaching = false); - ~InputFile(); - bool IsValid() const; - bool IsCached() const; - mpt::PathString GetFilename() const; - std::istream& GetStream(); - mpt::const_byte_span GetCache(); -private: - bool Open(const mpt::PathString &filename, bool allowWholeFileCaching = false); -}; - - -template -inline FileCursor make_FileCursor(Targ1 &&arg1) -{ - return mpt::IO::make_FileCursor(std::forward(arg1)); -} - -template -inline FileCursor make_FileCursor(Targ1 &&arg1, Targ2 &&arg2) -{ - return mpt::IO::make_FileCursor(std::forward(arg1), std::forward(arg2)); -} - - -// templated in order to reduce header inter-dependencies -class InputFile; -template ::value, bool> = true> -inline FileCursor make_FileCursor(TInputFile &file) -{ - if(!file.IsValid()) - { - return FileCursor(); - } - if(file.IsCached()) - { - return mpt::IO::make_FileCursor(file.GetCache(), std::make_shared(file.GetFilename())); - } else - { - return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); - } -} - - template inline FileCursor GetFileReader(Targ1 &&arg1) { - return make_FileCursor(std::forward(arg1)); + return mpt::IO::make_FileCursor(std::forward(arg1)); } template inline FileCursor GetFileReader(Targ1 &&arg1, Targ2 &&arg2) { - return make_FileCursor(std::forward(arg1), std::forward(arg2)); + return mpt::IO::make_FileCursor(std::forward(arg1), std::forward(arg2)); } -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -class OnDiskFileWrapper -{ - -private: - - mpt::PathString m_Filename; - bool m_IsTempFile; - -public: - - OnDiskFileWrapper(FileCursor& file, const mpt::PathString& fileNameExtension = P_("tmp")); - - ~OnDiskFileWrapper(); - -public: - - bool IsValid() const; - - mpt::PathString GetFilename() const; - -}; // class OnDiskFileWrapper - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - #endif // MPT_ENABLE_FILEIO diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.cpp new file mode 100644 index 000000000..72894e8c2 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.cpp @@ -0,0 +1,114 @@ +/* + * mptFileTemporary.cpp + * -------------------- + * Purpose: + * Notes : Currently none. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" +#include "mptFileTemporary.h" + +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS +#include "mpt/fs/common_directories.hpp" +#include "mpt/fs/fs.hpp" +#include "mpt/io_file_unique/unique_basename.hpp" +#include "mpt/io_file_unique/unique_tempfilename.hpp" +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS +#include "mpt/string_transcode/transcode.hpp" +#include "mpt/uuid/uuid.hpp" + +#include "mptRandom.h" + +#if MPT_OS_WINDOWS +#include +#endif + + + +OPENMPT_NAMESPACE_BEGIN + + + +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS + + + +namespace mpt +{ + + + +TemporaryPathname::TemporaryPathname(const mpt::PathString &fileNameExtension) +{ + mpt::PathString prefix; +#if defined(LIBOPENMPT_BUILD) + prefix = P_("libopenmpt"); +#else + prefix = P_("OpenMPT"); +#endif + m_Path = mpt::PathString::FromNative(mpt::IO::unique_tempfilename{mpt::IO::unique_basename{prefix, mpt::UUID::GenerateLocalUseOnly(mpt::global_prng())}, fileNameExtension}); +} + + + +TempFileGuard::TempFileGuard(const mpt::TemporaryPathname &pathname) + : filename(pathname.GetPathname()) +{ + return; +} + +mpt::PathString TempFileGuard::GetFilename() const +{ + return filename; +} + +TempFileGuard::~TempFileGuard() +{ + if(!filename.empty()) + { + DeleteFile(filename.AsNative().c_str()); + } +} + + +TempDirGuard::TempDirGuard(const mpt::TemporaryPathname &pathname) + : dirname(pathname.GetPathname().WithTrailingSlash()) +{ + if(dirname.empty()) + { + return; + } + if(::CreateDirectory(dirname.AsNative().c_str(), NULL) == 0) + { // fail + dirname = mpt::PathString(); + } +} + +mpt::PathString TempDirGuard::GetDirname() const +{ + return dirname; +} + +TempDirGuard::~TempDirGuard() +{ + if(!dirname.empty()) + { + mpt::native_fs{}.delete_tree(dirname); + } +} + + + +} // namespace mpt + + + +#else +MPT_MSVC_WORKAROUND_LNK4221(mptFileTemporary) +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS + + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.h b/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.h new file mode 100644 index 000000000..9cc9a0c9f --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileTemporary.h @@ -0,0 +1,84 @@ +/* + * mptFileTemporary.h + * ------------------ + * Purpose: + * Notes : Currently none. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include "mpt/base/namespace.hpp" + +#include "mptPathString.h" + + +OPENMPT_NAMESPACE_BEGIN + + + +namespace mpt +{ + + + +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS + + + +// Returns a new unique absolute path. +class TemporaryPathname +{ +private: + mpt::PathString m_Path; +public: + TemporaryPathname(const mpt::PathString &fileNameExtension = P_("tmp")); +public: + mpt::PathString GetPathname() const + { + return m_Path; + } +}; + + + +// Scoped temporary file guard. Deletes the file when going out of scope. +// The file itself is not created automatically. +class TempFileGuard +{ +private: + const mpt::PathString filename; +public: + TempFileGuard(const mpt::TemporaryPathname &pathname = mpt::TemporaryPathname{}); + mpt::PathString GetFilename() const; + ~TempFileGuard(); +}; + + +// Scoped temporary directory guard. Deletes the directory when going out of scope. +// The directory itself is created automatically. +class TempDirGuard +{ +private: + mpt::PathString dirname; +public: + TempDirGuard(const mpt::TemporaryPathname &pathname = mpt::TemporaryPathname{}); + mpt::PathString GetDirname() const; + ~TempDirGuard(); +}; + + + +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS + + + +} // namespace mpt + + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileType.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptFileType.cpp new file mode 100644 index 000000000..36380ed87 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileType.cpp @@ -0,0 +1,141 @@ +/* + * mptFileType.cpp + * --------------- + * Purpose: + * Notes : Currently none. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" +#include "mptFileType.h" + + +OPENMPT_NAMESPACE_BEGIN + + + +#ifdef MODPLUG_TRACKER + + + +mpt::PathString FileType::AsFilterString(FlagSet format) const +{ + mpt::PathString filter; + if(GetShortName().empty() || GetExtensions().empty()) + { + return filter; + } + if(!GetDescription().empty()) + { + filter += mpt::PathString::FromUnicode(GetDescription()); + } else + { + filter += mpt::PathString::FromUnicode(GetShortName()); + } + const auto extensions = GetExtensions(); + if(format[FileTypeFormatShowExtensions]) + { + filter += P_(" ("); + bool first = true; + for(const auto &ext : extensions) + { + if(first) + { + first = false; + } else + { + filter += P_(","); + } + filter += P_("*."); + filter += ext; + } + filter += P_(")"); + } + filter += P_("|"); + { + bool first = true; + for(const auto &ext : extensions) + { + if(first) + { + first = false; + } else + { + filter += P_(";"); + } + filter += P_("*."); + filter += ext; + } + } + filter += P_("|"); + return filter; +} + + +mpt::PathString FileType::AsFilterOnlyString() const +{ + mpt::PathString filter; + const auto extensions = GetExtensions(); + { + bool first = true; + for(const auto &ext : extensions) + { + if(first) + { + first = false; + } else + { + filter += P_(";"); + } + filter += P_("*."); + filter += ext; + } + } + return filter; +} + + +mpt::PathString ToFilterString(const FileType &fileType, FlagSet format) +{ + return fileType.AsFilterString(format); +} + + +mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format) +{ + mpt::PathString filter; + for(const auto &type : fileTypes) + { + filter += type.AsFilterString(format); + } + return filter; +} + + +mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty) +{ + mpt::PathString filter = fileType.AsFilterOnlyString(); + return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; +} + + +mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty) +{ + mpt::PathString filter; + for(const auto &type : fileTypes) + { + filter += type.AsFilterOnlyString(); + } + return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; +} + + + +#else +MPT_MSVC_WORKAROUND_LNK4221(mptFileType) +#endif // MODPLUG_TRACKER + + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptFileType.h b/Frameworks/OpenMPT/OpenMPT/common/mptFileType.h new file mode 100644 index 000000000..bed44180b --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/common/mptFileType.h @@ -0,0 +1,95 @@ +/* + * mptFileType.h + * ------------- + * Purpose: + * Notes : Currently none. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#include "mpt/base/alloc.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/string/types.hpp" + +#include "openmpt/base/FlagSet.hpp" + +#include + + + +OPENMPT_NAMESPACE_BEGIN + + + +#if defined(MODPLUG_TRACKER) + +enum FileTypeFormat +{ + FileTypeFormatNone = 0 , // do not show extensions after description, i.e. "Foo Files" + FileTypeFormatShowExtensions = 1<<0, // show extensions after descripten, i.e. "Foo Files (*.foo,*.bar)" +}; +MPT_DECLARE_ENUM(FileTypeFormat) + +class FileType +{ +private: + mpt::ustring m_ShortName; // "flac", "mod" (lowercase) + mpt::ustring m_Description; // "FastTracker 2 Module" + std::vector m_MimeTypes; // "audio/ogg" (in ASCII) + std::vector m_Extensions; // "mod", "xm" (lowercase) + std::vector m_Prefixes; // "mod" for "mod.*" +public: + FileType() { } + FileType(const std::vector &group) + { + for(const auto &type : group) + { + mpt::append(m_MimeTypes, type.m_MimeTypes); + mpt::append(m_Extensions, type.m_Extensions); + mpt::append(m_Prefixes, type.m_Prefixes); + } + } + static FileType Any() + { + return FileType().ShortName(U_("*")).Description(U_("All Files")).AddExtension(P_("*")); + } +public: + FileType& ShortName(const mpt::ustring &shortName) { m_ShortName = shortName; return *this; } + FileType& Description(const mpt::ustring &description) { m_Description = description; return *this; } + FileType& MimeTypes(const std::vector &mimeTypes) { m_MimeTypes = mimeTypes; return *this; } + FileType& Extensions(const std::vector &extensions) { m_Extensions = extensions; return *this; } + FileType& Prefixes(const std::vector &prefixes) { m_Prefixes = prefixes; return *this; } + FileType& AddMimeType(const std::string &mimeType) { m_MimeTypes.push_back(mimeType); return *this; } + FileType& AddExtension(const mpt::PathString &extension) { m_Extensions.push_back(extension); return *this; } + FileType& AddPrefix(const mpt::PathString &prefix) { m_Prefixes.push_back(prefix); return *this; } +public: + mpt::ustring GetShortName() const { return m_ShortName; } + mpt::ustring GetDescription() const { return m_Description; } + std::vector GetMimeTypes() const { return m_MimeTypes; } + std::vector GetExtensions() const { return m_Extensions; } + std::vector GetPrefixes() const { return m_Prefixes; } +public: + mpt::PathString AsFilterString(FlagSet format = FileTypeFormatNone) const; + mpt::PathString AsFilterOnlyString() const; +}; // class FileType + + +// "Ogg Vorbis|*.ogg;*.oga|" // FileTypeFormatNone +// "Ogg Vorbis (*.ogg,*.oga)|*.ogg;*.oga|" // FileTypeFormatShowExtensions +mpt::PathString ToFilterString(const FileType &fileType, FlagSet format = FileTypeFormatNone); +mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format = FileTypeFormatNone); + +// "*.ogg;*.oga" / ";*.ogg;*.oga" +mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty = false); +mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty = false); + +#endif // MODPLUG_TRACKER + + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp index d41a54941..ac677d2f4 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp @@ -10,370 +10,98 @@ #include "stdafx.h" #include "mptPathString.h" -#include "mpt/uuid/uuid.hpp" +#include "mpt/path/os_path_long.hpp" -#include "misc_util.h" +#include -#include "mptRandom.h" +#if MPT_OS_WINDOWS +#include +#endif #if MPT_OS_WINDOWS #include -#if defined(MODPLUG_TRACKER) -#include -#endif -#include #endif OPENMPT_NAMESPACE_BEGIN -#if MPT_OS_WINDOWS + namespace mpt { -RawPathString PathString::AsNativePrefixed() const -{ -#if MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00) - // For WinRT on Windows 8, there is no official wy to determine an absolute path. - return path; -#else - if(path.length() < MAX_PATH || path.substr(0, 4) == PL_("\\\\?\\")) - { - // Path is short enough or already in prefixed form - return path; - } - const RawPathString absPath = mpt::GetAbsolutePath(*this).AsNative(); - if(absPath.substr(0, 2) == PL_("\\\\")) - { - // Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar - return PL_("\\\\?\\UNC") + absPath.substr(1); - } else - { - // Regular file: C:\foo.bar -> \\?\C:\foo.bar - return PL_("\\\\?\\") + absPath; - } -#endif -} +#if MPT_OS_WINDOWS #if !MPT_OS_WINDOWS_WINRT -int PathString::CompareNoCase(const PathString & a, const PathString & b) +int PathCompareNoCase(const PathString & a, const PathString & b) { - return lstrcmpi(a.path.c_str(), b.path.c_str()); + return lstrcmpi(a.AsNative().c_str(), b.AsNative().c_str()); } #endif // !MPT_OS_WINDOWS_WINRT - -// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries -// Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH -// and unlimited versions are only available on Windows 8 and later. -// Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes. -PathString PathString::Simplify() const -{ - if(path.empty()) - return PathString(); - - std::vector components; - RawPathString root; - RawPathString::size_type startPos = 0; - if(path.size() >= 2 && path[1] == PC_(':')) - { - // Drive letter - root = path.substr(0, 2) + PC_('\\'); - startPos = 2; - } else if(path.substr(0, 2) == PL_("\\\\")) - { - // Network share - root = PL_("\\\\"); - startPos = 2; - } else if(path.substr(0, 2) == PL_(".\\") || path.substr(0, 2) == PL_("./")) - { - // Special case for relative paths - root = PL_(".\\"); - startPos = 2; - } else if(path.size() >= 1 && (path[0] == PC_('\\') || path[0] == PC_('/'))) - { - // Special case for relative paths - root = PL_("\\"); - startPos = 1; - } - - while(startPos < path.size()) - { - auto pos = path.find_first_of(PL_("\\/"), startPos); - if(pos == RawPathString::npos) - pos = path.size(); - mpt::RawPathString dir = path.substr(startPos, pos - startPos); - if(dir == PL_("..")) - { - // Go back one directory - if(!components.empty()) - { - components.pop_back(); - } - } else if(dir == PL_(".")) - { - // nop - } else if(!dir.empty()) - { - components.push_back(std::move(dir)); - } - startPos = pos + 1; - } - - RawPathString result = root; - result.reserve(path.size()); - for(const auto &component : components) - { - result += component + PL_("\\"); - } - if(!components.empty()) - result.pop_back(); - return mpt::PathString(result); -} - -} // namespace mpt - #endif // MPT_OS_WINDOWS -namespace mpt -{ - #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS -void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const -{ - // We cannot use CRT splitpath here, because: - // * limited to _MAX_PATH or similar - // * no support for UNC paths - // * no support for \\?\ prefixed paths - - if(drive) *drive = mpt::PathString(); - if(dir) *dir = mpt::PathString(); - if(fname) *fname = mpt::PathString(); - if(ext) *ext = mpt::PathString(); - - mpt::RawPathString p = path; - - // remove \\?\\ prefix - if(p.substr(0, 8) == PL_("\\\\?\\UNC\\")) - { - p = PL_("\\\\") + p.substr(8); - } else if(p.substr(0, 4) == PL_("\\\\?\\")) - { - p = p.substr(4); - } - - if (p.length() >= 2 && ( - p.substr(0, 2) == PL_("\\\\") - || p.substr(0, 2) == PL_("\\/") - || p.substr(0, 2) == PL_("/\\") - || p.substr(0, 2) == PL_("//") - )) - { // UNC - mpt::RawPathString::size_type first_slash = p.substr(2).find_first_of(PL_("\\/")); - if(first_slash != mpt::RawPathString::npos) - { - mpt::RawPathString::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(PL_("\\/")); - if(second_slash != mpt::RawPathString::npos) - { - if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2 + first_slash + 1 + second_slash)); - p = p.substr(2 + first_slash + 1 + second_slash); - } else - { - if(drive) *drive = mpt::PathString::FromNative(p); - p = mpt::RawPathString(); - } - } else - { - if(drive) *drive = mpt::PathString::FromNative(p); - p = mpt::RawPathString(); - } - } else - { // local - if(p.length() >= 2 && (p[1] == PC_(':'))) - { - if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2)); - p = p.substr(2); - } else - { - if(drive) *drive = mpt::PathString(); - } - } - mpt::RawPathString::size_type last_slash = p.find_last_of(PL_("\\/")); - if(last_slash != mpt::RawPathString::npos) - { - if(dir) *dir = mpt::PathString::FromNative(p.substr(0, last_slash + 1)); - p = p.substr(last_slash + 1); - } else - { - if(dir) *dir = mpt::PathString(); - } - mpt::RawPathString::size_type last_dot = p.find_last_of(PL_(".")); - if(last_dot == mpt::RawPathString::npos) - { - if(fname) *fname = mpt::PathString::FromNative(p); - if(ext) *ext = mpt::PathString(); - } else if(last_dot == 0) - { - if(fname) *fname = mpt::PathString::FromNative(p); - if(ext) *ext = mpt::PathString(); - } else if(p == PL_(".") || p == PL_("..")) - { - if(fname) *fname = mpt::PathString::FromNative(p); - if(ext) *ext = mpt::PathString(); - } else - { - if(fname) *fname = mpt::PathString::FromNative(p.substr(0, last_dot)); - if(ext) *ext = mpt::PathString::FromNative(p.substr(last_dot)); - } - -} - -PathString PathString::GetDrive() const -{ - PathString drive; - SplitPath(&drive, nullptr, nullptr, nullptr); - return drive; -} -PathString PathString::GetDir() const -{ - PathString dir; - SplitPath(nullptr, &dir, nullptr, nullptr); - return dir; -} -PathString PathString::GetPath() const -{ - PathString drive, dir; - SplitPath(&drive, &dir, nullptr, nullptr); - return drive + dir; -} -PathString PathString::GetFileName() const -{ - PathString fname; - SplitPath(nullptr, nullptr, &fname, nullptr); - return fname; -} -PathString PathString::GetFileExt() const -{ - PathString ext; - SplitPath(nullptr, nullptr, nullptr, &ext); - return ext; -} -PathString PathString::GetFullFileName() const -{ - PathString name, ext; - SplitPath(nullptr, nullptr, &name, &ext); - return name + ext; -} - - -bool PathString::IsDirectory() const -{ - // Using PathIsDirectoryW here instead would increase libopenmpt dependencies by shlwapi.dll. - // GetFileAttributesW also does the job just fine. - #if MPT_OS_WINDOWS_WINRT - WIN32_FILE_ATTRIBUTE_DATA data = {}; - if(::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0) - { - return false; - } - DWORD dwAttrib = data.dwFileAttributes; - #else // !MPT_OS_WINDOWS_WINRT - DWORD dwAttrib = ::GetFileAttributes(path.c_str()); - #endif // MPT_OS_WINDOWS_WINRT - return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); -} - -bool PathString::IsFile() const -{ - #if MPT_OS_WINDOWS_WINRT - WIN32_FILE_ATTRIBUTE_DATA data = {}; - if (::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0) - { - return false; - } - DWORD dwAttrib = data.dwFileAttributes; - #else // !MPT_OS_WINDOWS_WINRT - DWORD dwAttrib = ::GetFileAttributes(path.c_str()); - #endif // MPT_OS_WINDOWS_WINRT - return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); -} - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -bool PathString::FileOrDirectoryExists() const -{ - return ::PathFileExists(path.c_str()) != FALSE; -} - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -PathString PathString::ReplaceExt(const mpt::PathString &newExt) const -{ - return GetDrive() + GetDir() + GetFileName() + newExt; -} - - -PathString PathString::SanitizeComponent() const -{ - PathString result = *this; - SanitizeFilename(result); - return result; -} - // Convert an absolute path to a path that's relative to "&relativeTo". -PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) const +mpt::PathString AbsolutePathToRelative(const mpt::PathString &path, const mpt::PathString &relativeTo) { - mpt::PathString result = *this; + using namespace path_literals; + using char_type = RawPathString::value_type; + mpt::PathString result = path; if(path.empty()) { return result; } - if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), relativeTo.AsNative().length())) + if(!_tcsncicmp(relativeTo.AsNative().c_str(), path.AsNative().c_str(), relativeTo.AsNative().length())) { // Path is OpenMPT's directory or a sub directory ("C:\OpenMPT\Somepath" => ".\Somepath") - result = P_(".\\"); // ".\" - result += mpt::PathString::FromNative(AsNative().substr(relativeTo.AsNative().length())); - } else if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), 2)) + result = mpt::PathString::FromNative(L(".\\")); // ".\" + result += mpt::PathString::FromNative(path.AsNative().substr(relativeTo.AsNative().length())); + } else if(!_tcsncicmp(relativeTo.AsNative().c_str(), path.AsNative().c_str(), 2)) { // Path is on the same drive as OpenMPT ("C:\Somepath" => "\Somepath") - result = mpt::PathString::FromNative(AsNative().substr(2)); + result = mpt::PathString::FromNative(path.AsNative().substr(2)); } return result; } // Convert a path that is relative to "&relativeTo" to an absolute path. -PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) const +mpt::PathString RelativePathToAbsolute(const mpt::PathString &path, const mpt::PathString &relativeTo) { - mpt::PathString result = *this; + using namespace path_literals; + using char_type = RawPathString::value_type; + mpt::PathString result = path; if(path.empty()) { return result; } - if(path.length() >= 2 && path[0] == PC_('\\') && path[1] != PC_('\\')) + if(path.length() >= 2 && path.AsNative()[0] == L('\\') && path.AsNative()[1] == L('\\')) { - // Path is on the same drive as OpenMPT ("\Somepath\" => "C:\Somepath\"), but ignore network paths starting with "\\" + // Network / UNC paths + return result; + } if(path.length() >= 1 && path.AsNative()[0] == L('\\')) + { + // Path is on the same drive as relativeTo ("\Somepath\" => "C:\Somepath\") result = mpt::PathString::FromNative(relativeTo.AsNative().substr(0, 2)); result += mpt::PathString(path); - } else if(path.length() >= 2 && path.substr(0, 2) == PL_(".\\")) + } else if(path.length() >= 2 && path.AsNative().substr(0, 2) == L(".\\")) { - // Path is OpenMPT's directory or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\") + // Path is in relativeTo or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\") result = relativeTo; // "C:\OpenMPT\" - result += mpt::PathString::FromNative(AsNative().substr(2)); + result += mpt::PathString::FromNative(path.AsNative().substr(2)); + } else if(path.length() < 3 || path.AsNative()[1] != L(':') || path.AsNative()[2] != L('\\')) + { + // Any other path not starting with drive letter + result = relativeTo; // "C:\OpenMPT\" + result += mpt::PathString(path); } return result; } @@ -382,60 +110,10 @@ PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) cons #endif // MODPLUG_TRACKER && MPT_OS_WINDOWS -bool PathString::IsPathSeparator(RawPathString::value_type c) -{ -#if MPT_OS_WINDOWS - return (c == PC_('\\')) || (c == PC_('/')); -#else - return c == PC_('/'); -#endif -} - -RawPathString::value_type PathString::GetDefaultPathSeparator() -{ -#if MPT_OS_WINDOWS - return PC_('\\'); -#else - return PC_('/'); -#endif -} - - -} // namespace mpt - - -namespace mpt -{ - -bool PathIsAbsolute(const mpt::PathString &path) { - mpt::RawPathString rawpath = path.AsNative(); -#if MPT_OS_WINDOWS - if(rawpath.substr(0, 8) == PL_("\\\\?\\UNC\\")) - { - return true; - } - if(rawpath.substr(0, 4) == PL_("\\\\?\\")) - { - return true; - } - if(rawpath.substr(0, 2) == PL_("\\\\")) - { - return true; // UNC - } - if(rawpath.substr(0, 2) == PL_("//")) - { - return true; // UNC - } - return (rawpath.length()) >= 3 && (rawpath[1] == ':') && mpt::PathString::IsPathSeparator(rawpath[2]); -#else - return (rawpath.length() >= 1) && mpt::PathString::IsPathSeparator(rawpath[0]); -#endif -} - #if MPT_OS_WINDOWS -#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)) +#if !(MPT_WINRT_BEFORE(MPT_WIN_10)) mpt::PathString GetAbsolutePath(const mpt::PathString &path) { @@ -454,415 +132,30 @@ mpt::PathString GetAbsolutePath(const mpt::PathString &path) #endif -#ifdef MODPLUG_TRACKER - -bool DeleteWholeDirectoryTree(mpt::PathString path) -{ - if(path.AsNative().empty()) - { - return false; - } - if(PathIsRelative(path.AsNative().c_str()) == TRUE) - { - return false; - } - if(!path.FileOrDirectoryExists()) - { - return true; - } - if(!path.IsDirectory()) - { - return false; - } - path.EnsureTrailingSlash(); - HANDLE hFind = NULL; - WIN32_FIND_DATA wfd = {}; - hFind = FindFirstFile((path + P_("*.*")).AsNative().c_str(), &wfd); - if(hFind != NULL && hFind != INVALID_HANDLE_VALUE) - { - do - { - mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName); - if(filename != P_(".") && filename != P_("..")) - { - filename = path + filename; - if(filename.IsDirectory()) - { - if(!DeleteWholeDirectoryTree(filename)) - { - return false; - } - } else if(filename.IsFile()) - { - if(DeleteFile(filename.AsNative().c_str()) == 0) - { - return false; - } - } - } - } while(FindNextFile(hFind, &wfd)); - FindClose(hFind); - } - if(RemoveDirectory(path.AsNative().c_str()) == 0) - { - return false; - } - return true; -} - -#endif // MODPLUG_TRACKER - #endif // MPT_OS_WINDOWS -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -mpt::PathString GetExecutablePath() -{ - std::vector exeFileName(MAX_PATH); - while(GetModuleFileName(0, exeFileName.data(), mpt::saturate_cast(exeFileName.size())) >= exeFileName.size()) - { - if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) - { - return mpt::PathString(); - } - exeFileName.resize(exeFileName.size() * 2); - } - return mpt::GetAbsolutePath(mpt::PathString::FromNative(exeFileName.data()).GetPath()); -} - - -#if !MPT_OS_WINDOWS_WINRT - -mpt::PathString GetSystemPath() -{ - DWORD size = GetSystemDirectory(nullptr, 0); - std::vector path(size + 1); - if(!GetSystemDirectory(path.data(), size + 1)) - { - return mpt::PathString(); - } - return mpt::PathString::FromNative(path.data()) + P_("\\"); -} - -#endif // !MPT_OS_WINDOWS_WINRT - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -mpt::PathString GetTempDirectory() -{ - DWORD size = GetTempPath(0, nullptr); - if(size) - { - std::vector tempPath(size + 1); - if(GetTempPath(size + 1, tempPath.data())) - { - return mpt::PathString::FromNative(tempPath.data()); - } - } - // use exe directory as fallback - return mpt::GetExecutablePath(); -} - -mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix, const mpt::PathString &fileNameExtension) -{ - mpt::PathString filename = mpt::GetTempDirectory(); - filename += (!fileNamePrefix.empty() ? fileNamePrefix + P_("_") : mpt::PathString()); - filename += mpt::PathString::FromUnicode(mpt::UUID::GenerateLocalUseOnly(mpt::global_prng()).ToUString()); - filename += (!fileNameExtension.empty() ? P_(".") + fileNameExtension : mpt::PathString()); - return filename; -} - -TempFileGuard::TempFileGuard(const mpt::PathString &filename) - : filename(filename) -{ - return; -} - -mpt::PathString TempFileGuard::GetFilename() const -{ - return filename; -} - -TempFileGuard::~TempFileGuard() -{ - if(!filename.empty()) - { - DeleteFile(filename.AsNative().c_str()); - } -} - - -TempDirGuard::TempDirGuard(const mpt::PathString &dirname_) - : dirname(dirname_.WithTrailingSlash()) -{ - if(dirname.empty()) - { - return; - } - if(::CreateDirectory(dirname.AsNative().c_str(), NULL) == 0) - { // fail - dirname = mpt::PathString(); - } -} - -mpt::PathString TempDirGuard::GetDirname() const -{ - return dirname; -} - -TempDirGuard::~TempDirGuard() -{ - if(!dirname.empty()) - { - DeleteWholeDirectoryTree(dirname); - } -} - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - } // namespace mpt #if defined(MODPLUG_TRACKER) -static inline char SanitizeFilenameChar(char c) -{ - if( c == '\\' || - c == '\"' || - c == '/' || - c == ':' || - c == '?' || - c == '<' || - c == '>' || - c == '|' || - c == '*') - { - c = '_'; - } - return c; -} -static inline wchar_t SanitizeFilenameChar(wchar_t c) -{ - if( c == L'\\' || - c == L'\"' || - c == L'/' || - c == L':' || - c == L'?' || - c == L'<' || - c == L'>' || - c == L'|' || - c == L'*') - { - c = L'_'; - } - return c; -} -#if MPT_CXX_AT_LEAST(20) -static inline char8_t SanitizeFilenameChar(char8_t c) +mpt::ustring SanitizePathComponent(mpt::ustring str) { - if( c == u8'\\' || - c == u8'\"' || - c == u8'/' || - c == u8':' || - c == u8'?' || - c == u8'<' || - c == u8'>' || - c == u8'|' || - c == u8'*') - { - c = u8'_'; - } - return c; + return mpt::PathString::FromUnicode(str).AsSanitizedComponent().ToUnicode(); } -#endif - -void SanitizeFilename(mpt::PathString &filename) -{ - mpt::RawPathString tmp = filename.AsNative(); - for(auto &c : tmp) - { - c = SanitizeFilenameChar(c); - } - filename = mpt::PathString::FromNative(tmp); -} - -void SanitizeFilename(char *beg, char *end) -{ - for(char *it = beg; it != end; ++it) - { - *it = SanitizeFilenameChar(*it); - } -} - -void SanitizeFilename(wchar_t *beg, wchar_t *end) -{ - for(wchar_t *it = beg; it != end; ++it) - { - *it = SanitizeFilenameChar(*it); - } -} - -void SanitizeFilename(std::string &str) -{ - for(size_t i = 0; i < str.length(); i++) - { - str[i] = SanitizeFilenameChar(str[i]); - } -} - -void SanitizeFilename(std::wstring &str) -{ - for(size_t i = 0; i < str.length(); i++) - { - str[i] = SanitizeFilenameChar(str[i]); - } -} - -#if MPT_USTRING_MODE_UTF8 -void SanitizeFilename(mpt::u8string &str) -{ - for(size_t i = 0; i < str.length(); i++) - { - str[i] = SanitizeFilenameChar(str[i]); - } -} -#endif // MPT_USTRING_MODE_UTF8 #if defined(MPT_WITH_MFC) -void SanitizeFilename(CString &str) +CString SanitizePathComponent(CString str) { - for(int i = 0; i < str.GetLength(); i++) - { - str.SetAt(i, SanitizeFilenameChar(str.GetAt(i))); - } + return mpt::PathString::FromCString(str).AsSanitizedComponent().ToCString(); } #endif // MPT_WITH_MFC -#endif // MODPLUG_TRACKER - - -#if defined(MODPLUG_TRACKER) - - -mpt::PathString FileType::AsFilterString(FlagSet format) const -{ - mpt::PathString filter; - if(GetShortName().empty() || GetExtensions().empty()) - { - return filter; - } - if(!GetDescription().empty()) - { - filter += mpt::PathString::FromUnicode(GetDescription()); - } else - { - filter += mpt::PathString::FromUnicode(GetShortName()); - } - const auto extensions = GetExtensions(); - if(format[FileTypeFormatShowExtensions]) - { - filter += P_(" ("); - bool first = true; - for(const auto &ext : extensions) - { - if(first) - { - first = false; - } else - { - filter += P_(","); - } - filter += P_("*."); - filter += ext; - } - filter += P_(")"); - } - filter += P_("|"); - { - bool first = true; - for(const auto &ext : extensions) - { - if(first) - { - first = false; - } else - { - filter += P_(";"); - } - filter += P_("*."); - filter += ext; - } - } - filter += P_("|"); - return filter; -} - - -mpt::PathString FileType::AsFilterOnlyString() const -{ - mpt::PathString filter; - const auto extensions = GetExtensions(); - { - bool first = true; - for(const auto &ext : extensions) - { - if(first) - { - first = false; - } else - { - filter += P_(";"); - } - filter += P_("*."); - filter += ext; - } - } - return filter; -} - - -mpt::PathString ToFilterString(const FileType &fileType, FlagSet format) -{ - return fileType.AsFilterString(format); -} - - -mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format) -{ - mpt::PathString filter; - for(const auto &type : fileTypes) - { - filter += type.AsFilterString(format); - } - return filter; -} - - -mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty) -{ - mpt::PathString filter = fileType.AsFilterOnlyString(); - return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; -} - - -mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty) -{ - mpt::PathString filter; - for(const auto &type : fileTypes) - { - filter += type.AsFilterOnlyString(); - } - return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter; -} #endif // MODPLUG_TRACKER diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h index 95224c5b5..f41175a9d 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptPathString.h @@ -12,392 +12,85 @@ #include "openmpt/all/BuildSettings.hpp" +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/path/basic_path.hpp" +#include "mpt/path/native_path.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/string/types.hpp" + #include "mptString.h" -#include "mpt/base/namespace.hpp" -#include - -#include "openmpt/base/FlagSet.hpp" - -#define MPT_DEPRECATED_PATH -//#define MPT_DEPRECATED_PATH [[deprecated]] OPENMPT_NAMESPACE_BEGIN + + namespace mpt { -#if MPT_OS_WINDOWS -typedef mpt::winstring RawPathString; -#else // !MPT_OS_WINDOWS -typedef std::string RawPathString; -#endif // if MPT_OS_WINDOWS - -class PathString -{ - -private: - - RawPathString path; - -private: - - explicit PathString(const RawPathString & path_) - : path(path_) - { - return; - } - -public: - - PathString() - { - return; - } - PathString(const PathString & other) - : path(other.path) - { - return; - } - PathString(PathString && other) noexcept - : path(std::move(other.path)) - { - return; - } - PathString & assign(const PathString & other) - { - path = other.path; - return *this; - } - PathString & assign(PathString && other) noexcept - { - path = std::move(other.path); - return *this; - } - PathString & operator = (const PathString & other) - { - return assign(other); - } - PathString &operator = (PathString && other) noexcept - { - return assign(std::move(other)); - } - PathString & append(const PathString & other) - { - path.append(other.path); - return *this; - } - PathString & operator += (const PathString & other) - { - return append(other); - } - - friend PathString operator + (const PathString & a, const PathString & b) - { - return PathString(a).append(b); - } - - friend bool operator < (const PathString & a, const PathString & b) - { - return a.AsNative() < b.AsNative(); - } - friend bool operator == (const PathString & a, const PathString & b) - { - return a.AsNative() == b.AsNative(); - } - friend bool operator != (const PathString & a, const PathString & b) - { - return a.AsNative() != b.AsNative(); - } - - bool empty() const { return path.empty(); } - - std::size_t Length() const { return path.size(); } - - - -public: - -#if MPT_OS_WINDOWS -#if !MPT_OS_WINDOWS_WINRT - static int CompareNoCase(const PathString & a, const PathString & b); -#endif // !MPT_OS_WINDOWS_WINRT -#endif - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - - void SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const; - // \\?\ prefixes will be removed and \\?\\UNC prefixes converted to canonical \\ form. - PathString GetDrive() const; // Drive letter + colon, e.g. "C:" or \\server\\share - PathString GetDir() const; // Directory, e.g. "\OpenMPT\" - PathString GetPath() const; // Drive + Dir, e.g. "C:\OpenMPT\" - PathString GetFileName() const; // File name without extension, e.g. "OpenMPT" - PathString GetFileExt() const; // Extension including dot, e.g. ".exe" - PathString GetFullFileName() const; // File name + extension, e.g. "OpenMPT.exe" - - // Verify if this path represents a valid directory on the file system. - bool IsDirectory() const; - // Verify if this path exists and is a file on the file system. - bool IsFile() const; - - bool FileOrDirectoryExists() const; - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - - static bool IsPathSeparator(RawPathString::value_type c); - static RawPathString::value_type GetDefaultPathSeparator(); - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - - // Return the same path string with a different (or appended) extension (including "."), e.g. "foo.bar",".txt" -> "foo.txt" or "C:\OpenMPT\foo",".txt" -> "C:\OpenMPT\foo.txt" - PathString ReplaceExt(const mpt::PathString &newExt) const; - - // Removes special characters from a filename component and replaces them with a safe replacement character ("_" on windows). - // Returns the result. - // Note that this also removes path component separators, so this should only be used on single-component PathString objects. - PathString SanitizeComponent() const; - - bool HasTrailingSlash() const - { - if(path.empty()) - { - return false; - } - RawPathString::value_type c = path[path.length() - 1]; - return IsPathSeparator(c); - } - mpt::PathString &EnsureTrailingSlash() - { - if(!path.empty() && !HasTrailingSlash()) - { - path += GetDefaultPathSeparator(); - } - return *this; - } - - mpt::PathString WithoutTrailingSlash() const - { - mpt::PathString result = *this; - while(result.HasTrailingSlash()) - { - if(result.Length() == 1) - { - return result; - } - result = mpt::PathString(result.AsNative().substr(0, result.AsNative().length() - 1)); - } - return result; - } - - mpt::PathString WithTrailingSlash() const - { - mpt::PathString result = *this; - result.EnsureTrailingSlash(); - return result; - } - - // Relative / absolute paths conversion - mpt::PathString AbsolutePathToRelative(const mpt::PathString &relativeTo) const; - mpt::PathString RelativePathToAbsolute(const mpt::PathString &relativeTo) const; - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - -public: - -#if MPT_OS_WINDOWS - -#if !(MPT_WSTRING_CONVERT) -#error "mpt::PathString on Windows depends on MPT_WSTRING_CONVERT)" -#endif - // conversions #if defined(MPT_ENABLE_CHARSET_LOCALE) - MPT_DEPRECATED_PATH std::string ToLocale() const { return mpt::ToCharset(mpt::Charset::Locale, path); } -#endif - std::string ToUTF8() const { return mpt::ToCharset(mpt::Charset::UTF8, path); } - std::wstring ToWide() const { return mpt::ToWide(path); } - mpt::ustring ToUnicode() const { return mpt::ToUnicode(path); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) - MPT_DEPRECATED_PATH static PathString FromLocale(const std::string &path) { return PathString(mpt::ToWin(mpt::Charset::Locale, path)); } - static PathString FromLocaleSilent(const std::string &path) { return PathString(mpt::ToWin(mpt::Charset::Locale, path)); } -#endif - static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToWin(mpt::Charset::UTF8, path)); } - static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToWin(path)); } - static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToWin(path)); } - RawPathString AsNative() const { return path; } - // Return native string, with possible \\?\ prefix if it exceeds MAX_PATH characters. - RawPathString AsNativePrefixed() const; - static PathString FromNative(const RawPathString &path) { return PathString(path); } -#if defined(MPT_WITH_MFC) - // CString TCHAR, so this is CHAR or WCHAR, depending on UNICODE - CString ToCString() const { return mpt::ToCString(path); } - static PathString FromCString(const CString &path) { return PathString(mpt::ToWin(path)); } -#endif // MPT_WITH_MFC - // Convert a path to its simplified form, i.e. remove ".\" and "..\" entries - mpt::PathString Simplify() const; +using PathString = mpt::native_path; -#else // !MPT_OS_WINDOWS +#define MPT_PATHSTRING_LITERAL(x) MPT_OS_PATH_LITERAL( x ) +#define MPT_PATHSTRING(x) mpt::PathString::FromNative(MPT_OS_PATH_LITERAL( x )) - // conversions -#if defined(MPT_ENABLE_CHARSET_LOCALE) - std::string ToLocale() const { return path; } - std::string ToUTF8() const { return mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Locale, path); } -#if MPT_WSTRING_CONVERT - std::wstring ToWide() const { return mpt::ToWide(mpt::Charset::Locale, path); } -#endif - mpt::ustring ToUnicode() const { return mpt::ToUnicode(mpt::Charset::Locale, path); } - static PathString FromLocale(const std::string &path) { return PathString(path); } - static PathString FromLocaleSilent(const std::string &path) { return PathString(path); } - static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, mpt::Charset::UTF8, path)); } -#if MPT_WSTRING_CONVERT - static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, path)); } -#endif - static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, path)); } - RawPathString AsNative() const { return path; } - RawPathString AsNativePrefixed() const { return path; } - static PathString FromNative(const RawPathString &path) { return PathString(path); } #else // !MPT_ENABLE_CHARSET_LOCALE - std::string ToUTF8() const { return path; } -#if MPT_WSTRING_CONVERT - std::wstring ToWide() const { return mpt::ToWide(mpt::Charset::UTF8, path); } -#endif - mpt::ustring ToUnicode() const { return mpt::ToUnicode(mpt::Charset::UTF8, path); } - static PathString FromUTF8(const std::string &path) { return PathString(path); } -#if MPT_WSTRING_CONVERT - static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToCharset(mpt::Charset::UTF8, path)); } -#endif - static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToCharset(mpt::Charset::UTF8, path)); } - RawPathString AsNative() const { return path; } - RawPathString AsNativePrefixed() const { return path; } - static PathString FromNative(const RawPathString &path) { return PathString(path); } + +using PathString = mpt::BasicPathString; + +#define MPT_PATHSTRING_LITERAL(x) ( x ) +#define MPT_PATHSTRING(x) mpt::PathString::FromNative( x ) + #endif // MPT_ENABLE_CHARSET_LOCALE - // Convert a path to its simplified form (currently only implemented on Windows) - [[deprecated]] mpt::PathString Simplify() const { return PathString(path); } - -#endif // MPT_OS_WINDOWS - -}; - - - -#if defined(MPT_ENABLE_CHARSET_LOCALE) -#if MPT_OS_WINDOWS -#ifdef UNICODE -[[deprecated]] inline std::string ToAString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUnicode()); } -#else -MPT_DEPRECATED_PATH inline std::string ToAString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.AsNative()); } -#endif -#else -MPT_DEPRECATED_PATH inline std::string ToAString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUnicode()); } -#endif -#endif -inline mpt::ustring ToUString(const mpt::PathString & x) { return x.ToUnicode(); } -#if MPT_WSTRING_FORMAT -inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWide(); } -#endif - -} // namespace mpt - -#if MPT_OS_WINDOWS - -#ifdef UNICODE -#define MPT_PATHSTRING_LITERAL(x) ( L ## x ) -#define MPT_PATHSTRING(x) mpt::PathString::FromNative( L ## x ) -#else -#define MPT_PATHSTRING_LITERAL(x) ( x ) -#define MPT_PATHSTRING(x) mpt::PathString::FromNative( x ) -#endif - -#else // !MPT_OS_WINDOWS - -#define MPT_PATHSTRING_LITERAL(x) ( x ) -#define MPT_PATHSTRING(x) mpt::PathString::FromNative( x ) - -#endif // MPT_OS_WINDOWS +using RawPathString = PathString::raw_path_type; #define PC_(x) MPT_PATHSTRING_LITERAL(x) #define PL_(x) MPT_PATHSTRING_LITERAL(x) #define P_(x) MPT_PATHSTRING(x) -namespace mpt + + +template ::value, bool>::type = true> +inline mpt::ustring ToUString(const T &x) { + return x.ToUnicode(); +} -bool PathIsAbsolute(const mpt::PathString &path); #if MPT_OS_WINDOWS - -#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)) - +#if !(MPT_WINRT_BEFORE(MPT_WIN_10)) // Returns the absolute path for a potentially relative path and removes ".." or "." components. (same as GetFullPathNameW) mpt::PathString GetAbsolutePath(const mpt::PathString &path); - #endif - -#ifdef MODPLUG_TRACKER - -// Deletes a complete directory tree. Handle with EXTREME care. -// Returns false if any file could not be removed and aborts as soon as it -// encounters any error. path must be absolute. -bool DeleteWholeDirectoryTree(mpt::PathString path); - -#endif // MODPLUG_TRACKER - #endif // MPT_OS_WINDOWS #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS -// Returns the application executable path or an empty string (if unknown), e.g. "C:\mptrack\" -mpt::PathString GetExecutablePath(); +// Relative / absolute paths conversion +mpt::PathString AbsolutePathToRelative(const mpt::PathString &p, const mpt::PathString &relativeTo); // similar to std::fs::path::lexically_approximate + +mpt::PathString RelativePathToAbsolute(const mpt::PathString &p, const mpt::PathString &relativeTo); + +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS + + + +#if MPT_OS_WINDOWS #if !MPT_OS_WINDOWS_WINRT -// Returns the system directory path, e.g. "C:\Windows\System32\" -mpt::PathString GetSystemPath(); +int PathCompareNoCase(const PathString &a, const PathString &b); #endif // !MPT_OS_WINDOWS_WINRT - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS - -// Returns temporary directory (with trailing backslash added) (e.g. "C:\TEMP\") -mpt::PathString GetTempDirectory(); - -// Returns a new unique absolute path. -mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix = mpt::PathString(), const mpt::PathString &fileNameExtension = P_("tmp")); +#endif -// Scoped temporary file guard. Deletes the file when going out of scope. -// The file itself is not created automatically. -class TempFileGuard -{ -private: - const mpt::PathString filename; -public: - TempFileGuard(const mpt::PathString &filename = CreateTempFileName()); - mpt::PathString GetFilename() const; - ~TempFileGuard(); -}; - - -// Scoped temporary directory guard. Deletes the directory when going out of scope. -// The directory itself is created automatically. -class TempDirGuard -{ -private: - mpt::PathString dirname; -public: - TempDirGuard(const mpt::PathString &dirname_ = CreateTempFileName()); - mpt::PathString GetDirname() const; - ~TempDirGuard(); -}; - -#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS - } // namespace mpt @@ -405,101 +98,15 @@ public: #if defined(MODPLUG_TRACKER) // Sanitize a filename (remove special chars) -void SanitizeFilename(mpt::PathString &filename); -void SanitizeFilename(char *beg, char *end); -void SanitizeFilename(wchar_t *beg, wchar_t *end); - -void SanitizeFilename(std::string &str); -void SanitizeFilename(std::wstring &str); -#if MPT_USTRING_MODE_UTF8 -void SanitizeFilename(mpt::u8string &str); -#endif // MPT_USTRING_MODE_UTF8 - -template -void SanitizeFilename(char (&buffer)[size]) -{ - static_assert(size > 0); - SanitizeFilename(buffer, buffer + size); -} - -template -void SanitizeFilename(wchar_t (&buffer)[size]) -{ - static_assert(size > 0); - SanitizeFilename(buffer, buffer + size); -} +mpt::ustring SanitizePathComponent(mpt::ustring str); #if defined(MPT_WITH_MFC) -void SanitizeFilename(CString &str); +CString SanitizePathComponent(CString str); #endif // MPT_WITH_MFC #endif // MODPLUG_TRACKER -#if defined(MODPLUG_TRACKER) - -enum FileTypeFormat -{ - FileTypeFormatNone = 0 , // do not show extensions after description, i.e. "Foo Files" - FileTypeFormatShowExtensions = 1<<0, // show extensions after descripten, i.e. "Foo Files (*.foo,*.bar)" -}; -MPT_DECLARE_ENUM(FileTypeFormat) - -class FileType -{ -private: - mpt::ustring m_ShortName; // "flac", "mod" (lowercase) - mpt::ustring m_Description; // "FastTracker 2 Module" - std::vector m_MimeTypes; // "audio/ogg" (in ASCII) - std::vector m_Extensions; // "mod", "xm" (lowercase) - std::vector m_Prefixes; // "mod" for "mod.*" -public: - FileType() { } - FileType(const std::vector &group) - { - for(const auto &type : group) - { - mpt::append(m_MimeTypes, type.m_MimeTypes); - mpt::append(m_Extensions, type.m_Extensions); - mpt::append(m_Prefixes, type.m_Prefixes); - } - } - static FileType Any() - { - return FileType().ShortName(U_("*")).Description(U_("All Files")).AddExtension(P_("*")); - } -public: - FileType& ShortName(const mpt::ustring &shortName) { m_ShortName = shortName; return *this; } - FileType& Description(const mpt::ustring &description) { m_Description = description; return *this; } - FileType& MimeTypes(const std::vector &mimeTypes) { m_MimeTypes = mimeTypes; return *this; } - FileType& Extensions(const std::vector &extensions) { m_Extensions = extensions; return *this; } - FileType& Prefixes(const std::vector &prefixes) { m_Prefixes = prefixes; return *this; } - FileType& AddMimeType(const std::string &mimeType) { m_MimeTypes.push_back(mimeType); return *this; } - FileType& AddExtension(const mpt::PathString &extension) { m_Extensions.push_back(extension); return *this; } - FileType& AddPrefix(const mpt::PathString &prefix) { m_Prefixes.push_back(prefix); return *this; } -public: - mpt::ustring GetShortName() const { return m_ShortName; } - mpt::ustring GetDescription() const { return m_Description; } - std::vector GetMimeTypes() const { return m_MimeTypes; } - std::vector GetExtensions() const { return m_Extensions; } - std::vector GetPrefixes() const { return m_Prefixes; } -public: - mpt::PathString AsFilterString(FlagSet format = FileTypeFormatNone) const; - mpt::PathString AsFilterOnlyString() const; -}; // class FileType - - -// "Ogg Vorbis|*.ogg;*.oga|" // FileTypeFormatNone -// "Ogg Vorbis (*.ogg,*.oga)|*.ogg;*.oga|" // FileTypeFormatShowExtensions -mpt::PathString ToFilterString(const FileType &fileType, FlagSet format = FileTypeFormatNone); -mpt::PathString ToFilterString(const std::vector &fileTypes, FlagSet format = FileTypeFormatNone); - -// "*.ogg;*.oga" / ";*.ogg;*.oga" -mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty = false); -mpt::PathString ToFilterOnlyString(const std::vector &fileTypes, bool prependSemicolonWhenNotEmpty = false); - -#endif // MODPLUG_TRACKER - OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h index 905d18391..8d68cd682 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptRandom.h @@ -57,7 +57,7 @@ class thread_safe_prng private: mpt::mutex m; public: - typedef typename Trng::result_type result_type; + using result_type = typename Trng::result_type; public: template explicit thread_safe_prng(Trd & rd) diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptString.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptString.cpp index c64beef53..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptString.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptString.cpp @@ -1,838 +0,0 @@ -/* - * mptString.cpp - * ------------- - * Purpose: Small string-related utilities, number and message formatting. - * Notes : Currently none. - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#include "stdafx.h" -#include "mptString.h" - -#include "mpt/string/types.hpp" -#include "mpt/string/utility.hpp" -#include "mpt/string_transcode/transcode.hpp" - -#include -#include -#include - -#include - -#if defined(MODPLUG_TRACKER) -#include -#endif // MODPLUG_TRACKER - -#if defined(MODPLUG_TRACKER) -#include -#endif // MODPLUG_TRACKER - -#if MPT_OS_WINDOWS -#include -#endif // MPT_OS_WINDOWS - - -OPENMPT_NAMESPACE_BEGIN - - - -/* - - - -Quick guide to the OpenMPT string type jungle -============================================= - - - -This quick guide is only meant as a hint. There may be valid reasons to not -honor the recommendations found here. Staying consistent with surrounding and/or -related code sections may also be important. - - - -List of string types --------------------- - - * std::string (OpenMPT, libopenmpt) - C++ string of unspecifed 8bit encoding. Try to always document the - encoding if not clear from context. Do not use unless there is an obvious - reason to do so. - - * std::wstring (OpenMPT) - UTF16 (on windows) or UTF32 (otherwise). Do not use unless there is an - obvious reason to do so. - - * mpt::lstring (OpenMPT) - OpenMPT locale string type. The encoding is always CP_ACP. Do not use unless - there is an obvious reason to do so. - - * char* (OpenMPT, libopenmpt) - C string of unspecified encoding. Use only for static literals or in - performance critical inner loops where full control and avoidance of memory - allocations is required. - - * wchar_t* (OpenMPT) - C wide string. Use only if Unicode is required for static literals or in - performance critical inner loops where full control and avoidance of memory - allocation is required. - - * mpt::winstring (OpenMPT) - OpenMPT type-safe string to interface with native WinAPI, either encoded in - locale/CP_ACP (if !UNICODE) or UTF16 (if UNICODE). - - * CString (OpenMPT) - MFC string type, either encoded in locale/CP_ACP (if !UNICODE) or UTF16 (if - UNICODE). Specify literals with _T(""). Use in MFC GUI code. - - * CStringA (OpenMPT) - MFC ANSI string type. The encoding is always CP_ACP. Do not use. - - * CStringW (OpenMPT) - MFC Unicode string type. Do not use. - - * mpt::PathString (OpenMPT, libopenmpt) - String type representing paths and filenames. Always use for these in order - to avoid potentially lossy conversions. Use P_("") macro for - literals. - - * mpt::ustring (OpenMPT, libopenmpt) - The default unicode string type. Can be encoded in UTF8 or UTF16 or UTF32, - depending on MPT_USTRING_MODE_* and sizeof(wchar_t). Literals can written as - U_(""). Use as your default string type if no other string type is - a measurably better fit. - - * MPT_UTF8 (OpenMPT, libopenmpt) - Macro that generates a mpt::ustring from string literals containing - non-ascii characters. In order to keep the source code in ascii encoding, - always express non-ascii characters using explicit \x23 escaping. Note that - depending on the underlying type of mpt::ustring, MPT_UTF8 *requires* a - runtime conversion. Only use for string literals containing non-ascii - characters (use MPT_USTRING otherwise). - - * MPT_ULITERAL / MPT_UCHAR / mpt::uchar (OpenMPT, libopenmpt) - Macros which generate string literals, char literals and the char literal - type respectively. These are especially useful in constexpr contexts or - global data where MPT_USTRING is either unusable or requires a global - contructor to run. Do NOT use as a performance optimization in place of - MPT_USTRING however, because MPT_USTRING can be converted to C++11/14 user - defined literals eventually, while MPT_ULITERAL cannot because of constexpr - requirements. - - * mpt::RawPathString (OpenMPT, libopenmpt) - Internal representation of mpt::PathString. Only use for parsing path - fragments. - - * mpt::u8string (OpenMPT, libopenmpt) - Internal representation of mpt::ustring. Do not use directly. Ever. - - * std::basic_string (OpenMPT) - Same as std::string. Do not use std::basic_string in the templated form. - - * std::basic_string (OpenMPT) - Same as std::wstring. Do not use std::basic_string in the templated form. - -The following string types are available in order to avoid the need to overload -functions on a huge variety of string types. Use only ever as function argument -types. -Note that the locale charset is not available on all libopenmpt builds (in which -case the option is ignored or a sensible fallback is used; these types are -always available). -All these types publicly inherit from mpt::ustring and do not contain any -additional state. This means that they work the same way as mpt::ustring does -and do support type-slicing for both, read and write accesses. -These types only add conversion constructors for all string types that have a -defined encoding and for all 8bit string types using the specified encoding -heuristic. - - * AnyUnicodeString (OpenMPT, libopenmpt) - Is constructible from any Unicode string. - - * AnyString (OpenMPT, libopenmpt) - Tries to do the smartest auto-magic we can do. - - * AnyStringLocale (OpenMPT, libopenmpt) - char-based strings are assumed to be in locale encoding. - - * AnyStringUTF8orLocale (OpenMPT, libopenmpt) - char-based strings are tried in UTF8 first, if this fails, locale is used. - - * AnyStringUTF8 (OpenMPT, libopenmpt) - char-based strings are assumed to be in UTF8. - - - -Encoding of 8bit strings ------------------------- - -8bit strings have an unspecified encoding. When the string is contained within a -CSoundFile object, the encoding is most likely CSoundFile::GetCharsetInternal(), -otherwise, try to gather the most probable encoding from surrounding or related -code sections. - - - -Decision tree to help deciding which string type to use -------------------------------------------------------- - -if in libopenmpt - if in libopenmpt c++ interface - T = std::string, the encoding is utf8 - elif in libopenmpt c interface - T = char*, the encoding is utf8 - elif performance critical inner loop - T = char*, document the encoding if not clear from context - elif string literal containing non-ascii characters - T = MPT_UTF8 - elif path or file - if parsing path fragments - T = mpt::RawPathString - template your function on the concrete underlying string type - (std::string and std::wstring) or use preprocessor MPT_OS_WINDOWS - else - T = mpt::PathString - fi - else - T = mpt::ustring - fi -else - if performance critical inner loop - if needs unicode support - T = mpt::uchar* / MPT_ULITERAL - else - T = char*, document the encoding if not clear from context - fi - elif string literal containing non-ascii characters - T = MPT_UTF8 - elif path or file - if parsing path fragments - T = mpt::RawPathString - template your function on the concrete underlying string type - (std::string and std::wstring) or use preprocessor MPT_OS_WINDOWS - else - T = mpt::PathString - fi - elif winapi interfacing code - T = mpt::winstring - elif mfc/gui code - T = CString - else - if constexpr context or global data - T = mpt::uchar* / MPT_ULITERAL - else - T = mpt::ustring - fi - fi -fi - -This boils down to: Prefer mpt::PathString and mpt::ustring, and only use any -other string type if there is an obvious reason to do so. - - - -Character set conversions -------------------------- - -Character set conversions in OpenMPT are always fuzzy. - -Behaviour in case of an invalid source encoding and behaviour in case of an -unrepresentable destination encoding can be any of the following: - * The character is replaced by some replacement character ('?' or L'\ufffd' in - most cases). - * The character is replaced by a similar character (either semantically - similiar or visually similar). - * The character is transcribed with some ASCII text. - * The character is discarded. - * Conversion stops at this very character. - -Additionally. conversion may stop or continue on \0 characters in the middle of -the string. - -Behaviour can vary from one conversion tuple to any other. - -If you need to ensure lossless conversion, do a roundtrip conversion and check -for equality. - - - -Unicode handling ----------------- - -OpenMPT is generally not aware of and does not handle different Unicode -normalization forms. -You should be aware of the following possibilities: - * Conversion between UTF8, UTF16, UTF32 may or may not change between NFC and - NFD. - * Conversion from any non-Unicode 8bit encoding can result in both, NFC or NFD - forms. - * Conversion to any non-Unicode 8bit encoding may or may not involve - conversion to NFC, NFD, NFKC or NFKD during the conversion. This in - particular means that conversion of decomposed german umlauts to ISO8859-1 - may fail. - * Changing the normalization form of path strings may render the file - inaccessible. - -Unicode BOM may or may not be preserved and/or discarded during conversion. - -Invalid Unicode code points may be treated as invalid or as valid characters -when converting between different Unicode encodings. - - - -Interfacing with WinAPI ------------------------ - -When in MFC code, use CString. -When in non MFC code, either use std::wstring when directly interfacing with -APIs only available in WCHAR variants, or use mpt::winstring and -mpt::WinStringBuf helpers otherwise. -Specify TCHAR string literals with _T("foo") in mptrack/, and with TEXT("foo") -in common/ or sounddev/. _T() requires which is specific to the MSVC -runtime and not portable across compilers. TEXT() is from . We use -_T() in mptrack/ only because it is shorter. - - - -*/ - - - -namespace mpt { namespace String { - - - -#define C(x) (mpt::char_value((x))) - -// AMS1 actually only supports ASCII plus the modified control characters and no high chars at all. -// Just default to CP437 for those to keep things simple. -static constexpr char32_t CharsetTableCP437AMS[256] = { - C(' '),0x0001,0x0002,0x0003,0x00e4,0x0005,0x00e5,0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x00c4,0x00c5, // differs from CP437 - 0x0010,0x0011,0x0012,0x0013,0x00f6,0x0015,0x0016,0x0017,0x0018,0x00d6,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, // differs from CP437 - 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, - 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, - 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, - 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, - 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, - 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, - 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, - 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, - 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, - 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, - 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, - 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, - 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, - 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 -}; - -// AMS2: Looking at Velvet Studio's bitmap font (TPIC32.PCX), these appear to be the only supported non-ASCII chars. -static constexpr char32_t CharsetTableCP437AMS2[256] = { - C(' '),0x00a9,0x221a,0x00b7,C('0'),C('1'),C('2'),C('3'),C('4'),C('5'),C('6'),C('7'),C('8'),C('9'),C('A'),C('B'), // differs from CP437 - C('C'),C('D'),C('E'),C('F'),C(' '),0x00a7,C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '), // differs from CP437 - 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, - 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, - 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, - 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, - 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, - 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, - 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, - 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, - 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, - 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, - 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, - 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, - 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, - 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 -}; - -#undef C - - -// templated on 8bit strings because of type-safe variants -template -static Tdststring EncodeImpl(Charset charset, const mpt::widestring &src) -{ - static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); - static_assert(mpt::is_character::value); - switch(charset) - { -#if defined(MPT_ENABLE_CHARSET_LOCALE) - case Charset::Locale: return mpt::encode(mpt::logical_encoding::locale, src); break; -#endif - case Charset::UTF8: return mpt::encode(mpt::common_encoding::utf8, src); break; - case Charset::ASCII: return mpt::encode(mpt::common_encoding::ascii, src); break; - case Charset::ISO8859_1: return mpt::encode(mpt::common_encoding::iso8859_1, src); break; - case Charset::ISO8859_15: return mpt::encode(mpt::common_encoding::iso8859_15, src); break; - case Charset::CP850: return mpt::encode(mpt::common_encoding::cp850, src); break; - case Charset::CP437: return mpt::encode(mpt::common_encoding::cp437, src); break; - case Charset::CP437AMS: return mpt::encode(CharsetTableCP437AMS, src); break; - case Charset::CP437AMS2: return mpt::encode(CharsetTableCP437AMS2, src); break; - case Charset::Windows1252: return mpt::encode(mpt::common_encoding::windows1252, src); break; - case Charset::Amiga: return mpt::encode(mpt::common_encoding::amiga, src); break; - case Charset::RISC_OS: return mpt::encode(mpt::common_encoding::riscos, src); break; - case Charset::ISO8859_1_no_C1: return mpt::encode(mpt::common_encoding::iso8859_1_no_c1, src); break; - case Charset::ISO8859_15_no_C1: return mpt::encode(mpt::common_encoding::iso8859_15_no_c1, src); break; - case Charset::Amiga_no_C1: return mpt::encode(mpt::common_encoding::amiga_no_c1, src); break; - } - return Tdststring(); -} - - -// templated on 8bit strings because of type-safe variants -template -static mpt::widestring DecodeImpl(Charset charset, const Tsrcstring &src) -{ - static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); - static_assert(mpt::is_character::value); - switch(charset) - { -#if defined(MPT_ENABLE_CHARSET_LOCALE) - case Charset::Locale: return mpt::decode(mpt::logical_encoding::locale, src); break; -#endif - case Charset::UTF8: return mpt::decode(mpt::common_encoding::utf8, src); break; - case Charset::ASCII: return mpt::decode(mpt::common_encoding::ascii, src); break; - case Charset::ISO8859_1: return mpt::decode(mpt::common_encoding::iso8859_1, src); break; - case Charset::ISO8859_15: return mpt::decode(mpt::common_encoding::iso8859_15, src); break; - case Charset::CP850: return mpt::decode(mpt::common_encoding::cp850, src); break; - case Charset::CP437: return mpt::decode(mpt::common_encoding::cp437, src); break; - case Charset::CP437AMS: return mpt::decode(CharsetTableCP437AMS, src); break; - case Charset::CP437AMS2: return mpt::decode(CharsetTableCP437AMS2, src); break; - case Charset::Windows1252: return mpt::decode(mpt::common_encoding::windows1252, src); break; - case Charset::Amiga: return mpt::decode(mpt::common_encoding::amiga, src); break; - case Charset::RISC_OS: return mpt::decode(mpt::common_encoding::riscos, src); break; - case Charset::ISO8859_1_no_C1: return mpt::decode(mpt::common_encoding::iso8859_1_no_c1, src); break; - case Charset::ISO8859_15_no_C1: return mpt::decode(mpt::common_encoding::iso8859_15_no_c1, src); break; - case Charset::Amiga_no_C1: return mpt::decode(mpt::common_encoding::amiga_no_c1, src); break; - } - return mpt::widestring(); -} - - -// templated on 8bit strings because of type-safe variants -template -static Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src) -{ - static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); - static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); - if(to == from) - { - const typename Tsrcstring::value_type * src_beg = src.data(); - const typename Tsrcstring::value_type * src_end = src_beg + src.size(); - return Tdststring(reinterpret_cast(src_beg), reinterpret_cast(src_end)); - } - return EncodeImpl(to, DecodeImpl(from, src)); -} - - - -} // namespace String - - -bool IsUTF8(const std::string &str) -{ - return mpt::is_utf8(str); -} - - -#if MPT_WSTRING_CONVERT -std::wstring ToWide(Charset from, const std::string &str) -{ - return String::DecodeImpl(from, str); -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -std::wstring ToWide(const mpt::lstring &str) -{ - return String::DecodeImpl(Charset::Locale, str); -} -#endif // MPT_ENABLE_CHARSET_LOCALE -#endif - -#if MPT_WSTRING_CONVERT -std::string ToCharset(Charset to, const std::wstring &str) -{ - return String::EncodeImpl(to, str); -} -#endif -std::string ToCharset(Charset to, Charset from, const std::string &str) -{ - return String::ConvertImpl(to, from, str); -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -std::string ToCharset(Charset to, const mpt::lstring &str) -{ - return String::ConvertImpl(to, Charset::Locale, str); -} -#endif // MPT_ENABLE_CHARSET_LOCALE - -#if defined(MPT_ENABLE_CHARSET_LOCALE) -#if MPT_WSTRING_CONVERT -mpt::lstring ToLocale(const std::wstring &str) -{ - return String::EncodeImpl(Charset::Locale, str); -} -#endif -mpt::lstring ToLocale(Charset from, const std::string &str) -{ - return String::ConvertImpl(Charset::Locale, from, str); -} -#endif // MPT_ENABLE_CHARSET_LOCALE - -#if MPT_OS_WINDOWS -#if MPT_WSTRING_CONVERT -mpt::winstring ToWin(const std::wstring &str) -{ - #ifdef UNICODE - return str; - #else - return ToLocale(str); - #endif -} -#endif -mpt::winstring ToWin(Charset from, const std::string &str) -{ - #ifdef UNICODE - return ToWide(from, str); - #else - return ToLocale(from, str); - #endif -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::winstring ToWin(const mpt::lstring &str) -{ - #ifdef UNICODE - return ToWide(str); - #else - return str; - #endif -} -#endif // MPT_ENABLE_CHARSET_LOCALE -#endif // MPT_OS_WINDOWS - - -#if defined(MPT_WITH_MFC) - -CString ToCString(const std::wstring &str) -{ - #ifdef UNICODE - return str.c_str(); - #else - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return ToCharset(Charset::Locale, str).c_str(); - #endif -} -CString ToCString(Charset from, const std::string &str) -{ - #ifdef UNICODE - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return ToWide(from, str).c_str(); - #else - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return ToCharset(Charset::Locale, from, str).c_str(); - #endif -} -std::wstring ToWide(const CString &str) -{ - #ifdef UNICODE - return str.GetString(); - #else - return ToWide(Charset::Locale, str.GetString()); - #endif -} -std::string ToCharset(Charset to, const CString &str) -{ - #ifdef UNICODE - return ToCharset(to, str.GetString()); - #else - return ToCharset(to, Charset::Locale, str.GetString()); - #endif -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -CString ToCString(const mpt::lstring &str) -{ - #ifdef UNICODE - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return ToWide(str).c_str(); - #else - return str.c_str(); - #endif -} -mpt::lstring ToLocale(const CString &str) -{ - #ifdef UNICODE - return String::EncodeImpl(Charset::Locale, str.GetString()); - #else - return str.GetString(); - #endif -} -#endif // MPT_ENABLE_CHARSET_LOCALE -#if MPT_OS_WINDOWS -mpt::winstring ToWin(const CString &str) -{ - return str.GetString(); -} -#endif // MPT_OS_WINDOWS - -#endif // MPT_WITH_MFC - - -#if MPT_USTRING_MODE_WIDE -// inline -#else // !MPT_USTRING_MODE_WIDE -#if MPT_WSTRING_CONVERT -mpt::ustring ToUnicode(const std::wstring &str) -{ - return String::EncodeImpl(mpt::Charset::UTF8, str); -} -#endif -mpt::ustring ToUnicode(Charset from, const std::string &str) -{ - return String::ConvertImpl(mpt::Charset::UTF8, from, str); -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::ustring ToUnicode(const mpt::lstring &str) -{ - return String::ConvertImpl(mpt::Charset::UTF8, mpt::Charset::Locale, str); -} -#endif // MPT_ENABLE_CHARSET_LOCALE -#if defined(MPT_WITH_MFC) -mpt::ustring ToUnicode(const CString &str) -{ - #ifdef UNICODE - return String::EncodeImpl(mpt::Charset::UTF8, str.GetString()); - #else // !UNICODE - return String::ConvertImpl(mpt::Charset::UTF8, mpt::Charset::Locale, str.GetString()); - #endif // UNICODE -} -#endif // MPT_WITH_MFC -#endif // MPT_USTRING_MODE_WIDE - -#if MPT_USTRING_MODE_WIDE -// nothing, std::wstring overloads will catch all stuff -#else // !MPT_USTRING_MODE_WIDE -#if MPT_WSTRING_CONVERT -std::wstring ToWide(const mpt::ustring &str) -{ - return String::DecodeImpl(mpt::Charset::UTF8, str); -} -#endif -std::string ToCharset(Charset to, const mpt::ustring &str) -{ - return String::ConvertImpl(to, mpt::Charset::UTF8, str); -} -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::lstring ToLocale(const mpt::ustring &str) -{ - return String::ConvertImpl(mpt::Charset::Locale, mpt::Charset::UTF8, str); -} -#endif // MPT_ENABLE_CHARSET_LOCALE -#if MPT_OS_WINDOWS -mpt::winstring ToWin(const mpt::ustring &str) -{ - #ifdef UNICODE - return String::DecodeImpl(mpt::Charset::UTF8, str); - #else - return String::ConvertImpl(mpt::Charset::Locale, mpt::Charset::UTF8, str); - #endif -} -#endif // MPT_OS_WINDOWS -#if defined(MPT_WITH_MFC) -CString ToCString(const mpt::ustring &str) -{ - #ifdef UNICODE - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return String::DecodeImpl(mpt::Charset::UTF8, str).c_str(); - #else // !UNICODE - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return String::ConvertImpl(mpt::Charset::Locale, mpt::Charset::UTF8, str).c_str(); - #endif // UNICODE -} -#endif // MPT_WITH_MFC -#endif // MPT_USTRING_MODE_WIDE - - - - - -static mpt::Charset CharsetFromCodePage(uint16 codepage, mpt::Charset fallback, bool * isFallback = nullptr) -{ - mpt::Charset result = fallback; - switch(codepage) - { - case 65001: - result = mpt::Charset::UTF8; - if(isFallback) *isFallback = false; - break; - case 20127: - result = mpt::Charset::ASCII; - if(isFallback) *isFallback = false; - break; - case 28591: - result = mpt::Charset::ISO8859_1; - if(isFallback) *isFallback = false; - break; - case 28605: - result = mpt::Charset::ISO8859_15; - if(isFallback) *isFallback = false; - break; - case 437: - result = mpt::Charset::CP437; - if(isFallback) *isFallback = false; - break; - case 1252: - result = mpt::Charset::Windows1252; - if(isFallback) *isFallback = false; - break; - default: - result = fallback; - if(isFallback) *isFallback = true; - break; - } - return result; -} - -mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str) -{ - #if MPT_OS_WINDOWS - mpt::ustring result; - bool noCharsetMatch = true; - mpt::Charset charset = mpt::CharsetFromCodePage(codepage, fallback, &noCharsetMatch); - if(noCharsetMatch && mpt::has_codepage(codepage)) - { - result = mpt::ToUnicode(mpt::decode(codepage, str)); - } else - { - result = mpt::ToUnicode(charset, str); - } - return result; - #else // !MPT_OS_WINDOWS - return mpt::ToUnicode(mpt::CharsetFromCodePage(codepage, fallback), str); - #endif // MPT_OS_WINDOWS -} - - - - - -char ToLowerCaseAscii(char c) -{ - return mpt::to_lower_ascii(c); -} - -char ToUpperCaseAscii(char c) -{ - return mpt::to_upper_ascii(c); -} - -std::string ToLowerCaseAscii(std::string s) -{ - std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToLowerCaseAscii)); - return s; -} - -std::string ToUpperCaseAscii(std::string s) -{ - std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToUpperCaseAscii)); - return s; -} - -int CompareNoCaseAscii(const char *a, const char *b, std::size_t n) -{ - while(n--) - { - unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(*a)); - unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(*b)); - if(ac != bc) - { - return ac < bc ? -1 : 1; - } else if(!ac && !bc) - { - return 0; - } - ++a; - ++b; - } - return 0; -} - -int CompareNoCaseAscii(std::string_view a, std::string_view b) -{ - for(std::size_t i = 0; i < std::min(a.length(), b.length()); ++i) - { - unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(a[i])); - unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(b[i])); - if(ac != bc) - { - return ac < bc ? -1 : 1; - } else if(!ac && !bc) - { - return 0; - } - } - if(a.length() == b.length()) - { - return 0; - } - return a.length() < b.length() ? -1 : 1; -} - -int CompareNoCaseAscii(const std::string &a, const std::string &b) -{ - return CompareNoCaseAscii(std::string_view(a), std::string_view(b)); -} - - -#if defined(MODPLUG_TRACKER) - -mpt::ustring ToLowerCase(const mpt::ustring &s) -{ - #if defined(MPT_WITH_MFC) - #if defined(UNICODE) - CString tmp = mpt::ToCString(s); - tmp.MakeLower(); - return mpt::ToUnicode(tmp); - #else // !UNICODE - CStringW tmp = mpt::ToWide(s).c_str(); - tmp.MakeLower(); - return mpt::ToUnicode(tmp.GetString()); - #endif // UNICODE - #else // !MPT_WITH_MFC - std::wstring ws = mpt::ToWide(s); - std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower); - return mpt::ToUnicode(ws); - #endif // MPT_WITH_MFC -} - -mpt::ustring ToUpperCase(const mpt::ustring &s) -{ - #if defined(MPT_WITH_MFC) - #if defined(UNICODE) - CString tmp = mpt::ToCString(s); - tmp.MakeUpper(); - return mpt::ToUnicode(tmp); - #else // !UNICODE - CStringW tmp = mpt::ToWide(s).c_str(); - tmp.MakeUpper(); - return mpt::ToUnicode(tmp.GetString()); - #endif // UNICODE - #else // !MPT_WITH_MFC - std::wstring ws = mpt::ToWide(s); - std::transform(ws.begin(), ws.end(), ws.begin(), &std::towupper); - return mpt::ToUnicode(ws); - #endif // MPT_WITH_MFC -} - -#endif // MODPLUG_TRACKER - - - -} // namespace mpt - - - -OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptString.h b/Frameworks/OpenMPT/OpenMPT/common/mptString.h index c308eef94..16fc64c49 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptString.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptString.h @@ -12,19 +12,19 @@ #include "openmpt/all/BuildSettings.hpp" -#include "mpt/base/alloc.hpp" -#include "mpt/base/span.hpp" #include "mpt/string/types.hpp" #include "mpt/string/utility.hpp" - -#include "mptBaseTypes.h" +#include "mpt/string_transcode/transcode.hpp" #include -#include #include #include +#include -#include +#include +#if defined(MODPLUG_TRACKER) +#include +#endif // MODPLUG_TRACKER @@ -36,21 +36,7 @@ namespace mpt -namespace String -{ - - -template -inline Tstring Replace(Tstring str, const Tstring2 &oldStr, const Tstring3 &newStr) -{ - return mpt::replace(str, oldStr, newStr); -} - - -} // namespace String - - -enum class Charset { +enum class CharsetEnum { UTF8, @@ -59,8 +45,23 @@ enum class Charset { ISO8859_1, ISO8859_15, - CP850, CP437, + CP737, + CP775, + CP850, + CP852, + CP855, + CP857, + CP860, + CP861, + CP862, + CP863, + CP864, + CP865, + CP866, + CP869, + CP874, + CP437AMS, CP437AMS2, @@ -68,6 +69,7 @@ enum class Charset { Amiga, RISC_OS, + AtariST, ISO8859_1_no_C1, ISO8859_15_no_C1, @@ -79,34 +81,228 @@ enum class Charset { }; +namespace CharsetTable +{ + +#define C(x) (mpt::char_value((x))) + +// AMS1 actually only supports ASCII plus the modified control characters and no high chars at all. +// Just default to CP437 for those to keep things simple. +inline constexpr char32_t CP437AMS[256] = { + C(' '),0x0001,0x0002,0x0003,0x00e4,0x0005,0x00e5,0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x00c4,0x00c5, // differs from CP437 + 0x0010,0x0011,0x0012,0x0013,0x00f6,0x0015,0x0016,0x0017,0x0018,0x00d6,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, // differs from CP437 + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +// AMS2: Looking at Velvet Studio's bitmap font (TPIC32.PCX), these appear to be the only supported non-ASCII chars. +inline constexpr char32_t CP437AMS2[256] = { + C(' '),0x00a9,0x221a,0x00b7,C('0'),C('1'),C('2'),C('3'),C('4'),C('5'),C('6'),C('7'),C('8'),C('9'),C('A'),C('B'), // differs from CP437 + C('C'),C('D'),C('E'),C('F'),C(' '),0x00a7,C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '), // differs from CP437 + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +#undef C + +} // namespace CharsetTable -// source code / preprocessor (i.e. # token) -inline constexpr Charset CharsetSource = Charset::ASCII; -// debug log files -inline constexpr Charset CharsetLogfile = Charset::UTF8; +struct CharsetTranscoder +{ -// std::clog / std::cout / std::cerr -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS && defined(MPT_ENABLE_CHARSET_LOCALE) -inline constexpr Charset CharsetStdIO = Charset::Locale; -#else -inline constexpr Charset CharsetStdIO = Charset::UTF8; -#endif +private: + + CharsetEnum m_Charset; + +public: + + constexpr CharsetEnum GetCharset() const noexcept + { + return m_Charset; + } + + constexpr CharsetTranscoder(CharsetEnum charset) noexcept + : m_Charset(charset) + { + return; + } + + constexpr operator CharsetEnum() const noexcept + { + return m_Charset; + } + + // templated on 8bit strings because of type-safe variants + template + inline Tdststring encode(const mpt::widestring &src) const + { + static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); + static_assert(mpt::is_character::value); + switch(m_Charset) + { + #if defined(MPT_ENABLE_CHARSET_LOCALE) + case CharsetEnum::Locale: return mpt::encode(mpt::logical_encoding::locale, src); break; + #endif + case CharsetEnum::UTF8: return mpt::encode(mpt::common_encoding::utf8, src); break; + case CharsetEnum::ASCII: return mpt::encode(mpt::common_encoding::ascii, src); break; + case CharsetEnum::ISO8859_1: return mpt::encode(mpt::common_encoding::iso8859_1, src); break; + case CharsetEnum::ISO8859_15: return mpt::encode(mpt::common_encoding::iso8859_15, src); break; + case CharsetEnum::CP437: return mpt::encode(mpt::common_encoding::cp437, src); break; + case CharsetEnum::CP737: return mpt::encode(mpt::common_encoding::cp737, src); break; + case CharsetEnum::CP775: return mpt::encode(mpt::common_encoding::cp775, src); break; + case CharsetEnum::CP850: return mpt::encode(mpt::common_encoding::cp850, src); break; + case CharsetEnum::CP852: return mpt::encode(mpt::common_encoding::cp852, src); break; + case CharsetEnum::CP855: return mpt::encode(mpt::common_encoding::cp855, src); break; + case CharsetEnum::CP857: return mpt::encode(mpt::common_encoding::cp857, src); break; + case CharsetEnum::CP860: return mpt::encode(mpt::common_encoding::cp860, src); break; + case CharsetEnum::CP861: return mpt::encode(mpt::common_encoding::cp861, src); break; + case CharsetEnum::CP862: return mpt::encode(mpt::common_encoding::cp862, src); break; + case CharsetEnum::CP863: return mpt::encode(mpt::common_encoding::cp863, src); break; + case CharsetEnum::CP864: return mpt::encode(mpt::common_encoding::cp864, src); break; + case CharsetEnum::CP865: return mpt::encode(mpt::common_encoding::cp865, src); break; + case CharsetEnum::CP866: return mpt::encode(mpt::common_encoding::cp866, src); break; + case CharsetEnum::CP869: return mpt::encode(mpt::common_encoding::cp869, src); break; + case CharsetEnum::CP874: return mpt::encode(mpt::common_encoding::cp874, src); break; + case CharsetEnum::CP437AMS: return mpt::encode(CharsetTable::CP437AMS, src); break; + case CharsetEnum::CP437AMS2: return mpt::encode(CharsetTable::CP437AMS2, src); break; + case CharsetEnum::Windows1252: return mpt::encode(mpt::common_encoding::windows1252, src); break; + case CharsetEnum::Amiga: return mpt::encode(mpt::common_encoding::amiga, src); break; + case CharsetEnum::RISC_OS: return mpt::encode(mpt::common_encoding::riscos, src); break; + case CharsetEnum::AtariST: return mpt::encode(mpt::common_encoding::atarist, src); break; + case CharsetEnum::ISO8859_1_no_C1: return mpt::encode(mpt::common_encoding::iso8859_1_no_c1, src); break; + case CharsetEnum::ISO8859_15_no_C1: return mpt::encode(mpt::common_encoding::iso8859_15_no_c1, src); break; + case CharsetEnum::Amiga_no_C1: return mpt::encode(mpt::common_encoding::amiga_no_c1, src); break; + } + return Tdststring(); + } + + // templated on 8bit strings because of type-safe variants + template + inline mpt::widestring decode(const Tsrcstring &src) const + { + static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); + static_assert(mpt::is_character::value); + switch(m_Charset) + { + #if defined(MPT_ENABLE_CHARSET_LOCALE) + case CharsetEnum::Locale: return mpt::decode(mpt::logical_encoding::locale, src); break; + #endif + case CharsetEnum::UTF8: return mpt::decode(mpt::common_encoding::utf8, src); break; + case CharsetEnum::ASCII: return mpt::decode(mpt::common_encoding::ascii, src); break; + case CharsetEnum::ISO8859_1: return mpt::decode(mpt::common_encoding::iso8859_1, src); break; + case CharsetEnum::ISO8859_15: return mpt::decode(mpt::common_encoding::iso8859_15, src); break; + case CharsetEnum::CP437: return mpt::decode(mpt::common_encoding::cp437, src); break; + case CharsetEnum::CP737: return mpt::decode(mpt::common_encoding::cp737, src); break; + case CharsetEnum::CP775: return mpt::decode(mpt::common_encoding::cp775, src); break; + case CharsetEnum::CP850: return mpt::decode(mpt::common_encoding::cp850, src); break; + case CharsetEnum::CP852: return mpt::decode(mpt::common_encoding::cp852, src); break; + case CharsetEnum::CP855: return mpt::decode(mpt::common_encoding::cp855, src); break; + case CharsetEnum::CP857: return mpt::decode(mpt::common_encoding::cp857, src); break; + case CharsetEnum::CP860: return mpt::decode(mpt::common_encoding::cp860, src); break; + case CharsetEnum::CP861: return mpt::decode(mpt::common_encoding::cp861, src); break; + case CharsetEnum::CP862: return mpt::decode(mpt::common_encoding::cp862, src); break; + case CharsetEnum::CP863: return mpt::decode(mpt::common_encoding::cp863, src); break; + case CharsetEnum::CP864: return mpt::decode(mpt::common_encoding::cp864, src); break; + case CharsetEnum::CP865: return mpt::decode(mpt::common_encoding::cp865, src); break; + case CharsetEnum::CP866: return mpt::decode(mpt::common_encoding::cp866, src); break; + case CharsetEnum::CP869: return mpt::decode(mpt::common_encoding::cp869, src); break; + case CharsetEnum::CP874: return mpt::decode(mpt::common_encoding::cp874, src); break; + case CharsetEnum::CP437AMS: return mpt::decode(CharsetTable::CP437AMS, src); break; + case CharsetEnum::CP437AMS2: return mpt::decode(CharsetTable::CP437AMS2, src); break; + case CharsetEnum::Windows1252: return mpt::decode(mpt::common_encoding::windows1252, src); break; + case CharsetEnum::Amiga: return mpt::decode(mpt::common_encoding::amiga, src); break; + case CharsetEnum::RISC_OS: return mpt::decode(mpt::common_encoding::riscos, src); break; + case CharsetEnum::AtariST: return mpt::decode(mpt::common_encoding::atarist, src); break; + case CharsetEnum::ISO8859_1_no_C1: return mpt::decode(mpt::common_encoding::iso8859_1_no_c1, src); break; + case CharsetEnum::ISO8859_15_no_C1: return mpt::decode(mpt::common_encoding::iso8859_15_no_c1, src); break; + case CharsetEnum::Amiga_no_C1: return mpt::decode(mpt::common_encoding::amiga_no_c1, src); break; + } + return mpt::widestring(); + } + +}; + + + +struct Charset + : public CharsetTranscoder +{ + + constexpr Charset(mpt::CharsetEnum charset) noexcept + : CharsetTranscoder(charset) + { + return; + } + + constexpr Charset(mpt::CharsetTranscoder charset) noexcept + : CharsetTranscoder(charset.GetCharset()) + { + return; + } + + static inline constexpr auto UTF8 = mpt::CharsetTranscoder{ mpt::CharsetEnum::UTF8 }; + static inline constexpr auto ASCII = mpt::CharsetTranscoder{ mpt::CharsetEnum::ASCII }; + static inline constexpr auto ISO8859_1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_1 }; + static inline constexpr auto ISO8859_15 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_15 }; + static inline constexpr auto CP437 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437 }; + static inline constexpr auto CP737 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP737 }; + static inline constexpr auto CP775 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP775 }; + static inline constexpr auto CP850 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP850 }; + static inline constexpr auto CP852 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP852 }; + static inline constexpr auto CP855 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP855 }; + static inline constexpr auto CP857 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP857 }; + static inline constexpr auto CP860 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP860 }; + static inline constexpr auto CP861 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP861 }; + static inline constexpr auto CP862 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP862 }; + static inline constexpr auto CP863 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP863 }; + static inline constexpr auto CP864 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP864 }; + static inline constexpr auto CP865 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP865 }; + static inline constexpr auto CP866 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP866 }; + static inline constexpr auto CP869 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP869 }; + static inline constexpr auto CP874 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP874 }; + static inline constexpr auto CP437AMS = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437AMS }; + static inline constexpr auto CP437AMS2 = mpt::CharsetTranscoder{ mpt::CharsetEnum::CP437AMS2 }; + static inline constexpr auto Windows1252 = mpt::CharsetTranscoder{ mpt::CharsetEnum::Windows1252 }; + static inline constexpr auto Amiga = mpt::CharsetTranscoder{ mpt::CharsetEnum::Amiga }; + static inline constexpr auto RISC_OS = mpt::CharsetTranscoder{ mpt::CharsetEnum::RISC_OS }; + static inline constexpr auto AtariST = mpt::CharsetTranscoder{ mpt::CharsetEnum::AtariST }; + static inline constexpr auto ISO8859_1_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_1_no_C1 }; + static inline constexpr auto ISO8859_15_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::ISO8859_15_no_C1 }; + static inline constexpr auto Amiga_no_C1 = mpt::CharsetTranscoder{ mpt::CharsetEnum::Amiga_no_C1 }; -// getenv #if defined(MPT_ENABLE_CHARSET_LOCALE) -inline constexpr Charset CharsetEnvironment = Charset::Locale; -#else -inline constexpr Charset CharsetEnvironment = Charset::UTF8; -#endif + static inline constexpr auto Locale = mpt::CharsetTranscoder{ mpt::CharsetEnum::Locale }; +#endif // MPT_ENABLE_CHARSET_LOCALE + +}; + -// std::exception::what() -#if defined(MPT_ENABLE_CHARSET_LOCALE) -inline constexpr Charset CharsetException = Charset::Locale; -#else -inline constexpr Charset CharsetException = Charset::UTF8; -#endif @@ -117,22 +313,39 @@ inline constexpr Charset CharsetException = Charset::UTF8; // - can give false negatives because of possible unicode normalization during conversion // - can give false positives if the 8bit encoding contains high-ascii only in valid utf8 groups // - slow because of double conversion -bool IsUTF8(const std::string &str); +inline bool IsUTF8(const std::string &str) +{ + return mpt::is_utf8(str); +} -#if MPT_WSTRING_CONVERT +template +inline mpt::ustring ToUnicode(Tsrc &&str) +{ + return mpt::transcode(std::forward(str)); +} +template +inline mpt::ustring ToUnicode(Tencoding &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(from), std::forward(str)); +} + +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // Convert to a wide character string. // The wide encoding is UTF-16 or UTF-32, based on sizeof(wchar_t). // If str does not contain any invalid characters, this conversion is lossless. // Invalid source bytes will be replaced by some replacement character or string. -inline std::wstring ToWide(const std::wstring &str) { return str; } -inline std::wstring ToWide(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); } -std::wstring ToWide(Charset from, const std::string &str); -inline std::wstring ToWide(Charset from, const char * str) { return ToWide(from, str ? std::string(str) : std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -std::wstring ToWide(const mpt::lstring &str); -#endif // MPT_ENABLE_CHARSET_LOCALE +template +inline std::wstring ToWide(Tsrc &&str) +{ + return mpt::transcode(std::forward(str)); +} +template +inline std::wstring ToWide(Tencoding &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(from), std::forward(str)); +} #endif // Convert to a string encoded in the 'to'-specified character set. @@ -141,66 +354,54 @@ std::wstring ToWide(const mpt::lstring &str); // 'to' is UTF8. // Invalid source bytes or characters that are not representable in the // destination charset will be replaced by some replacement character or string. -#if MPT_WSTRING_CONVERT -std::string ToCharset(Charset to, const std::wstring &str); -inline std::string ToCharset(Charset to, const wchar_t * str) { return ToCharset(to, str ? std::wstring(str) : std::wstring()); } -#endif -std::string ToCharset(Charset to, Charset from, const std::string &str); -inline std::string ToCharset(Charset to, Charset from, const char * str) { return ToCharset(to, from, str ? std::string(str) : std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -std::string ToCharset(Charset to, const mpt::lstring &str); -#endif // MPT_ENABLE_CHARSET_LOCALE +template +inline std::string ToCharset(Tencoding &&to, Tsrc &&str) +{ + return mpt::transcode(std::forward(to), std::forward(str)); +} +template +inline std::string ToCharset(Tto &&to, Tfrom &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(to), std::forward(from), std::forward(str)); +} #if defined(MPT_ENABLE_CHARSET_LOCALE) -#if MPT_WSTRING_CONVERT -mpt::lstring ToLocale(const std::wstring &str); -inline mpt::lstring ToLocale(const wchar_t * str) { return ToLocale(str ? std::wstring(str): std::wstring()); } -#endif -mpt::lstring ToLocale(Charset from, const std::string &str); -inline mpt::lstring ToLocale(Charset from, const char * str) { return ToLocale(from, str ? std::string(str): std::string()); } -inline mpt::lstring ToLocale(const mpt::lstring &str) { return str; } +template +inline mpt::lstring ToLocale(Tsrc &&str) +{ + return mpt::transcode(std::forward(str)); +} +template +inline mpt::lstring ToLocale(Tencoding &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(from), std::forward(str)); +} #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS -#if MPT_WSTRING_CONVERT -mpt::winstring ToWin(const std::wstring &str); -inline mpt::winstring ToWin(const wchar_t * str) { return ToWin(str ? std::wstring(str): std::wstring()); } -#endif -mpt::winstring ToWin(Charset from, const std::string &str); -inline mpt::winstring ToWin(Charset from, const char * str) { return ToWin(from, str ? std::string(str): std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::winstring ToWin(const mpt::lstring &str); -#endif // MPT_ENABLE_CHARSET_LOCALE +template +inline mpt::winstring ToWin(Tsrc &&str) +{ + return mpt::transcode(std::forward(str)); +} +template +inline mpt::winstring ToWin(Tencoding &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(from), std::forward(str)); +} #endif // MPT_OS_WINDOWS - #if defined(MPT_WITH_MFC) -#if !(MPT_WSTRING_CONVERT) -#error "MFC depends on MPT_WSTRING_CONVERT)" -#endif - -// Convert to a MFC CString. The CString encoding depends on UNICODE. -// This should also be used when converting to TCHAR strings. -// If UNICODE is defined, this is a completely lossless operation. -inline CString ToCString(const CString &str) { return str; } -CString ToCString(const std::wstring &str); -inline CString ToCString(const wchar_t * str) { return ToCString(str ? std::wstring(str) : std::wstring()); } -CString ToCString(Charset from, const std::string &str); -inline CString ToCString(Charset from, const char * str) { return ToCString(from, str ? std::string(str) : std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -CString ToCString(const mpt::lstring &str); -mpt::lstring ToLocale(const CString &str); -#endif // MPT_ENABLE_CHARSET_LOCALE -#if MPT_OS_WINDOWS -mpt::winstring ToWin(const CString &str); -#endif // MPT_OS_WINDOWS - -// Convert from a MFC CString. The CString encoding depends on UNICODE. -// This should also be used when converting from TCHAR strings. -// If UNICODE is defined, this is a completely lossless operation. -std::wstring ToWide(const CString &str); -std::string ToCharset(Charset to, const CString &str); - +template +inline CString ToCString(Tsrc &&str) +{ + return mpt::transcode(std::forward(str)); +} +template +inline CString ToCString(Tencoding &&from, Tsrc &&str) +{ + return mpt::transcode(std::forward(from), std::forward(str)); +} #endif // MPT_WITH_MFC @@ -211,92 +412,141 @@ std::string ToCharset(Charset to, const CString &str); -#if MPT_USTRING_MODE_WIDE -#if !(MPT_WSTRING_CONVERT) -#error "MPT_USTRING_MODE_WIDE depends on MPT_WSTRING_CONVERT)" -#endif -inline mpt::ustring ToUnicode(const std::wstring &str) { return str; } -inline mpt::ustring ToUnicode(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); } -inline mpt::ustring ToUnicode(Charset from, const std::string &str) { return ToWide(from, str); } -inline mpt::ustring ToUnicode(Charset from, const char * str) { return ToUnicode(from, str ? std::string(str) : std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -inline mpt::ustring ToUnicode(const mpt::lstring &str) { return ToWide(str); } -#endif // MPT_ENABLE_CHARSET_LOCALE -#if defined(MPT_WITH_MFC) -inline mpt::ustring ToUnicode(const CString &str) { return ToWide(str); } -#endif // MFC -#else // !MPT_USTRING_MODE_WIDE -inline mpt::ustring ToUnicode(const mpt::ustring &str) { return str; } -#if MPT_WSTRING_CONVERT -mpt::ustring ToUnicode(const std::wstring &str); -inline mpt::ustring ToUnicode(const wchar_t * str) { return ToUnicode(str ? std::wstring(str) : std::wstring()); } -#endif -mpt::ustring ToUnicode(Charset from, const std::string &str); -inline mpt::ustring ToUnicode(Charset from, const char * str) { return ToUnicode(from, str ? std::string(str) : std::string()); } -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::ustring ToUnicode(const mpt::lstring &str); -#endif // MPT_ENABLE_CHARSET_LOCALE -#if defined(MPT_WITH_MFC) -mpt::ustring ToUnicode(const CString &str); -#endif // MPT_WITH_MFC -#endif // MPT_USTRING_MODE_WIDE - -#if MPT_USTRING_MODE_WIDE -#if !(MPT_WSTRING_CONVERT) -#error "MPT_USTRING_MODE_WIDE depends on MPT_WSTRING_CONVERT)" -#endif -// nothing, std::wstring overloads will catch all stuff -#else // !MPT_USTRING_MODE_WIDE -#if MPT_WSTRING_CONVERT -std::wstring ToWide(const mpt::ustring &str); -#endif -std::string ToCharset(Charset to, const mpt::ustring &str); -#if defined(MPT_ENABLE_CHARSET_LOCALE) -mpt::lstring ToLocale(const mpt::ustring &str); -#endif // MPT_ENABLE_CHARSET_LOCALE -#if MPT_OS_WINDOWS -mpt::winstring ToWin(const mpt::ustring &str); -#endif // MPT_OS_WINDOWS -#if defined(MPT_WITH_MFC) -CString ToCString(const mpt::ustring &str); -#endif // MPT_WITH_MFC -#endif // MPT_USTRING_MODE_WIDE - - - - - // The MPT_UTF8 allows specifying UTF8 char arrays. // The resulting type is mpt::ustring and the construction might require runtime translation, // i.e. it is NOT generally available at compile time. // Use explicit UTF8 encoding, // i.e. U+00FC (LATIN SMALL LETTER U WITH DIAERESIS) would be written as "\xC3\xBC". -#define MPT_UTF8(x) mpt::ToUnicode(mpt::Charset::UTF8, x) +#define MPT_UTF8(x) mpt::transcode(mpt::common_encoding::utf8, x) + + + +template +inline mpt::ustring ToUnicode(uint16 codepage, Tencoding &&fallback, Tsrc &&str) +{ + #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + mpt::ustring result; + std::optional charset = mpt::optional_encoding_from_codepage(codepage); + if(charset.has_value()) + { + result = mpt::transcode(charset.value(), std::forward(str)); + } else if(mpt::has_codepage(static_cast(codepage))) + { + result = mpt::transcode(static_cast(codepage), std::forward(str)); + } else + { + result = mpt::transcode(std::forward(fallback), std::forward(str)); + } + return result; + #else // !MPT_OS_WINDOWS + std::optional charset = mpt::optional_encoding_from_codepage(codepage); + return charset.has_value() ? mpt::transcode(charset.value(), std::forward(str)) : mpt::transcode(std::forward(fallback), std::forward(str)); + #endif // MPT_OS_WINDOWS +} -mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str); +inline char ToLowerCaseAscii(char c) +{ + return mpt::to_lower_ascii(c); +} +inline char ToUpperCaseAscii(char c) +{ + return mpt::to_upper_ascii(c); +} +inline std::string ToLowerCaseAscii(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToLowerCaseAscii)); + return s; +} +inline std::string ToUpperCaseAscii(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), static_cast(&mpt::ToUpperCaseAscii)); + return s; +} +inline int CompareNoCaseAscii(const char *a, const char *b, std::size_t n) +{ + while(n--) + { + unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(*a)); + unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(*b)); + if(ac != bc) + { + return ac < bc ? -1 : 1; + } else if(!ac && !bc) + { + return 0; + } + ++a; + ++b; + } + return 0; +} -char ToLowerCaseAscii(char c); -char ToUpperCaseAscii(char c); -std::string ToLowerCaseAscii(std::string s); -std::string ToUpperCaseAscii(std::string s); +inline int CompareNoCaseAscii(std::string_view a, std::string_view b) +{ + for(std::size_t i = 0; i < std::min(a.length(), b.length()); ++i) + { + unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(a[i])); + unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(b[i])); + if(ac != bc) + { + return ac < bc ? -1 : 1; + } else if(!ac && !bc) + { + return 0; + } + } + if(a.length() == b.length()) + { + return 0; + } + return a.length() < b.length() ? -1 : 1; +} -int CompareNoCaseAscii(const char *a, const char *b, std::size_t n); -int CompareNoCaseAscii(std::string_view a, std::string_view b); -int CompareNoCaseAscii(const std::string &a, const std::string &b); +inline int CompareNoCaseAscii(const std::string &a, const std::string &b) +{ + return CompareNoCaseAscii(std::string_view(a), std::string_view(b)); +} #if defined(MODPLUG_TRACKER) -mpt::ustring ToLowerCase(const mpt::ustring &s); -mpt::ustring ToUpperCase(const mpt::ustring &s); +inline mpt::ustring ToLowerCase(const mpt::ustring &s) +{ + #if defined(MPT_WITH_MFC) + #if defined(UNICODE) + return mpt::transcode(mpt::transcode(s).MakeLower()); + #else // !UNICODE + return mpt::transcode(mpt::transcode(s).MakeLower()); + #endif // UNICODE + #else // !MPT_WITH_MFC + std::wstring ws = mpt::transcode(s); + std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower); + return mpt::transcode(ws); + #endif // MPT_WITH_MFC +} + +inline mpt::ustring ToUpperCase(const mpt::ustring &s) +{ + #if defined(MPT_WITH_MFC) + #if defined(UNICODE) + return mpt::transcode(mpt::transcode(s).MakeUpper()); + #else // !UNICODE + return mpt::transcode(mpt::transcode(s).MakeUpper()); + #endif // UNICODE + #else // !MPT_WITH_MFC + std::wstring ws = mpt::transcode(s); + std::transform(ws.begin(), ws.end(), ws.begin(), &std::towupper); + return mpt::transcode(ws); + #endif // MPT_WITH_MFC +} #endif // MODPLUG_TRACKER @@ -317,32 +567,32 @@ mpt::ustring ToUpperCase(const mpt::ustring &s); // Warning: These types will silently do charset conversions. Only use them when this can be tolerated. // BasicAnyString is convertable to mpt::ustring and constructable from any string at all. -template +template class BasicAnyString : public mpt::ustring { private: - static mpt::ustring From8bit(const std::string &str) + static mpt::ustring From8bit(std::string str) { - if constexpr(charset == mpt::Charset::UTF8) + if constexpr(charset == mpt::CharsetEnum::UTF8) { - return mpt::ToUnicode(mpt::Charset::UTF8, str); + return mpt::transcode(mpt::common_encoding::utf8, std::move(str)); } else { // auto utf8 detection if constexpr(tryUTF8) { - if(mpt::IsUTF8(str)) + if(mpt::is_utf8(str)) { - return mpt::ToUnicode(mpt::Charset::UTF8, str); + return mpt::transcode(mpt::common_encoding::utf8, std::move(str)); } else { - return mpt::ToUnicode(charset, str); + return mpt::transcode(mpt::CharsetTranscoder(charset), std::move(str)); } } else { - return mpt::ToUnicode(charset, str); + return mpt::transcode(mpt::CharsetTranscoder(charset), std::move(str)); } } } @@ -350,97 +600,83 @@ private: public: // 8 bit - BasicAnyString(const char *str) : mpt::ustring(From8bit(str ? str : std::string())) { } - BasicAnyString(const std::string str) : mpt::ustring(From8bit(str)) { } + BasicAnyString(const char *str) + : mpt::ustring(From8bit(str ? str : std::string())) + { + return; + } + BasicAnyString(std::string str) + : mpt::ustring(From8bit(std::move(str))) + { + return; + } - // locale -#if defined(MPT_ENABLE_CHARSET_LOCALE) - BasicAnyString(const mpt::lstring str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif // MPT_ENABLE_CHARSET_LOCALE - - // unicode - BasicAnyString(const mpt::ustring &str) : mpt::ustring(str) { } - BasicAnyString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { } -#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT - BasicAnyString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif -#if MPT_WSTRING_CONVERT - BasicAnyString(const wchar_t *str) : mpt::ustring(str ? mpt::ToUnicode(str) : mpt::ustring()) { } -#endif - - // mfc -#if defined(MPT_WITH_MFC) - BasicAnyString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif // MPT_WITH_MFC - - // fallback for custom string types - template BasicAnyString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { } - template BasicAnyString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward(str))) { } + template + BasicAnyString(Tstring &&str) + : mpt::ustring(mpt::transcode(std::forward(str))) + { + return; + } }; -// AnyUnicodeString is convertable to mpt::ustring and constructable from any unicode string, +// AnyUnicodeString is convertable to mpt::ustring and constructable from any known encoding class AnyUnicodeString : public mpt::ustring { public: - // locale -#if defined(MPT_ENABLE_CHARSET_LOCALE) - AnyUnicodeString(const mpt::lstring &str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif // MPT_ENABLE_CHARSET_LOCALE - - // unicode - AnyUnicodeString(const mpt::ustring &str) : mpt::ustring(str) { } - AnyUnicodeString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { } -#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT - AnyUnicodeString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif -#if MPT_WSTRING_CONVERT - AnyUnicodeString(const wchar_t *str) : mpt::ustring(str ? mpt::ToUnicode(str) : mpt::ustring()) { } -#endif - - // mfc -#if defined(MPT_WITH_MFC) - AnyUnicodeString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { } -#endif // MPT_WITH_MFC - - // fallback for custom string types - template AnyUnicodeString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { } - template AnyUnicodeString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward(str))) { } + template + AnyUnicodeString(Tstring &&str) + : mpt::ustring(mpt::transcode(std::forward(str))) + { + return; + } }; // AnyString // Try to do the smartest auto-magic we can do. #if defined(MPT_ENABLE_CHARSET_LOCALE) -using AnyString = BasicAnyString; +using AnyString = BasicAnyString; #elif MPT_OS_WINDOWS -using AnyString = BasicAnyString; +using AnyString = BasicAnyString; #else -using AnyString = BasicAnyString; +using AnyString = BasicAnyString; #endif // AnyStringLocale // char-based strings are assumed to be in locale encoding. #if defined(MPT_ENABLE_CHARSET_LOCALE) -using AnyStringLocale = BasicAnyString; +using AnyStringLocale = BasicAnyString; #else -using AnyStringLocale = BasicAnyString; +using AnyStringLocale = BasicAnyString; #endif // AnyStringUTF8orLocale // char-based strings are tried in UTF8 first, if this fails, locale is used. #if defined(MPT_ENABLE_CHARSET_LOCALE) -using AnyStringUTF8orLocale = BasicAnyString; +using AnyStringUTF8orLocale = BasicAnyString; #else -using AnyStringUTF8orLocale = BasicAnyString; +using AnyStringUTF8orLocale = BasicAnyString; #endif // AnyStringUTF8 // char-based strings are assumed to be in UTF8. -using AnyStringUTF8 = BasicAnyString; +using AnyStringUTF8 = BasicAnyString; OPENMPT_NAMESPACE_END + + + +template +struct mpt::make_string_type> { + using type = mpt::ustring; +}; + +template <> +struct mpt::make_string_type { + using type = mpt::ustring; +}; diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h b/Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h index 4724b99ad..e2044a858 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h @@ -180,7 +180,7 @@ template struct modecharbuf { public: - typedef char Tchar; + using Tchar = char; using char_type = Tchar; using string_type = std::basic_string; public: @@ -297,3 +297,26 @@ namespace String OPENMPT_NAMESPACE_END + + + +template +struct mpt::make_string_type> { + using type = std::basic_string::type>; +}; + +template +struct mpt::make_string_view_type> { + using type = std::basic_string_view::type>; +}; + + +template +struct mpt::make_string_type> { + using type = std::string; +}; + +template +struct mpt::make_string_view_type> { + using type = std::string_view; +}; diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp index 189b777fd..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp @@ -1,143 +0,0 @@ -/* - * mptStringFormat.cpp - * ------------------- - * Purpose: Convert other types to strings. - * Notes : Currently none. - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#include "stdafx.h" -#include "mptStringFormat.h" - -#include "mpt/format/default_floatingpoint.hpp" -#include "mpt/format/default_integer.hpp" -#include "mpt/format/helpers.hpp" -#include "mpt/format/simple_floatingpoint.hpp" -#include "mpt/format/simple_integer.hpp" - - -OPENMPT_NAMESPACE_BEGIN - - -namespace mpt -{ - - - -std::string ToAString(const bool & x) { return mpt::format_value_default(x); } -std::string ToAString(const signed char & x) { return mpt::format_value_default(x); } -std::string ToAString(const unsigned char & x) { return mpt::format_value_default(x); } -std::string ToAString(const signed short & x) { return mpt::format_value_default(x); } -std::string ToAString(const unsigned short & x) { return mpt::format_value_default(x); } -std::string ToAString(const signed int & x) { return mpt::format_value_default(x); } -std::string ToAString(const unsigned int & x) { return mpt::format_value_default(x); } -std::string ToAString(const signed long & x) { return mpt::format_value_default(x); } -std::string ToAString(const unsigned long & x) { return mpt::format_value_default(x); } -std::string ToAString(const signed long long & x) { return mpt::format_value_default(x); } -std::string ToAString(const unsigned long long & x) { return mpt::format_value_default(x); } -std::string ToAString(const float & x) { return mpt::format_value_default(x); } -std::string ToAString(const double & x) { return mpt::format_value_default(x); } -std::string ToAString(const long double & x) { return mpt::format_value_default(x); } - -#if MPT_WSTRING_FORMAT -#if MPT_USTRING_MODE_UTF8 -mpt::ustring ToUString(const std::wstring & x) { return mpt::ToUnicode(x); } -#endif -mpt::ustring ToUString(const wchar_t * const & x) { return mpt::ToUnicode(x); } -#endif -#if defined(MPT_WITH_MFC) -mpt::ustring ToUString(const CString & x) { return mpt::ToUnicode(x); } -#endif // MPT_WITH_MFC -mpt::ustring ToUString(const bool & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const signed char & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const unsigned char & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const signed short & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const unsigned short & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const signed int & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const unsigned int & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const signed long & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const unsigned long & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const signed long long & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const unsigned long long & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const float & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const double & x) { return mpt::format_value_default(x); } -mpt::ustring ToUString(const long double & x) { return mpt::format_value_default(x); } - -#if MPT_WSTRING_FORMAT -#if MPT_USTRING_MODE_UTF8 -std::wstring ToWString(const mpt::ustring & x) { return mpt::ToWide(x); } -#endif -#if defined(MPT_WITH_MFC) -std::wstring ToWString(const CString & x) { return mpt::ToWide(x); } -#endif // MPT_WITH_MFC -std::wstring ToWString(const bool & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const signed char & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const unsigned char & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const signed short & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const unsigned short & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const signed int & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const unsigned int & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const signed long & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const unsigned long & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const signed long long & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const unsigned long long & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const float & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const double & x) { return mpt::format_value_default(x); } -std::wstring ToWString(const long double & x) { return mpt::format_value_default(x); } -#endif - - - -std::string FormatValA(const bool & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const signed char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const signed short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const signed int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const signed long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const signed long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const float & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::string FormatValA(const long double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } - -mpt::ustring FormatValU(const bool & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const signed char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const signed short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const signed int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const signed long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const float & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -mpt::ustring FormatValU(const long double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } - -#if MPT_WSTRING_FORMAT -std::wstring FormatValW(const bool & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const signed char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const signed short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const signed int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const signed long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const signed long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const float & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -std::wstring FormatValW(const long double & x, const FormatSpec & f) { return mpt::format_simple(x, f); } -#endif - - -} // namespace mpt - - -OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h b/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h index 27a7dbc65..bb1a3a9c4 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h @@ -12,19 +12,21 @@ #include "openmpt/all/BuildSettings.hpp" -#include "mpt/base/pointer.hpp" +#include "mpt/base/detect.hpp" +#include "mpt/endian/integer.hpp" +#include "mpt/format/default_formatter.hpp" #include "mpt/format/message.hpp" +#include "mpt/format/message_macros.hpp" +#include "mpt/format/simple.hpp" #include "mpt/format/simple_spec.hpp" #include "mpt/string/types.hpp" - -#include - -#include "mptString.h" +#include "mpt/string_transcode/transcode.hpp" #include "openmpt/base/FlagSet.hpp" +#include "mptString.h" -OPENMPT_NAMESPACE_BEGIN +#include @@ -66,431 +68,86 @@ OPENMPT_NAMESPACE_BEGIN // almost all these copies. This should not be a problem for any decent modern compiler (and even less so for a c++11 compiler where // move-semantics will kick in if RVO/NRVO fails). + + +namespace mpt { +inline namespace MPT_INLINE_NS { +template +inline auto format_value_default(const mpt::packed & x) -> decltype(mpt::default_formatter::format(x)) { + return mpt::default_formatter::format(x); +} +} // namespace MPT_INLINE_NS +} // namespace mpt + + +OPENMPT_NAMESPACE_BEGIN + + +template +inline auto format_value_default(const T & x) -> decltype(mpt::transcode(x.ToUString())) { + return mpt::transcode(x.ToUString()); +} + + +template +inline auto format_value_default(const T & x) -> decltype(mpt::transcode(ToUString(x))) { + return mpt::transcode(ToUString(x)); +} + + namespace mpt { -// ToUString() converts various built-in types to a well-defined, locale-independent string representation. -// This is also used as a type-tunnel pattern for mpt::format. -// Custom types that need to be converted to strings are encouraged to overload ToUString(). -// fallback to member function ToUString() -#if MPT_USTRING_MODE_UTF8 -template [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding -#else -#if defined(MPT_ENABLE_CHARSET_LOCALE) -template [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::Locale, x.ToUString())) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUString()); } // unknown encoding -#else // !MPT_ENABLE_CHARSET_LOCALE -template [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding -#endif // MPT_ENABLE_CHARSET_LOCALE -#endif - -inline std::string ToAString(const std::string & x) { return x; } -inline std::string ToAString(const char * const & x) { return x; } -std::string ToAString(const char &x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -#if MPT_WSTRING_FORMAT -std::string ToAString(const std::wstring & x) = delete; // Unknown encoding. -std::string ToAString(const wchar_t * const & x) = delete; // Unknown encoding. -std::string ToAString(const wchar_t &x ) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#endif -#if MPT_USTRING_MODE_UTF8 -std::string ToAString(const mpt::ustring & x) = delete; // Unknown encoding. -#endif -#if defined(MPT_WITH_MFC) -std::string ToAString(const CString & x) = delete; // unknown encoding -#endif // MPT_WITH_MFC -std::string ToAString(const bool & x); -std::string ToAString(const signed char & x); -std::string ToAString(const unsigned char & x); -std::string ToAString(const signed short & x); -std::string ToAString(const unsigned short & x); -std::string ToAString(const signed int & x); -std::string ToAString(const unsigned int & x); -std::string ToAString(const signed long & x); -std::string ToAString(const unsigned long & x); -std::string ToAString(const signed long long & x); -std::string ToAString(const unsigned long long & x); -std::string ToAString(const float & x); -std::string ToAString(const double & x); -std::string ToAString(const long double & x); - -// fallback to member function ToUString() -template auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); } - -inline mpt::ustring ToUString(const mpt::ustring & x) { return x; } -mpt::ustring ToUString(const std::string & x) = delete; // Unknown encoding. -mpt::ustring ToUString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case. -mpt::ustring ToUString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -#if MPT_WSTRING_FORMAT -#if MPT_USTRING_MODE_UTF8 -mpt::ustring ToUString(const std::wstring & x); -#endif -mpt::ustring ToUString(const wchar_t * const & x); -mpt::ustring ToUString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#endif -#if defined(MPT_WITH_MFC) -mpt::ustring ToUString(const CString & x); -#endif // MPT_WITH_MFC -mpt::ustring ToUString(const bool & x); -mpt::ustring ToUString(const signed char & x); -mpt::ustring ToUString(const unsigned char & x); -mpt::ustring ToUString(const signed short & x); -mpt::ustring ToUString(const unsigned short & x); -mpt::ustring ToUString(const signed int & x); -mpt::ustring ToUString(const unsigned int & x); -mpt::ustring ToUString(const signed long & x); -mpt::ustring ToUString(const unsigned long & x); -mpt::ustring ToUString(const signed long long & x); -mpt::ustring ToUString(const unsigned long long & x); -mpt::ustring ToUString(const float & x); -mpt::ustring ToUString(const double & x); -mpt::ustring ToUString(const long double & x); - -#if MPT_WSTRING_FORMAT -std::wstring ToWString(const std::string & x) = delete; // Unknown encoding. -std::wstring ToWString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case. -std::wstring ToWString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -inline std::wstring ToWString(const std::wstring & x) { return x; } -inline std::wstring ToWString(const wchar_t * const & x) { return x; } -std::wstring ToWString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#if MPT_USTRING_MODE_UTF8 -std::wstring ToWString(const mpt::ustring & x); -#endif -#if defined(MPT_WITH_MFC) -std::wstring ToWString(const CString & x); -#endif // MPT_WITH_MFC -std::wstring ToWString(const bool & x); -std::wstring ToWString(const signed char & x); -std::wstring ToWString(const unsigned char & x); -std::wstring ToWString(const signed short & x); -std::wstring ToWString(const unsigned short & x); -std::wstring ToWString(const signed int & x); -std::wstring ToWString(const unsigned int & x); -std::wstring ToWString(const signed long & x); -std::wstring ToWString(const unsigned long & x); -std::wstring ToWString(const signed long long & x); -std::wstring ToWString(const unsigned long long & x); -std::wstring ToWString(const float & x); -std::wstring ToWString(const double & x); -std::wstring ToWString(const long double & x); -// fallback to member function ToUString() -template auto ToWString(const T & x) -> decltype(mpt::ToWide(x.ToUString())) { return mpt::ToWide(x.ToUString()); } -#endif - -#if defined(MPT_ENABLE_CHARSET_LOCALE) -template struct ToLocaleHelper { mpt::lstring operator () (const T & v) { return mpt::ToLocale(ToUString(v)); } }; -template <> struct ToLocaleHelper { mpt::lstring operator () (const mpt::lstring & v) { return v; } }; -#endif // MPT_ENABLE_CHARSET_LOCALE - -#if defined(MPT_WITH_MFC) -template struct ToCStringHelper { CString operator () (const T & v) { return mpt::ToCString(ToUString(v)); } }; -template <> struct ToCStringHelper { CString operator () (const CString & v) { return v; } }; -#endif // MPT_WITH_MFC - -template struct ToStringTFunctor {}; -template <> struct ToStringTFunctor { template inline std::string operator() (const T & x) { return ToAString(x); } }; -template <> struct ToStringTFunctor { template inline mpt::ustring operator() (const T & x) { return ToUString(x); } }; -#if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8 -template <> struct ToStringTFunctor { template inline std::wstring operator() (const T & x) { return ToWString(x); } }; -#endif -#if defined(MPT_ENABLE_CHARSET_LOCALE) -template <> struct ToStringTFunctor { template inline mpt::lstring operator() (const T & x) { return mpt::ToLocaleHelper()(x); } }; -#endif // MPT_ENABLE_CHARSET_LOCALE -#if defined(MPT_WITH_MFC) -template <> struct ToStringTFunctor { template inline CString operator() (const T & x) { return mpt::ToCStringHelper()(x); } }; -#endif // MPT_WITH_MFC - -template inline Tstring ToStringT(const T & x) { return ToStringTFunctor()(x); } +template +inline auto format_value_default(const T & x) -> decltype(mpt::transcode(x.ToUString())) { + return mpt::transcode(x.ToUString()); +} -struct ToStringFormatter { - template - static inline Tstring format(const T& value) { - return ToStringTFunctor()(value); - - } -}; - - -using FormatSpec = mpt::format_simple_spec; - -using FormatFlags = mpt::format_simple_flags; - -using fmt_base = mpt::format_simple_base; - - -std::string FormatValA(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) -std::string FormatValA(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#endif // !MPT_COMPILER_QUIRK_NO_WCHAR -std::string FormatValA(const bool & x, const FormatSpec & f); -std::string FormatValA(const signed char & x, const FormatSpec & f); -std::string FormatValA(const unsigned char & x, const FormatSpec & f); -std::string FormatValA(const signed short & x, const FormatSpec & f); -std::string FormatValA(const unsigned short & x, const FormatSpec & f); -std::string FormatValA(const signed int & x, const FormatSpec & f); -std::string FormatValA(const unsigned int & x, const FormatSpec & f); -std::string FormatValA(const signed long & x, const FormatSpec & f); -std::string FormatValA(const unsigned long & x, const FormatSpec & f); -std::string FormatValA(const signed long long & x, const FormatSpec & f); -std::string FormatValA(const unsigned long long & x, const FormatSpec & f); -std::string FormatValA(const float & x, const FormatSpec & f); -std::string FormatValA(const double & x, const FormatSpec & f); -std::string FormatValA(const long double & x, const FormatSpec & f); - -mpt::ustring FormatValU(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) -mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#endif // !MPT_COMPILER_QUIRK_NO_WCHAR -mpt::ustring FormatValU(const bool & x, const FormatSpec & f); -mpt::ustring FormatValU(const signed char & x, const FormatSpec & f); -mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f); -mpt::ustring FormatValU(const signed short & x, const FormatSpec & f); -mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f); -mpt::ustring FormatValU(const signed int & x, const FormatSpec & f); -mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f); -mpt::ustring FormatValU(const signed long & x, const FormatSpec & f); -mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f); -mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f); -mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f); -mpt::ustring FormatValU(const float & x, const FormatSpec & f); -mpt::ustring FormatValU(const double & x, const FormatSpec & f); -mpt::ustring FormatValU(const long double & x, const FormatSpec & f); - -#if MPT_WSTRING_FORMAT -std::wstring FormatValW(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead -#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) -std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead -#endif // !MPT_COMPILER_QUIRK_NO_WCHAR -std::wstring FormatValW(const bool & x, const FormatSpec & f); -std::wstring FormatValW(const signed char & x, const FormatSpec & f); -std::wstring FormatValW(const unsigned char & x, const FormatSpec & f); -std::wstring FormatValW(const signed short & x, const FormatSpec & f); -std::wstring FormatValW(const unsigned short & x, const FormatSpec & f); -std::wstring FormatValW(const signed int & x, const FormatSpec & f); -std::wstring FormatValW(const unsigned int & x, const FormatSpec & f); -std::wstring FormatValW(const signed long & x, const FormatSpec & f); -std::wstring FormatValW(const unsigned long & x, const FormatSpec & f); -std::wstring FormatValW(const signed long long & x, const FormatSpec & f); -std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f); -std::wstring FormatValW(const float & x, const FormatSpec & f); -std::wstring FormatValW(const double & x, const FormatSpec & f); -std::wstring FormatValW(const long double & x, const FormatSpec & f); -#endif - -template struct FormatValTFunctor {}; -template <> struct FormatValTFunctor { template inline std::string operator() (const T & x, const FormatSpec & f) { return FormatValA(x, f); } }; -template <> struct FormatValTFunctor { template inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return FormatValU(x, f); } }; -#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_FORMAT -template <> struct FormatValTFunctor { template inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } }; -#endif -#if defined(MPT_ENABLE_CHARSET_LOCALE) -template <> struct FormatValTFunctor { template inline mpt::lstring operator() (const T & x, const FormatSpec & f) { return mpt::ToLocale(mpt::Charset::Locale, FormatValA(x, f)); } }; -#endif // MPT_ENABLE_CHARSET_LOCALE -#if defined(MPT_WITH_MFC) -#ifdef UNICODE -template <> struct FormatValTFunctor { template inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } }; -#else // !UNICODE -template <> struct FormatValTFunctor { template inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(mpt::Charset::Locale, FormatValA(x, f)); } }; -#endif // UNICODE -#endif // MPT_WITH_MFC +template +inline auto format_value_default(const T & x) -> decltype(mpt::transcode(ToUString(x))) { + return mpt::transcode(ToUString(x)); +} template -struct fmtT : fmt_base -{ +using fmtT = mpt::format; -template -static inline Tstring val(const T& x) -{ - return ToStringTFunctor()(x); -} - -template -static inline Tstring fmt(const T& x, const FormatSpec& f) -{ - return FormatValTFunctor()(x, f); -} - -template -static inline Tstring dec(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseDec().FillOff()); -} -template -static inline Tstring dec0(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseDec().FillNul().Width(width)); -} - -template -static inline Tstring dec(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseDec().FillOff().Group(g).GroupSep(s)); -} -template -static inline Tstring dec0(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s)); -} - -template -static inline Tstring hex(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillOff()); -} -template -static inline Tstring HEX(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillOff()); -} -template -static inline Tstring hex0(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width)); -} -template -static inline Tstring HEX0(const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width)); -} - -template -static inline Tstring hex(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s)); -} -template -static inline Tstring HEX(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s)); -} -template -static inline Tstring hex0(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s)); -} -template -static inline Tstring HEX0(unsigned int g, char s, const T& x) -{ - static_assert(std::numeric_limits::is_integer); - return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s)); -} - -template -static inline Tstring flt(const T& x, int precision = -1) -{ - static_assert(std::is_floating_point::value); - return FormatValTFunctor()(x, FormatSpec().NotaNrm().FillOff().Precision(precision)); -} -template -static inline Tstring fix(const T& x, int precision = -1) -{ - static_assert(std::is_floating_point::value); - return FormatValTFunctor()(x, FormatSpec().NotaFix().FillOff().Precision(precision)); -} -template -static inline Tstring sci(const T& x, int precision = -1) -{ - static_assert(std::is_floating_point::value); - return FormatValTFunctor()(x, FormatSpec().NotaSci().FillOff().Precision(precision)); -} - -template -static inline Tstring ptr(const T& x) -{ - static_assert(std::is_pointer::value || std::is_same::value || std::is_same::value, ""); - return hex0(mpt::pointer_cast(x)); -} -template -static inline Tstring PTR(const T& x) -{ - static_assert(std::is_pointer::value || std::is_same::value || std::is_same::value, ""); - return HEX0(mpt::pointer_cast(x)); -} - -static inline Tstring pad_left(std::size_t width_, const Tstring &str) -{ - typedef mpt::string_traits traits; - typename traits::size_type width = static_cast(width_); - return traits::pad(str, width, 0); -} -static inline Tstring pad_right(std::size_t width_, const Tstring &str) -{ - typedef mpt::string_traits traits; - typename traits::size_type width = static_cast(width_); - return traits::pad(str, 0, width); -} -static inline Tstring left(std::size_t width_, const Tstring &str) -{ - typedef mpt::string_traits traits; - typename traits::size_type width = static_cast(width_); - return (traits::length(str) < width) ? traits::pad(str, 0, width - traits::length(str)) : str; -} -static inline Tstring right(std::size_t width_, const Tstring &str) -{ - typedef mpt::string_traits traits; - typename traits::size_type width = static_cast(width_); - return (traits::length(str) < width) ? traits::pad(str, width - traits::length(str), 0) : str; -} -static inline Tstring center(std::size_t width_, const Tstring &str) -{ - typedef mpt::string_traits traits; - typename traits::size_type width = static_cast(width_); - return (traits::length(str) < width) ? traits::pad(str, (width - traits::length(str)) / 2, (width - traits::length(str) + 1) / 2) : str; -} - -}; // struct fmtT - - -typedef fmtT afmt; -#if MPT_WSTRING_FORMAT -typedef fmtT wfmt; -#endif -#if MPT_USTRING_MODE_WIDE -typedef fmtT ufmt; -#else -typedef fmtT ufmt; +using afmt = fmtT; +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +using wfmt = fmtT; #endif +using ufmt = fmtT; #if defined(MPT_ENABLE_CHARSET_LOCALE) -typedef fmtT lfmt; +using lfmt = fmtT; #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS -typedef fmtT tfmt; +using tfmt = fmtT; #endif #if defined(MPT_WITH_MFC) -typedef fmtT cfmt; +using cfmt = fmtT; #endif // MPT_WITH_MFC -#define MPT_AFORMAT(f) mpt::format_message(f) +#define MPT_AFORMAT(f) MPT_AFORMAT_MESSAGE(f) -#if MPT_WSTRING_FORMAT -#define MPT_WFORMAT(f) mpt::format_message_typed( L ## f ) +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +#define MPT_WFORMAT(f) MPT_WFORMAT_MESSAGE(f) #endif -#define MPT_UFORMAT(f) mpt::format_message_typed(MPT_ULITERAL(f)) +#define MPT_UFORMAT(f) MPT_UFORMAT_MESSAGE(f) #if defined(MPT_ENABLE_CHARSET_LOCALE) -#define MPT_LFORMAT(f) mpt::format_message_typed(f) +#define MPT_LFORMAT(f) MPT_LFORMAT_MESSAGE(f) #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS -#define MPT_TFORMAT(f) mpt::format_message_typed(TEXT(f)) -#endif +#define MPT_TFORMAT(f) MPT_TFORMAT_MESSAGE(f) +#endif // MPT_OS_WINDOWS #if defined(MPT_WITH_MFC) -#define MPT_CFORMAT(f) mpt::format_message_typed(TEXT(f)) +#define MPT_CFORMAT(f) MPT_CFORMAT_MESSAGE(f) #endif // MPT_WITH_MFC @@ -498,43 +155,6 @@ typedef fmtT cfmt; -namespace mpt { namespace String { - -// Combine a vector of values into a string, separated with the given separator. -// No escaping is performed. -template -mpt::ustring Combine(const std::vector &vals, const mpt::ustring &sep=U_(",")) -{ - mpt::ustring str; - for(std::size_t i = 0; i < vals.size(); ++i) - { - if(i > 0) - { - str += sep; - } - str += mpt::ufmt::val(vals[i]); - } - return str; -} -template -std::string Combine(const std::vector &vals, const std::string &sep=std::string(",")) -{ - std::string str; - for(std::size_t i = 0; i < vals.size(); ++i) - { - if(i > 0) - { - str += sep; - } - str += mpt::afmt::val(vals[i]); - } - return str; -} - -} } // namespace mpt::String - - - template mpt::ustring ToUString(FlagSet flagset) { @@ -550,5 +170,4 @@ mpt::ustring ToUString(FlagSet flagset) - OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp index a4306f32e..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp @@ -1,98 +0,0 @@ -/* - * mptStringParse.cpp - * ------------------ - * Purpose: Convert strings to other types. - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - - -#include "stdafx.h" -#include "mptStringParse.h" - -#include "mpt/parse/parse.hpp" - - -OPENMPT_NAMESPACE_BEGIN - - -template -inline T ConvertStrToHelper(const std::string &str) -{ - return mpt::ConvertStringTo(str); -} -template<> inline bool ConvertStrToHelper(const std::string &str) { return ConvertStrToHelper(str)?true:false; } -template<> inline signed char ConvertStrToHelper(const std::string &str) { return static_cast(ConvertStrToHelper(str)); } -template<> inline unsigned char ConvertStrToHelper(const std::string &str) { return static_cast(ConvertStrToHelper(str)); } - -#if MPT_WSTRING_FORMAT -template -inline T ConvertStrToHelper(const std::wstring &str) -{ - return mpt::ConvertStringTo(str); -} -template<> inline bool ConvertStrToHelper(const std::wstring &str) { return ConvertStrToHelper(str)?true:false; } -template<> inline signed char ConvertStrToHelper(const std::wstring &str) { return static_cast(ConvertStrToHelper(str)); } -template<> inline unsigned char ConvertStrToHelper(const std::wstring &str) { return static_cast(ConvertStrToHelper(str)); } -#endif - -bool ConvertStrToBool(const std::string &str) { return ConvertStrToHelper(str); } -signed char ConvertStrToSignedChar(const std::string &str) { return ConvertStrToHelper(str); } -unsigned char ConvertStrToUnsignedChar(const std::string &str) { return ConvertStrToHelper(str); } -signed short ConvertStrToSignedShort(const std::string &str) { return ConvertStrToHelper(str); } -unsigned short ConvertStrToUnsignedShort(const std::string &str) { return ConvertStrToHelper(str); } -signed int ConvertStrToSignedInt(const std::string &str) { return ConvertStrToHelper(str); } -unsigned int ConvertStrToUnsignedInt(const std::string &str) { return ConvertStrToHelper(str); } -signed long ConvertStrToSignedLong(const std::string &str) { return ConvertStrToHelper(str); } -unsigned long ConvertStrToUnsignedLong(const std::string &str) { return ConvertStrToHelper(str); } -signed long long ConvertStrToSignedLongLong(const std::string &str) { return ConvertStrToHelper(str); } -unsigned long long ConvertStrToUnsignedLongLong(const std::string &str) { return ConvertStrToHelper(str); } -float ConvertStrToFloat(const std::string &str) { return ConvertStrToHelper(str); } -double ConvertStrToDouble(const std::string &str) { return ConvertStrToHelper(str); } -long double ConvertStrToLongDouble(const std::string &str) { return ConvertStrToHelper(str); } - -#if MPT_WSTRING_FORMAT -bool ConvertStrToBool(const std::wstring &str) { return ConvertStrToHelper(str); } -signed char ConvertStrToSignedChar(const std::wstring &str) { return ConvertStrToHelper(str); } -unsigned char ConvertStrToUnsignedChar(const std::wstring &str) { return ConvertStrToHelper(str); } -signed short ConvertStrToSignedShort(const std::wstring &str) { return ConvertStrToHelper(str); } -unsigned short ConvertStrToUnsignedShort(const std::wstring &str) { return ConvertStrToHelper(str); } -signed int ConvertStrToSignedInt(const std::wstring &str) { return ConvertStrToHelper(str); } -unsigned int ConvertStrToUnsignedInt(const std::wstring &str) { return ConvertStrToHelper(str); } -signed long ConvertStrToSignedLong(const std::wstring &str) { return ConvertStrToHelper(str); } -unsigned long ConvertStrToUnsignedLong(const std::wstring &str) { return ConvertStrToHelper(str); } -signed long long ConvertStrToSignedLongLong(const std::wstring &str) { return ConvertStrToHelper(str); } -unsigned long long ConvertStrToUnsignedLongLong(const std::wstring &str) { return ConvertStrToHelper(str); } -float ConvertStrToFloat(const std::wstring &str) { return ConvertStrToHelper(str); } -double ConvertStrToDouble(const std::wstring &str) { return ConvertStrToHelper(str); } -long double ConvertStrToLongDouble(const std::wstring &str) { return ConvertStrToHelper(str); } -#endif - - -namespace mpt -{ -namespace String -{ -namespace Parse -{ - -template -T HexToHelper(const std::string &str) -{ - return mpt::ConvertHexStringTo(str); -} -template<> unsigned char HexToHelper(const std::string &str) { return static_cast(HexToHelper(str)); } - -unsigned char HexToUnsignedChar(const std::string &str) { return HexToHelper(str); } -unsigned short HexToUnsignedShort(const std::string &str) { return HexToHelper(str); } -unsigned int HexToUnsignedInt(const std::string &str) { return HexToHelper(str); } -unsigned long HexToUnsignedLong(const std::string &str) { return HexToHelper(str); } -unsigned long long HexToUnsignedLongLong(const std::string &str) { return HexToHelper(str); } - -} // namespace Parse -} // namespace String -} // namespace mpt - - -OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h b/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h index 9e7fbd0a4..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h @@ -1,250 +0,0 @@ -/* - * mptStringParse.h - * ---------------- - * Purpose: Convert strings to other types. - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - - -#pragma once - -#include "openmpt/all/BuildSettings.hpp" - - -OPENMPT_NAMESPACE_BEGIN - - -bool ConvertStrToBool(const std::string &str); -signed char ConvertStrToSignedChar(const std::string &str); -unsigned char ConvertStrToUnsignedChar(const std::string &str); -signed short ConvertStrToSignedShort(const std::string &str); -unsigned short ConvertStrToUnsignedShort(const std::string &str); -signed int ConvertStrToSignedInt(const std::string &str); -unsigned int ConvertStrToUnsignedInt(const std::string &str); -signed long ConvertStrToSignedLong(const std::string &str); -unsigned long ConvertStrToUnsignedLong(const std::string &str); -signed long long ConvertStrToSignedLongLong(const std::string &str); -unsigned long long ConvertStrToUnsignedLongLong(const std::string &str); -float ConvertStrToFloat(const std::string &str); -double ConvertStrToDouble(const std::string &str); -long double ConvertStrToLongDouble(const std::string &str); -template inline T ConvertStrTo(const std::string &str); // not defined, generates compiler error for non-specialized types -template<> inline std::string ConvertStrTo(const std::string &str) { return str; } -template<> inline bool ConvertStrTo(const std::string &str) { return ConvertStrToBool(str); } -template<> inline signed char ConvertStrTo(const std::string &str) { return ConvertStrToSignedChar(str); } -template<> inline unsigned char ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedChar(str); } -template<> inline signed short ConvertStrTo(const std::string &str) { return ConvertStrToSignedShort(str); } -template<> inline unsigned short ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedShort(str); } -template<> inline signed int ConvertStrTo(const std::string &str) { return ConvertStrToSignedInt(str); } -template<> inline unsigned int ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedInt(str); } -template<> inline signed long ConvertStrTo(const std::string &str) { return ConvertStrToSignedLong(str); } -template<> inline unsigned long ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedLong(str); } -template<> inline signed long long ConvertStrTo(const std::string &str) { return ConvertStrToSignedLongLong(str); } -template<> inline unsigned long long ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedLongLong(str); } -template<> inline float ConvertStrTo(const std::string &str) { return ConvertStrToFloat(str); } -template<> inline double ConvertStrTo(const std::string &str) { return ConvertStrToDouble(str); } -template<> inline long double ConvertStrTo(const std::string &str) { return ConvertStrToLongDouble(str); } - -#if MPT_WSTRING_FORMAT -bool ConvertStrToBool(const std::wstring &str); -signed char ConvertStrToSignedChar(const std::wstring &str); -unsigned char ConvertStrToUnsignedChar(const std::wstring &str); -signed short ConvertStrToSignedShort(const std::wstring &str); -unsigned short ConvertStrToUnsignedShort(const std::wstring &str); -signed int ConvertStrToSignedInt(const std::wstring &str); -unsigned int ConvertStrToUnsignedInt(const std::wstring &str); -signed long ConvertStrToSignedLong(const std::wstring &str); -unsigned long ConvertStrToUnsignedLong(const std::wstring &str); -signed long long ConvertStrToSignedLongLong(const std::wstring &str); -unsigned long long ConvertStrToUnsignedLongLong(const std::wstring &str); -float ConvertStrToFloat(const std::wstring &str); -double ConvertStrToDouble(const std::wstring &str); -long double ConvertStrToLongDouble(const std::wstring &str); -template inline T ConvertStrTo(const std::wstring &str); // not defined, generates compiler error for non-specialized types -template<> inline std::wstring ConvertStrTo(const std::wstring &str) { return str; } -template<> inline bool ConvertStrTo(const std::wstring &str) { return ConvertStrToBool(str); } -template<> inline signed char ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedChar(str); } -template<> inline unsigned char ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedChar(str); } -template<> inline signed short ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedShort(str); } -template<> inline unsigned short ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedShort(str); } -template<> inline signed int ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedInt(str); } -template<> inline unsigned int ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedInt(str); } -template<> inline signed long ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedLong(str); } -template<> inline unsigned long ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedLong(str); } -template<> inline signed long long ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedLongLong(str); } -template<> inline unsigned long long ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedLongLong(str); } -template<> inline float ConvertStrTo(const std::wstring &str) { return ConvertStrToFloat(str); } -template<> inline double ConvertStrTo(const std::wstring &str) { return ConvertStrToDouble(str); } -template<> inline long double ConvertStrTo(const std::wstring &str) { return ConvertStrToLongDouble(str); } -#endif - -#if defined(MPT_WITH_MFC) -template -inline T ConvertStrTo(const CString &str) -{ - #if defined(UNICODE) && MPT_WSTRING_FORMAT - return ConvertStrTo(mpt::ToWide(str)); - #elif defined(UNICODE) - return ConvertStrTo(mpt::ToCharset(mpt::Charset::UTF8, str)); - #else // !UNICODE - return ConvertStrTo(mpt::ToCharset(mpt::Charset::Locale, str)); - #endif // UNICODE -} -#endif // MPT_WITH_MFC - -template -inline T ConvertStrTo(const char *str) -{ - if(!str) - { - return T(); - } - return ConvertStrTo(std::string(str)); -} - -#if MPT_WSTRING_FORMAT -#if MPT_USTRING_MODE_UTF8 -template<> inline mpt::ustring ConvertStrTo(const std::wstring &str) { return mpt::ToUnicode(str); } -#endif -template -inline T ConvertStrTo(const wchar_t *str) -{ - if(!str) - { - return T(); - } - return ConvertStrTo(std::wstring(str)); -} -#endif - -#if MPT_USTRING_MODE_UTF8 -template -inline T ConvertStrTo(const mpt::ustring &str) -{ - return ConvertStrTo(mpt::ToCharset(mpt::Charset::UTF8, str)); -} -template<> inline mpt::ustring ConvertStrTo(const mpt::ustring &str) { return str; } -#if MPT_WSTRING_CONVERT -template<> inline std::wstring ConvertStrTo(const mpt::ustring &str) { return mpt::ToWide(str); } -#endif -#endif - -#if defined(MPT_ENABLE_CHARSET_LOCALE) -template -inline T ConvertStrTo(const mpt::lstring &str) -{ - return ConvertStrTo(mpt::ToCharset(mpt::Charset::Locale, str)); -} -template<> inline mpt::lstring ConvertStrTo(const mpt::lstring &str) { return str; } -#endif - - -namespace mpt -{ -namespace String -{ -namespace Parse -{ - -unsigned char HexToUnsignedChar(const std::string &str); -unsigned short HexToUnsignedShort(const std::string &str); -unsigned int HexToUnsignedInt(const std::string &str); -unsigned long HexToUnsignedLong(const std::string &str); -unsigned long long HexToUnsignedLongLong(const std::string &str); - -template inline T Hex(const std::string &str); // not defined, generates compiler error for non-specialized types -template<> inline unsigned char Hex(const std::string &str) { return HexToUnsignedChar(str); } -template<> inline unsigned short Hex(const std::string &str) { return HexToUnsignedShort(str); } -template<> inline unsigned int Hex(const std::string &str) { return HexToUnsignedInt(str); } -template<> inline unsigned long Hex(const std::string &str) { return HexToUnsignedLong(str); } -template<> inline unsigned long long Hex(const std::string &str) { return HexToUnsignedLongLong(str); } - -template -inline T Hex(const char *str) -{ - if(!str) - { - return T(); - } - return Hex(std::string(str)); -} - -#if MPT_WSTRING_FORMAT - -template -inline T Hex(const std::wstring &str) -{ - return Hex(mpt::ToCharset(mpt::Charset::UTF8, str)); -} - -template -inline T Hex(const wchar_t *str) -{ - if(!str) - { - return T(); - } - return Hex(std::wstring(str)); -} - -#endif - -#if MPT_USTRING_MODE_UTF8 -template -inline T Hex(const mpt::ustring &str) -{ - return Hex(mpt::ToCharset(mpt::Charset::UTF8, str)); -} -#endif - -} // namespace Parse -} // namespace String -} // namespace mpt - - - -namespace mpt { namespace String { - -// Split the given string at separator positions into individual values returned as a vector. -// An empty string results in an empty vector. -// Leading or trailing separators result in a default-constructed element being inserted before or after the other elements. -template -std::vector Split(const mpt::ustring &str, const mpt::ustring &sep=U_(",")) -{ - std::vector vals; - std::size_t pos = 0; - while(str.find(sep, pos) != std::string::npos) - { - vals.push_back(ConvertStrTo(str.substr(pos, str.find(sep, pos) - pos))); - pos = str.find(sep, pos) + sep.length(); - } - if(!vals.empty() || (str.substr(pos).length() > 0)) - { - vals.push_back(ConvertStrTo(str.substr(pos))); - } - return vals; -} -template -std::vector Split(const std::string &str, const std::string &sep=std::string(",")) -{ - std::vector vals; - std::size_t pos = 0; - while(str.find(sep, pos) != std::string::npos) - { - vals.push_back(ConvertStrTo(str.substr(pos, str.find(sep, pos) - pos))); - pos = str.find(sep, pos) + sep.length(); - } - if(!vals.empty() || (str.substr(pos).length() > 0)) - { - vals.push_back(ConvertStrTo(str.substr(pos))); - } - return vals; -} - -} } // namespace mpt::String - - - -OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp b/Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp index 70874d16f..40e3da50c 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp @@ -11,9 +11,19 @@ #include "stdafx.h" #include "mptTime.h" +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS +#include "mpt/osinfo/windows_wine_version.hpp" +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS + #include "mptStringBuffer.h" -#include +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) +#include +#endif + +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS +#include +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS #if MPT_OS_WINDOWS #include @@ -81,22 +91,8 @@ mpt::ustring ToUString(uint64 time100ns) #endif // MODPLUG_TRACKER -Unix::Unix() - : Value(0) +namespace nochrono { - return; -} - -Unix::Unix(int64 unixtime) - : Value(unixtime) -{ - return; -} - -Unix::operator int64 () const -{ - return Value; -} static int32 ToDaynum(int32 year, int32 month, int32 day) { @@ -128,81 +124,270 @@ static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day) day = static_cast(dd); } -mpt::Date::Unix Unix::FromUTC(tm timeUtc) +Unix UnixFromUTC(UTC timeUtc) { - int32 daynum = ToDaynum(timeUtc.tm_year+1900, timeUtc.tm_mon+1, timeUtc.tm_mday); - int64 seconds = static_cast(daynum - ToDaynum(1970,1,1))*24*60*60 + timeUtc.tm_hour*60*60 + timeUtc.tm_min*60 + timeUtc.tm_sec; - return mpt::Date::Unix(seconds); + int32 daynum = ToDaynum(timeUtc.year, timeUtc.month, timeUtc.day); + int64 seconds = static_cast(daynum - ToDaynum(1970, 1, 1)) * 24 * 60 * 60 + timeUtc.hours * 60 * 60 + timeUtc.minutes * 60 + timeUtc.seconds; + return Unix{seconds}; } -tm Unix::AsUTC() const +UTC UnixAsUTC(Unix tp) { - int64 tmp = Value; + int64 tmp = tp.value; int64 seconds = tmp % 60; tmp /= 60; int64 minutes = tmp % 60; tmp /= 60; int64 hours = tmp % 24; tmp /= 24; int32 year = 0, month = 0, day = 0; FromDaynum(static_cast(tmp) + ToDaynum(1970,1,1), year, month, day); - tm result = {}; - result.tm_year = year - 1900; - result.tm_mon = month - 1; - result.tm_mday = day; - result.tm_hour = static_cast(hours); - result.tm_min = static_cast(minutes); - result.tm_sec = static_cast(seconds); + UTC result = {}; + result.year = year; + result.month = month; + result.day = day; + result.hours = static_cast(hours); + result.minutes = static_cast(minutes); + result.seconds = seconds; return result; } -mpt::ustring ToShortenedISO8601(tm date) +#if defined(MODPLUG_TRACKER) + +struct tz_error +{ +}; + +Unix UnixFromLocal(Local timeLocal) +{ +#if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC) + try + { + if(mpt::osinfo::windows::current_is_wine()) + { + throw tz_error{}; + } + SYSTEMTIME sys_local{}; + sys_local.wYear = static_cast(timeLocal.year); + sys_local.wMonth = static_cast(timeLocal.month); + sys_local.wDay = static_cast(timeLocal.day); + sys_local.wHour = static_cast(timeLocal.hours); + sys_local.wMinute = static_cast(timeLocal.minutes); + sys_local.wSecond = static_cast(timeLocal.seconds); + sys_local.wMilliseconds = 0; + DYNAMIC_TIME_ZONE_INFORMATION dtzi{}; + if(GetDynamicTimeZoneInformation(&dtzi) == TIME_ZONE_ID_INVALID) // WinVista + { + throw tz_error{}; + } + SYSTEMTIME sys_utc{}; + if(TzSpecificLocalTimeToSystemTimeEx(&dtzi, &sys_local, &sys_utc) == FALSE) // Win7/Win8 + { + throw tz_error{}; + } + FILETIME ft{}; + if(SystemTimeToFileTime(&sys_utc, &ft) == FALSE) // Win 2000 + { + throw tz_error{}; + } + ULARGE_INTEGER time_value{}; + time_value.LowPart = ft.dwLowDateTime; + time_value.HighPart = ft.dwHighDateTime; + return UnixFromSeconds(static_cast((time_value.QuadPart - 116444736000000000LL) / 10000000LL)); + } catch(const tz_error &) + { + // nothing + } +#endif +#if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT) + try + { + SYSTEMTIME sys_local{}; + sys_local.wYear = static_cast(timeLocal.year); + sys_local.wMonth = static_cast(timeLocal.month); + sys_local.wDay = static_cast(timeLocal.day); + sys_local.wHour = static_cast(timeLocal.hours); + sys_local.wMinute = static_cast(timeLocal.minutes); + sys_local.wSecond = static_cast(timeLocal.seconds); + sys_local.wMilliseconds = 0; + SYSTEMTIME sys_utc{}; + if(TzSpecificLocalTimeToSystemTime(NULL, &sys_local, &sys_utc) == FALSE) // WinXP + { + throw tz_error{}; + } + FILETIME ft{}; + if(SystemTimeToFileTime(&sys_utc, &ft) == FALSE) // Win 2000 + { + throw tz_error{}; + } + ULARGE_INTEGER time_value{}; + time_value.LowPart = ft.dwLowDateTime; + time_value.HighPart = ft.dwHighDateTime; + return UnixFromSeconds(static_cast((time_value.QuadPart - 116444736000000000LL) / 10000000LL)); + } catch(const tz_error &) + { + // nothing + } +#endif +#if defined(MPT_FALLBACK_TIMEZONE_C) + std::tm tmp{}; + tmp.tm_year = timeLocal.year - 1900; + tmp.tm_mon = timeLocal.month - 1; + tmp.tm_mday = timeLocal.day; + tmp.tm_hour = timeLocal.hours; + tmp.tm_min = timeLocal.minutes; + tmp.tm_sec = static_cast(timeLocal.seconds); + return UnixFromSeconds(static_cast(std::mktime(&tmp))); +#endif +} + +Local UnixAsLocal(Unix tp) +{ +#if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC) + try + { + if(mpt::osinfo::windows::current_is_wine()) + { + throw tz_error{}; + } + ULARGE_INTEGER time_value{}; + time_value.QuadPart = static_cast(UnixAsSeconds(tp)) * 10000000LL + 116444736000000000LL; + FILETIME ft{}; + ft.dwLowDateTime = time_value.LowPart; + ft.dwHighDateTime = time_value.HighPart; + SYSTEMTIME sys_utc{}; + if(FileTimeToSystemTime(&ft, &sys_utc) == FALSE) // WinXP + { + throw tz_error{}; + } + DYNAMIC_TIME_ZONE_INFORMATION dtzi{}; + if(GetDynamicTimeZoneInformation(&dtzi) == TIME_ZONE_ID_INVALID) // WinVista + { + throw tz_error{}; + } + SYSTEMTIME sys_local{}; + if(SystemTimeToTzSpecificLocalTimeEx(&dtzi, &sys_utc, &sys_local) == FALSE) // Win7/Win8 + { + throw tz_error{}; + } + Local result{}; + result.year = sys_local.wYear; + result.month = sys_local.wMonth; + result.day = sys_local.wDay; + result.hours = sys_local.wHour; + result.minutes = sys_local.wMinute; + result.seconds = sys_local.wSecond; + return result; + } catch(const tz_error&) + { + // nothing + } +#endif +#if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT) + try + { + ULARGE_INTEGER time_value{}; + time_value.QuadPart = static_cast(UnixAsSeconds(tp)) * 10000000LL + 116444736000000000LL; + FILETIME ft{}; + ft.dwLowDateTime = time_value.LowPart; + ft.dwHighDateTime = time_value.HighPart; + SYSTEMTIME sys_utc{}; + if(FileTimeToSystemTime(&ft, &sys_utc) == FALSE) // WinXP + { + throw tz_error{}; + } + SYSTEMTIME sys_local{}; + if(SystemTimeToTzSpecificLocalTime(NULL, &sys_utc, &sys_local) == FALSE) // Win2000 + { + throw tz_error{}; + } + Local result{}; + result.year = sys_local.wYear; + result.month = sys_local.wMonth; + result.day = sys_local.wDay; + result.hours = sys_local.wHour; + result.minutes = sys_local.wMinute; + result.seconds = sys_local.wSecond; + return result; + } catch(const tz_error&) + { + // nothing + } +#endif +#if defined(MPT_FALLBACK_TIMEZONE_C) + std::time_t time_tp = static_cast(UnixAsSeconds(tp)); + std::tm *tmp = std::localtime(&time_tp); + if(!tmp) + { + return Local{}; + } + std::tm local = *tmp; + Local result{}; + result.year = local.tm_year + 1900; + result.month = local.tm_mon + 1; + result.day = local.tm_mday; + result.hours = local.tm_hour; + result.minutes = local.tm_min; + result.seconds = local.tm_sec; + return result; +#endif +} + +#endif // MODPLUG_TRACKER + +} // namespace nochrono + +template +static mpt::ustring ToShortenedISO8601Impl(mpt::Date::Gregorian date) { - // We assume date in UTC here. - // There are too many differences in supported format specifiers in strftime() - // and strftime does not support reduced precision ISO8601 at all. - // Just do the formatting ourselves. mpt::ustring result; - mpt::ustring tz = U_("Z"); - if(date.tm_year == 0) + mpt::ustring tz; + if constexpr(TZ == LogicalTimezone::Unspecified) + { + tz = U_(""); + } else if constexpr(TZ == LogicalTimezone::UTC) + { + tz = U_("Z"); + } else + { + tz = U_(""); + } + if(date.year == 0) { return result; } - result += mpt::ufmt::dec0<4>(date.tm_year + 1900); - if(date.tm_mon < 0 || date.tm_mon > 11) - { - return result; - } - result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mon + 1); - if(date.tm_mday < 1 || date.tm_mday > 31) - { - return result; - } - result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mday); - if(date.tm_hour == 0 && date.tm_min == 0 && date.tm_sec == 0) - { - return result; - } - if(date.tm_hour < 0 || date.tm_hour > 23) - { - return result; - } - if(date.tm_min < 0 || date.tm_min > 59) + result += mpt::ufmt::dec0<4>(date.year); + result += U_("-") + mpt::ufmt::dec0<2>(date.month); + result += U_("-") + mpt::ufmt::dec0<2>(date.day); + if(date.hours == 0 && date.minutes == 0 && date.seconds) { return result; } result += U_("T"); - if(date.tm_isdst > 0) - { - tz = U_("+01:00"); - } - result += mpt::ufmt::dec0<2>(date.tm_hour) + U_(":") + mpt::ufmt::dec0<2>(date.tm_min); - if(date.tm_sec < 0 || date.tm_sec > 61) + result += mpt::ufmt::dec0<2>(date.hours) + U_(":") + mpt::ufmt::dec0<2>(date.minutes); + if(date.seconds == 0) { return result + tz; } - result += U_(":") + mpt::ufmt::dec0<2>(date.tm_sec); + result += U_(":") + mpt::ufmt::dec0<2>(date.seconds); result += tz; return result; } +mpt::ustring ToShortenedISO8601(mpt::Date::AnyGregorian date) +{ + return ToShortenedISO8601Impl(date); +} + +mpt::ustring ToShortenedISO8601(mpt::Date::UTC date) +{ + return ToShortenedISO8601Impl(date); +} + +#ifdef MODPLUG_TRACKER +mpt::ustring ToShortenedISO8601(Local date) +{ + return ToShortenedISO8601Impl(date); +} +#endif // MODPLUG_TRACKER + } // namespace Date } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/common/mptTime.h b/Frameworks/OpenMPT/OpenMPT/common/mptTime.h index 95b48e5bb..212d09ccc 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/mptTime.h +++ b/Frameworks/OpenMPT/OpenMPT/common/mptTime.h @@ -12,9 +12,25 @@ #include "openmpt/all/BuildSettings.hpp" +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) +#include +#include +#endif #include -#include +#include + +#if MPT_WINNT_AT_LEAST(MPT_WIN_8) +#define MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC +#define MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT +#define MPT_FALLBACK_TIMEZONE_C +#elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) +#define MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT +#define MPT_FALLBACK_TIMEZONE_C +#else +#define MPT_FALLBACK_TIMEZONE_C +#endif + OPENMPT_NAMESPACE_BEGIN @@ -44,21 +60,260 @@ mpt::ustring ToUString(uint64 time100ns); // i.e. 2015-01-15 18:32:01.718 #endif // MODPLUG_TRACKER -class Unix +enum class LogicalTimezone { -// int64 counts 1s since 1970-01-01T00:00Z -private: - int64 Value; -public: - Unix(); - explicit Unix(int64 unixtime); - operator int64 () const; -public: - static mpt::Date::Unix FromUTC(tm timeUtc); - tm AsUTC() const; + Unspecified, + UTC, +#if defined(MODPLUG_TRACKER) + Local, +#endif // MODPLUG_TRACKER }; -mpt::ustring ToShortenedISO8601(tm date); // i.e. 2015-01-15T18:32:01Z +template +struct Gregorian +{ + int year = 0; + unsigned int month = 0; + unsigned int day = 0; + int32 hours = 0; + int32 minutes = 0; + int64 seconds = 0; + friend bool operator==(const Gregorian& lhs, const Gregorian& rhs) + { + return true + && lhs.year == rhs.year + && lhs.month == rhs.month + && lhs.day == rhs.day + && lhs.hours == rhs.hours + && lhs.minutes == rhs.minutes + && lhs.seconds == rhs.seconds + ; + } + friend bool operator!=(const Gregorian& lhs, const Gregorian& rhs) + { + return false + || lhs.year != rhs.year + || lhs.month != rhs.month + || lhs.day != rhs.day + || lhs.hours != rhs.hours + || lhs.minutes != rhs.minutes + || lhs.seconds != rhs.seconds + ; + } +}; + +using AnyGregorian = Gregorian; + +using UTC = Gregorian; + +#if defined(MODPLUG_TRACKER) +using Local = Gregorian; +#endif // MODPLUG_TRACKER + +template +inline Gregorian interpret_as_timezone(AnyGregorian gregorian) +{ + Gregorian result; + result.year = gregorian.year; + result.month = gregorian.month; + result.day = gregorian.day; + result.hours = gregorian.hours; + result.minutes = gregorian.minutes; + result.seconds = gregorian.seconds; + return result; +} + +template +inline Gregorian forget_timezone(Gregorian gregorian) +{ + Gregorian result; + result.year = gregorian.year; + result.month = gregorian.month; + result.day = gregorian.day; + result.hours = gregorian.hours; + result.minutes = gregorian.minutes; + result.seconds = gregorian.seconds; + return result; +} + +namespace nochrono +{ + +// int64 counts 1s since 1970-01-01T00:00Z +struct Unix +{ + int64 value{}; + friend bool operator==(const Unix &a, const Unix &b) + { + return a.value == b.value; + } + friend bool operator!=(const Unix &a, const Unix &b) + { + return a.value != b.value; + } +}; + +inline Unix UnixNow() +{ + return Unix{static_cast(std::time(nullptr))}; +} + +inline int64 UnixAsSeconds(Unix tp) +{ + return tp.value; +} + +inline Unix UnixFromSeconds(int64 seconds) +{ + return Unix{seconds}; +} + +Unix UnixFromUTC(UTC timeUtc); + +UTC UnixAsUTC(Unix tp); + +#if defined(MODPLUG_TRACKER) + +Unix UnixFromLocal(Local timeLocal); + +Local UnixAsLocal(Unix tp); + +#endif // MODPLUG_TRACKER + +} // namespace nochrono + +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) + +using Unix = std::chrono::system_clock::time_point; + +inline Unix UnixNow() +{ + return std::chrono::system_clock::now(); +} + +inline int64 UnixAsSeconds(Unix tp) +{ + return std::chrono::duration_cast(tp.time_since_epoch()).count(); +} + +inline Unix UnixFromSeconds(int64 seconds) +{ + return std::chrono::system_clock::time_point{std::chrono::seconds{seconds}}; +} + +inline mpt::Date::Unix UnixFromUTC(UTC utc) +{ + try + { + return std::chrono::system_clock::time_point{ + std::chrono::sys_days { + std::chrono::year{ utc.year } / + std::chrono::month{ utc.month } / + std::chrono::day{ utc.day } + } + + std::chrono::hours{ utc.hours } + + std::chrono::minutes{ utc.minutes } + + std::chrono::seconds{ utc.seconds }}; + } catch(const std::exception &) + { + return mpt::Date::UnixFromSeconds(mpt::Date::nochrono::UnixAsSeconds(mpt::Date::nochrono::UnixFromUTC(utc))); + } +} + +inline mpt::Date::UTC UnixAsUTC(Unix tp) +{ + try + { + std::chrono::sys_days dp = std::chrono::floor(tp); + std::chrono::year_month_day ymd{dp}; + std::chrono::hh_mm_ss hms{tp - dp}; + mpt::Date::UTC result; + result.year = static_cast(ymd.year()); + result.month = static_cast(ymd.month()); + result.day = static_cast(ymd.day()); + result.hours = static_cast(hms.hours().count()); + result.minutes = static_cast(hms.minutes().count()); + result.seconds = static_cast(hms.seconds().count()); + return result; + } catch(const std::exception &) + { + return mpt::Date::nochrono::UnixAsUTC(mpt::Date::nochrono::UnixFromSeconds(mpt::Date::UnixAsSeconds(tp))); + } +} + +#if defined(MODPLUG_TRACKER) + +inline mpt::Date::Unix UnixFromLocal(Local local) +{ + try + { + std::chrono::time_point local_tp = + std::chrono::local_days { + std::chrono::year{ local.year } / + std::chrono::month{ local.month } / + std::chrono::day{ local.day } + } + + std::chrono::hours{ local.hours } + + std::chrono::minutes{ local.minutes } + + std::chrono::seconds{ local.seconds }; + return std::chrono::zoned_time{std::chrono::current_zone(), local_tp}.get_sys_time(); + } catch(const std::exception &) + { + return mpt::Date::UnixFromSeconds(mpt::Date::nochrono::UnixAsSeconds(mpt::Date::nochrono::UnixFromLocal(local))); + } +} + +inline mpt::Date::Local UnixAsLocal(Unix tp) +{ + try + { + std::chrono::zoned_time local_tp{ std::chrono::current_zone(), tp }; + std::chrono::local_days dp = std::chrono::floor(local_tp.get_local_time()); + std::chrono::year_month_day ymd{dp}; + std::chrono::hh_mm_ss hms{local_tp.get_local_time() - dp}; + mpt::Date::Local result; + result.year = static_cast(ymd.year()); + result.month = static_cast(ymd.month()); + result.day = static_cast(ymd.day()); + result.hours = static_cast(hms.hours().count()); + result.minutes = static_cast(hms.minutes().count()); + result.seconds = static_cast(hms.seconds().count()); + return result; + } catch(const std::exception &) + { + return mpt::Date::nochrono::UnixAsLocal(mpt::Date::nochrono::UnixFromSeconds(mpt::Date::UnixAsSeconds(tp))); + } +} + +#endif // MODPLUG_TRACKER + +#else + +using Unix = nochrono::Unix; + +using nochrono::UnixNow; +using nochrono::UnixAsSeconds; +using nochrono::UnixFromSeconds; + +using nochrono::UnixFromUTC; +using nochrono::UnixAsUTC; + +#if defined(MODPLUG_TRACKER) + +using nochrono::UnixFromLocal; +using nochrono::UnixAsLocal; + +#endif // MODPLUG_TRACKER + +#endif + +mpt::ustring ToShortenedISO8601(AnyGregorian date); // i.e. 2015-01-15T18:32:01 + +mpt::ustring ToShortenedISO8601(UTC date); // i.e. 2015-01-15T18:32:01Z + +#ifdef MODPLUG_TRACKER +mpt::ustring ToShortenedISO8601(Local date); // i.e. 2015-01-15T18:32:01 +#endif // MODPLUG_TRACKER } // namespace Date } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp b/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp index 7d742e1ea..f7993a4bc 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp @@ -12,6 +12,7 @@ #include "serialization_utils.h" +#include "mpt/base/utility.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" @@ -30,18 +31,6 @@ namespace srlztn { -#ifdef MPT_ALL_LOGGING -#define SSB_LOGGING -#endif - - -#ifdef SSB_LOGGING -#define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", x) -#else -#define SSB_LOG(x) do { } while(0) -#endif - - static const uint8 HeaderId_FlagByte = 0; // Indexing starts from 0. @@ -49,11 +38,17 @@ static inline bool Testbit(uint8 val, uint8 bitindex) {return ((val & (1 << biti static inline void Setbit(uint8& val, uint8 bitindex, bool newval) { - if(newval) val |= (1 << bitindex); - else val &= ~(1 << bitindex); + if(newval) + { + val |= static_cast(1u << bitindex); + } else + { + val &= static_cast(~(1u << bitindex)); + } } +#ifdef SSB_LOGGING bool ID::IsPrintable() const { for(std::size_t i = 0; i < m_ID.length(); ++i) @@ -65,6 +60,7 @@ bool ID::IsPrintable() const } return true; } +#endif //Format: First bit tells whether the size indicator is 1 or 2 bytes. @@ -88,7 +84,7 @@ void WriteItemString(std::ostream& oStrm, const std::string &str) } -void ReadItemString(std::istream& iStrm, std::string& str, const DataSize) +void ReadItemString(std::istream& iStrm, std::string& str, const std::size_t) { // bits 0,1: Bytes per char type: 1,2,3,4. // bits 2,3: Bytes in size indicator, 1,2,3,4 @@ -118,6 +114,7 @@ void ReadItemString(std::istream& iStrm, std::string& str, const DataSize) } +#ifdef SSB_LOGGING mpt::ustring ID::AsString() const { if(IsPrintable()) @@ -133,13 +130,14 @@ mpt::ustring ID::AsString() const std::memcpy(&val, m_ID.data(), m_ID.length()); return mpt::ufmt::val(val); } +#endif const char Ssb::s_EntryID[3] = {'2','2','8'}; Ssb::Ssb() - : m_Status(SNT_NONE) + : m_Status(Status{}) , m_nFixedEntrySize(0) , m_posStart(0) , m_nIdbytes(IdSizeVariable) @@ -173,59 +171,53 @@ SsbRead::SsbRead(std::istream& is) } -void SsbWrite::AddWriteNote(const SsbStatus s) +void SsbWrite::AddWriteNote(const Status s) { - m_Status |= s; - SSB_LOG(MPT_UFORMAT("{}: 0x{}")(U_("Write note: "), mpt::ufmt::hex(s))); + m_Status.level = static_cast(mpt::to_underlying(m_Status.level) | mpt::to_underlying(s.level)); + m_Status.messages = static_cast(mpt::to_underlying(m_Status.messages) | mpt::to_underlying(s.messages)); + SSB_LOG(MPT_UFORMAT("{}: 0x{} 0x{}")(U_("Write note: "), mpt::ufmt::hex(mpt::to_underlying(s.level)), mpt::ufmt::hex(mpt::to_underlying(s.messages)))); } -void SsbRead::AddReadNote(const SsbStatus s) +void SsbRead::AddReadNote(const Status s) { - m_Status |= s; - SSB_LOG(MPT_UFORMAT("{}: 0x{}")(U_("Read note: "), mpt::ufmt::hex(s))); + m_Status.level = static_cast(mpt::to_underlying(m_Status.level) | mpt::to_underlying(s.level)); + m_Status.messages = static_cast(mpt::to_underlying(m_Status.messages) | mpt::to_underlying(s.messages)); + SSB_LOG(MPT_UFORMAT("{}: 0x{} 0x{}")(U_("Read note: "), mpt::ufmt::hex(mpt::to_underlying(s.level)), mpt::ufmt::hex(mpt::to_underlying(s.messages)))); } -void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum) +#ifdef SSB_LOGGING +void SsbRead::LogReadEntry(const ReadEntry &pRe, const std::size_t nNum) { - m_Status |= SNT_PROGRESS; SSB_LOG(MPT_UFORMAT("Read entry: {{num, id, rpos, size, desc}} = {{{}, {}, {}, {}, {}}}")( nNum, - (pRe && pRe->nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe->nIdpos], pRe->nIdLength).AsString() : U_(""), - (pRe) ? pRe->rposStart : 0, - (pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : U_(""), + (pRe.nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe.nIdpos], pRe.nIdLength).AsString() : U_(""), + pRe.rposStart, + (pRe.nSize != invalidDatasize) ? mpt::ufmt::val(pRe.nSize) : U_(""), U_(""))); -#ifndef SSB_LOGGING - MPT_UNREFERENCED_PARAMETER(pRe); - MPT_UNREFERENCED_PARAMETER(nNum); -#endif } +#endif +#ifdef SSB_LOGGING // Called after writing an entry. -void SsbWrite::AddWriteNote(const ID &id, const NumType nEntryNum, const DataSize nBytecount, const RposType rposStart) +void SsbWrite::LogWriteEntry(const ID &id, const std::size_t nEntryNum, const std::size_t nBytecount, const std::streamoff rposStart) { - m_Status |= SNT_PROGRESS; SSB_LOG(MPT_UFORMAT("Wrote entry: {{num, id, rpos, size}} = {{{}, {}, {}, {}}}")(nEntryNum, id.AsString(), rposStart, nBytecount)); -#ifndef SSB_LOGGING - MPT_UNREFERENCED_PARAMETER(id); - MPT_UNREFERENCED_PARAMETER(nEntryNum); - MPT_UNREFERENCED_PARAMETER(nBytecount); - MPT_UNREFERENCED_PARAMETER(rposStart); -#endif } +#endif void SsbRead::ResetReadstatus() { - m_Status = SNT_NONE; + m_Status = Status{}; m_Idarray.reserve(32); m_Idarray.push_back(0); } void SsbWrite::WriteMapItem(const ID &id, - const RposType& rposDataStart, - const DataSize& nDatasize, - const char* pszDesc) + const std::streamoff& rposDataStart, + const std::size_t& nDatasize, + const std::string &pszDesc) { SSB_LOG(MPT_UFORMAT("Writing map entry: id={}, rpos={}, size={}")( (id.GetSize() > 0) ? id.AsString() : U_(""), @@ -243,32 +235,21 @@ void SsbWrite::WriteMapItem(const ID &id, mpt::IO::WriteAdaptiveInt16LE(mapStream, static_cast(id.GetSize())); if(id.GetSize() > 0) - mapStream.write(id.GetBytes(), id.GetSize()); + mapStream.write(id.AsSpan().data(), id.AsSpan().size()); } - if (GetFlag(RwfWMapStartPosEntry)) //Startpos + if(m_Flags[RwfWMapStartPosEntry]) // Startpos mpt::IO::WriteAdaptiveInt64LE(mapStream, rposDataStart); - if (GetFlag(RwfWMapSizeEntry)) //Entrysize + if(m_Flags[RwfWMapSizeEntry]) // Entrysize mpt::IO::WriteAdaptiveInt64LE(mapStream, nDatasize); - if (GetFlag(RwfWMapDescEntry)) //Entry descriptions - WriteAdaptive12String(mapStream, std::string(pszDesc)); + if(m_Flags[RwfWMapDescEntry]) // Entry descriptions + WriteAdaptive12String(mapStream, pszDesc); m_MapStreamString.append(mapStream.str()); } -void SsbWrite::IncrementWriteCounter() -{ - m_nCounter++; - if(m_nCounter >= static_cast(std::numeric_limits::max() >> 2)) - { - FinishWrite(); - AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED); - } -} - - void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion) { SSB_LOG(MPT_UFORMAT("Write header with ID = {}")(id.AsString())); @@ -281,26 +262,26 @@ void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion) // Start bytes. oStrm.write(s_EntryID, sizeof(s_EntryID)); - m_posStart = oStrm.tellp() - Offtype(sizeof(s_EntryID)); + m_posStart = static_cast(oStrm.tellp()) - static_cast(sizeof(s_EntryID)); // Object ID. { uint8 idsize = static_cast(id.GetSize()); Binarywrite(oStrm, idsize); - if(idsize > 0) oStrm.write(id.GetBytes(), id.GetSize()); + if(idsize > 0) oStrm.write(id.AsSpan().data(), id.AsSpan().size()); } // Form header. uint8 header = 0; - SetFlag(RwfWMapStartPosEntry, GetFlag(RwfWMapStartPosEntry) && m_nFixedEntrySize == 0); - SetFlag(RwfWMapSizeEntry, GetFlag(RwfWMapSizeEntry) && m_nFixedEntrySize == 0); + m_Flags[RwfWMapStartPosEntry] = m_Flags[RwfWMapStartPosEntry] && m_nFixedEntrySize == 0; + m_Flags[RwfWMapSizeEntry] = m_Flags[RwfWMapSizeEntry] && m_nFixedEntrySize == 0; header = (m_nIdbytes != 4) ? (m_nIdbytes & 3) : 3; //0,1 : Bytes per IDtype, 0,1,2,4 - Setbit(header, 2, GetFlag(RwfWMapStartPosEntry)); //2 : Startpos in map? - Setbit(header, 3, GetFlag(RwfWMapSizeEntry)); //3 : Datasize in map? - Setbit(header, 4, GetFlag(RwfWVersionNum)); //4 : Version numeric field? - Setbit(header, 7, GetFlag(RwfWMapDescEntry)); //7 : Entrydescriptions in map? + Setbit(header, 2, m_Flags[RwfWMapStartPosEntry]); //2 : Startpos in map? + Setbit(header, 3, m_Flags[RwfWMapSizeEntry]); //3 : Datasize in map? + Setbit(header, 4, m_Flags[RwfWVersionNum]); //4 : Version numeric field? + Setbit(header, 7, m_Flags[RwfWMapDescEntry]); //7 : Entrydescriptions in map? // Write header Binarywrite(oStrm, header); @@ -333,55 +314,59 @@ void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion) mpt::IO::WriteAdaptiveInt32LE(oStrm, m_nFixedEntrySize); //Entrycount. Reserve two bytes(max uint16_max / 4 entries), actual value is written after writing data. - m_posEntrycount = oStrm.tellp(); + m_posEntrycount = static_cast(oStrm.tellp()); Binarywrite(oStrm, 0); - SetFlag(RwfRwHasMap, (m_nIdbytes != 0 || GetFlag(RwfWMapStartPosEntry) || GetFlag(RwfWMapSizeEntry) || GetFlag(RwfWMapDescEntry))); + m_Flags[RwfRwHasMap] = (m_nIdbytes != 0 || m_Flags[RwfWMapStartPosEntry] || m_Flags[RwfWMapSizeEntry] || m_Flags[RwfWMapDescEntry]); - m_posMapPosField = oStrm.tellp(); - if (GetFlag(RwfRwHasMap)) //Mapping begin pos(reserve space - actual value is written after writing data) + m_posMapPosField = static_cast(oStrm.tellp()); + if(m_Flags[RwfRwHasMap]) // Mapping begin pos(reserve space - actual value is written after writing data) Binarywrite(oStrm, 0); } -SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin) +void SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const std::streamoff& posReadBegin) { - if (pE != nullptr) - AddReadNote(pE, m_nCounter); - else if (GetFlag(RwfRMapHasId) == false) // Not ID's in map. +#ifdef SSB_LOGGING + if(pE) + { + LogReadEntry(*pE, m_nCounter); + } else if(!m_Flags[RwfRMapHasId]) // Not ID's in map. { ReadEntry e; - e.rposStart = static_cast(posReadBegin - m_posStart); - e.nSize = static_cast(iStrm.tellg() - posReadBegin); - AddReadNote(&e, m_nCounter); - } - else // Entry not found. + e.rposStart = posReadBegin - m_posStart; + e.nSize = mpt::saturate_cast(static_cast(static_cast(iStrm.tellg()) - posReadBegin)); + LogReadEntry(e, m_nCounter); + } else // Entry not found. { SSB_LOG(MPT_UFORMAT("No entry with id {} found.")(id.AsString())); -#ifndef SSB_LOGGING - MPT_UNREFERENCED_PARAMETER(id); -#endif - return EntryNotFound; } - m_nCounter++; - return EntryRead; +#else + MPT_UNREFERENCED_PARAMETER(id); + MPT_UNREFERENCED_PARAMETER(posReadBegin); +#endif + const bool entryFound = (pE || !m_Flags[RwfRMapHasId]); + if(entryFound) + { + m_nCounter++; + } } -void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite) +void SsbWrite::OnWroteItem(const ID &id, const std::streamoff& posBeforeWrite) { - const Offtype nRawEntrySize = oStrm.tellp() - posBeforeWrite; + const std::streamoff nRawEntrySize = static_cast(oStrm.tellp()) - posBeforeWrite; - MPT_MAYBE_CONSTANT_IF(nRawEntrySize < 0 || static_cast(nRawEntrySize) > std::numeric_limits::max()) + MPT_MAYBE_CONSTANT_IF(!mpt::in_range(nRawEntrySize)) { AddWriteNote(SNW_INSUFFICIENT_DATASIZETYPE); return; } - if(GetFlag(RwfRMapHasSize) && (nRawEntrySize < 0 || static_cast(nRawEntrySize) > (std::numeric_limits::max() >> 2))) + if(m_Flags[RwfRMapHasSize] && (static_cast(nRawEntrySize) > (std::numeric_limits::max() >> 2))) { AddWriteNote(SNW_DATASIZETYPE_OVERFLOW); return; } - DataSize nEntrySize = static_cast(nRawEntrySize); + std::size_t nEntrySize = static_cast(nRawEntrySize); // Handle fixed size entries: if (m_nFixedEntrySize > 0) @@ -395,11 +380,19 @@ void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite) else { AddWriteNote(SNW_INSUFFICIENT_FIXEDSIZE); return; } } - if (GetFlag(RwfRwHasMap)) - WriteMapItem(id, static_cast(posBeforeWrite - m_posStart), nEntrySize, ""); + if(m_Flags[RwfRwHasMap]) + WriteMapItem(id, posBeforeWrite - m_posStart, nEntrySize, ""); - AddWriteNote(id, m_nCounter, nEntrySize, static_cast(posBeforeWrite - m_posStart)); - IncrementWriteCounter(); +#ifdef SSB_LOGGING + LogWriteEntry(id, m_nCounter, nEntrySize, posBeforeWrite - m_posStart); +#endif + + m_nCounter++; + if(m_nCounter >= static_cast(std::numeric_limits::max() >> 2)) + { + FinishWrite(); + AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED); + } } @@ -412,7 +405,7 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) if (!iStrm.good()) { AddReadNote(SNRW_BADGIVEN_STREAM); return; } - m_posStart = iStrm.tellg(); + m_posStart = static_cast(iStrm.tellg()); // Start bytes. { @@ -438,7 +431,7 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) { AddReadNote(SNR_OBJECTCLASS_IDMISMATCH); } - if ((m_Status & SNT_FAILURE) != 0) + if(HasFailed()) { SSB_LOG(U_("ID mismatch, terminating read.")); return; @@ -452,7 +445,7 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) const uint8 header = tempU8; m_nIdbytes = ((header & 3) == 3) ? 4 : (header & 3); if (Testbit(header, 6)) - SetFlag(RwfRTwoBytesDescChar, true); + m_Flags[RwfRTwoBytesDescChar] = true; // Read headerdata size uint32 tempU32 = 0; @@ -502,13 +495,13 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) if(Testbit(flagbyte, 1)) // Fixedsize entries? mpt::IO::ReadAdaptiveInt32LE(iStrm, m_nFixedEntrySize); - SetFlag(RwfRMapHasStartpos, Testbit(header, 2)); - SetFlag(RwfRMapHasSize, Testbit(header, 3)); - SetFlag(RwfRMapHasId, (m_nIdbytes > 0)); - SetFlag(RwfRMapHasDesc, Testbit(header, 7)); - SetFlag(RwfRwHasMap, GetFlag(RwfRMapHasId) || GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || GetFlag(RwfRMapHasDesc)); + m_Flags[RwfRMapHasStartpos] = Testbit(header, 2); + m_Flags[RwfRMapHasSize] = Testbit(header, 3); + m_Flags[RwfRMapHasId] = (m_nIdbytes > 0); + m_Flags[RwfRMapHasDesc] = Testbit(header, 7); + m_Flags[RwfRwHasMap] = m_Flags[RwfRMapHasId] || m_Flags[RwfRMapHasStartpos] || m_Flags[RwfRMapHasSize] || m_Flags[RwfRMapHasDesc]; - if (GetFlag(RwfRwHasMap) == false) + if(!m_Flags[RwfRwHasMap]) { SSB_LOG(U_("No map in the file.")); } @@ -517,7 +510,7 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) { uint16 size = 0; mpt::IO::ReadAdaptiveInt16LE(iStrm, size); - iStrm.ignore(size * (GetFlag(RwfRTwoBytesDescChar) ? 2 : 1)); + iStrm.ignore(size * (m_Flags[RwfRTwoBytesDescChar] ? 2 : 1)); } if(Testbit(flagbyte, 3)) @@ -530,41 +523,41 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion) // Additionally, 16000 is an arbitrary limit to avoid an out-of-memory DoS when caching the map. { AddReadNote(SNR_TOO_MANY_ENTRIES_TO_READ); return; } - m_nReadEntrycount = static_cast(tempU64); + m_nReadEntrycount = static_cast(tempU64); if(m_nReadEntrycount == 0) AddReadNote(SNR_ZEROENTRYCOUNT); // Read map rpos if map exists. - if (GetFlag(RwfRwHasMap)) + if(m_Flags[RwfRwHasMap]) { mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); - if(tempU64 > static_cast(std::numeric_limits::max())) + if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } } - const Offtype rawEndOfHdrData = iStrm.tellg() - m_posStart; + const std::streamoff rawEndOfHdrData = static_cast(iStrm.tellg()) - m_posStart; - MPT_MAYBE_CONSTANT_IF(rawEndOfHdrData < 0 || static_cast(rawEndOfHdrData) > std::numeric_limits::max()) + if(rawEndOfHdrData < 0) { AddReadNote(SNR_INSUFFICIENT_RPOSTYPE); return; } - m_rposEndofHdrData = static_cast(rawEndOfHdrData); - m_rposMapBegin = (GetFlag(RwfRwHasMap)) ? static_cast(tempU64) : m_rposEndofHdrData; + m_rposEndofHdrData = rawEndOfHdrData; + m_rposMapBegin = (m_Flags[RwfRwHasMap]) ? static_cast(tempU64) : m_rposEndofHdrData; - if (GetFlag(RwfRwHasMap) == false) + if(!m_Flags[RwfRwHasMap]) m_posMapEnd = m_posStart + m_rposEndofHdrData; - SetFlag(RwfRHeaderIsRead, true); + m_Flags[RwfRHeaderIsRead] = true; } void SsbRead::CacheMap() { - if(GetFlag(RwfRwHasMap) || m_nFixedEntrySize > 0) + if(m_Flags[RwfRwHasMap] || m_nFixedEntrySize > 0) { - iStrm.seekg(m_posStart + m_rposMapBegin); + iStrm.seekg(m_posStart + m_rposMapBegin, std::ios::beg); if(iStrm.fail()) { AddReadNote(SNR_BADSTREAM_AFTER_MAPHEADERSEEK); return; } @@ -575,7 +568,7 @@ void SsbRead::CacheMap() m_Idarray.reserve(m_nReadEntrycount * 4); //Read map - for(NumType i = 0; i static_cast(std::numeric_limits::max())) + if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } - mapData[i].rposStart = static_cast(tempU64); + mapData[i].rposStart = static_cast(tempU64); } // Read entry size. if (m_nFixedEntrySize > 0) mapData[i].nSize = m_nFixedEntrySize; - else if(GetFlag(RwfRMapHasSize)) // Map has datasize field. + else if(m_Flags[RwfRMapHasSize]) // Map has datasize field. { uint64 tempU64; mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64); - if(tempU64 > static_cast(std::numeric_limits::max())) + if(!mpt::in_range(tempU64)) { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; } - mapData[i].nSize = static_cast(tempU64); + mapData[i].nSize = static_cast(tempU64); } // If there's no entry startpos in map, count start pos from datasizes. // Here readentry.rposStart is set to relative position from databegin. - if (mapData[i].nSize != invalidDatasize && GetFlag(RwfRMapHasStartpos) == false) + if(mapData[i].nSize != invalidDatasize && !m_Flags[RwfRMapHasStartpos]) mapData[i].rposStart = (i > 0) ? mapData[i-1].rposStart + mapData[i-1].nSize : 0; - if(GetFlag(RwfRMapHasDesc)) //Map has entrydescriptions? + if(m_Flags[RwfRMapHasDesc]) // Map has entrydescriptions? { uint16 size = 0; mpt::IO::ReadAdaptiveInt16LE(iStrm, size); - if(GetFlag(RwfRTwoBytesDescChar)) + if(m_Flags[RwfRTwoBytesDescChar]) iStrm.ignore(size * 2); else iStrm.ignore(size); } } - m_posMapEnd = iStrm.tellg(); + m_posMapEnd = static_cast(iStrm.tellg()); SSB_LOG(MPT_UFORMAT("End of map(rpos): {}")(m_posMapEnd - m_posStart)); } - SetFlag(RwfRMapCached, true); - m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + Postype(m_rposEndofHdrData); - iStrm.seekg(m_posDataBegin); + m_Flags[RwfRMapCached] = true; + m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + m_rposEndofHdrData; + iStrm.seekg(m_posDataBegin, std::ios::beg); // If there are no positions in the map but there are entry sizes, rposStart will // be relative to data start. Now that posDataBegin is known, make them relative to // startpos. - if (GetFlag(RwfRMapHasStartpos) == false && (GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0)) + if(!m_Flags[RwfRMapHasStartpos] && (m_Flags[RwfRMapHasSize] || m_nFixedEntrySize > 0)) { - const RposType offset = static_cast(m_posDataBegin - m_posStart); + const std::streamoff offset = m_posDataBegin - m_posStart; for(size_t i = 0; i < m_nReadEntrycount; i++) mapData[i].rposStart += offset; } @@ -653,13 +646,13 @@ void SsbRead::CacheMap() const ReadEntry* SsbRead::Find(const ID &id) { iStrm.clear(); - if (GetFlag(RwfRMapCached) == false) + if(!m_Flags[RwfRMapCached]) CacheMap(); - if (m_nFixedEntrySize > 0 && GetFlag(RwfRMapHasStartpos) == false && GetFlag(RwfRMapHasSize) == false) - iStrm.seekg(m_posDataBegin + Postype(m_nFixedEntrySize * m_nCounter)); + if(m_nFixedEntrySize > 0 && !m_Flags[RwfRMapHasStartpos] && !m_Flags[RwfRMapHasSize]) + iStrm.seekg(m_posDataBegin + static_cast(m_nFixedEntrySize * m_nCounter), std::ios::beg); - if (GetFlag(RwfRMapHasId) == true) + if(m_Flags[RwfRMapHasId]) { const size_t nEntries = mapData.size(); for(size_t i0 = 0; i0 < nEntries; i0++) @@ -669,7 +662,7 @@ const ReadEntry* SsbRead::Find(const ID &id) { m_nNextReadHint = (i + 1) % nEntries; if (mapData[i].rposStart != 0) - iStrm.seekg(m_posStart + Postype(mapData[i].rposStart)); + iStrm.seekg(m_posStart + mapData[i].rposStart, std::ios::beg); return &mapData[i]; } } @@ -680,28 +673,28 @@ const ReadEntry* SsbRead::Find(const ID &id) void SsbWrite::FinishWrite() { - const Postype posDataEnd = oStrm.tellp(); + const std::streamoff posDataEnd = static_cast(oStrm.tellp()); - Postype posMapStart = oStrm.tellp(); + std::streamoff posMapStart = static_cast(oStrm.tellp()); SSB_LOG(MPT_UFORMAT("Writing map to rpos: {}")(posMapStart - m_posStart)); - if (GetFlag(RwfRwHasMap)) //Write map + if(m_Flags[RwfRwHasMap]) // Write map { oStrm.write(m_MapStreamString.c_str(), m_MapStreamString.length()); } - const Postype posMapEnd = oStrm.tellp(); + const std::streamoff posMapEnd = static_cast(oStrm.tellp()); // Write entry count. - oStrm.seekp(m_posEntrycount); + oStrm.seekp(m_posEntrycount, std::ios::beg); // Write a fixed size=2 Adaptive64LE because space for this value has already been reserved berforehand. mpt::IO::WriteAdaptiveInt64LE(oStrm, m_nCounter, 2); - if (GetFlag(RwfRwHasMap)) + if(m_Flags[RwfRwHasMap]) { // Write map start position. - oStrm.seekp(m_posMapPosField); + oStrm.seekp(m_posMapPosField, std::ios::beg); const uint64 rposMap = posMapStart - m_posStart; // Write a fixed size=8 Adaptive64LE because space for this value has already been reserved berforehand. @@ -710,9 +703,9 @@ void SsbWrite::FinishWrite() } // Seek to end. - oStrm.seekp(std::max(posMapEnd, posDataEnd)); + oStrm.seekp(std::max(posMapEnd, posDataEnd), std::ios::beg); - SSB_LOG(MPT_UFORMAT("End of stream(rpos): {}")(oStrm.tellp() - m_posStart)); + SSB_LOG(MPT_UFORMAT("End of stream(rpos): {}")(static_cast(oStrm.tellp()) - m_posStart)); } } // namespace srlztn diff --git a/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h b/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h index ac140ff67..f290c6dd9 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h +++ b/Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h @@ -12,6 +12,7 @@ #include "openmpt/all/BuildSettings.hpp" +#include "mpt/base/alloc.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "openmpt/base/Endian.hpp" @@ -29,72 +30,108 @@ #include #include +#include #include OPENMPT_NAMESPACE_BEGIN + +#ifdef MPT_ALL_LOGGING +#define SSB_LOGGING +#endif + + +#ifdef SSB_LOGGING +#define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", x) +#else +#define SSB_LOG(x) do { } while(0) +#endif + + namespace srlztn //SeRiaLiZaTioN { -typedef std::ios::off_type Offtype; -typedef Offtype Postype; -typedef uintptr_t DataSize; // Data size type. -typedef uintptr_t RposType; // Relative position type. -typedef uintptr_t NumType; // Entry count type. +constexpr inline std::size_t invalidDatasize = static_cast(0) - 1; -const DataSize invalidDatasize = DataSize(-1); -enum +enum class StatusLevel : uint8 { - SNT_PROGRESS = 0x08000000, // = 1 << 27 - SNT_FAILURE = 0x40000000, // = 1 << 30 - SNT_NOTE = 0x20000000, // = 1 << 29 - SNT_WARNING = 0x10000000, // = 1 << 28 - SNT_NONE = 0, - - SNRW_BADGIVEN_STREAM = 1 | SNT_FAILURE, - - // Read failures. - SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 2 | SNT_FAILURE, - SNR_STARTBYTE_MISMATCH = 3 | SNT_FAILURE, - SNR_BADSTREAM_AT_MAP_READ = 4 | SNT_FAILURE, - SNR_INSUFFICIENT_STREAM_OFFTYPE = 5 | SNT_FAILURE, - SNR_OBJECTCLASS_IDMISMATCH = 6 | SNT_FAILURE, - SNR_TOO_MANY_ENTRIES_TO_READ = 7 | SNT_FAILURE, - SNR_INSUFFICIENT_RPOSTYPE = 8 | SNT_FAILURE, - - // Read notes and warnings. - SNR_ZEROENTRYCOUNT = 0x80 | SNT_NOTE, // 0x80 == 1 << 7 - SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x100 | SNT_NOTE, - SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x200 | SNT_NOTE, - - // Write failures. - SNW_INSUFFICIENT_FIXEDSIZE = (0x10) | SNT_FAILURE, - SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = (0x11) | SNT_FAILURE, - SNW_DATASIZETYPE_OVERFLOW = (0x13) | SNT_FAILURE, - SNW_MAX_WRITE_COUNT_REACHED = (0x14) | SNT_FAILURE, - SNW_INSUFFICIENT_DATASIZETYPE = (0x16) | SNT_FAILURE + Failure = 0x2, + Note = 0x1, + None = 0x0, + Max = 0xff, }; +enum class StatusMessages : uint32 +{ + None = 0, -enum + // Read notes and warnings. + SNR_ZEROENTRYCOUNT = 0x00'00'00'01, + SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x00'00'00'02, + SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x00'00'00'04, + + // Read failures. + SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 0x00'00'01'00, + SNR_STARTBYTE_MISMATCH = 0x00'00'02'00, + SNR_BADSTREAM_AT_MAP_READ = 0x00'00'04'00, + SNR_INSUFFICIENT_STREAM_OFFTYPE = 0x00'00'08'00, + SNR_OBJECTCLASS_IDMISMATCH = 0x00'00'10'00, + SNR_TOO_MANY_ENTRIES_TO_READ = 0x00'00'20'00, + SNR_INSUFFICIENT_RPOSTYPE = 0x00'00'40'00, + + // Write failures. + SNW_INSUFFICIENT_FIXEDSIZE = 0x00'01'00'00, + SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = 0x00'02'00'00, + SNW_DATASIZETYPE_OVERFLOW = 0x00'04'00'00, + SNW_MAX_WRITE_COUNT_REACHED = 0x00'08'00'00, + SNW_INSUFFICIENT_DATASIZETYPE = 0x00'10'00'00, + + SNRW_BADGIVEN_STREAM = 0x01'00'00'00, + + Max = 0xffffffff, +}; + +struct Status +{ + StatusLevel level = StatusLevel::None; + StatusMessages messages = StatusMessages::None; +}; + +constexpr inline Status SNR_ZEROENTRYCOUNT = {StatusLevel::Note, StatusMessages::SNR_ZEROENTRYCOUNT}; +constexpr inline Status SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = {StatusLevel::Note, StatusMessages::SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED}; +constexpr inline Status SNR_LOADING_OBJECT_WITH_LARGER_VERSION = {StatusLevel::Note, StatusMessages::SNR_LOADING_OBJECT_WITH_LARGER_VERSION}; + +constexpr inline Status SNR_BADSTREAM_AFTER_MAPHEADERSEEK = {StatusLevel::Failure, StatusMessages::SNR_BADSTREAM_AFTER_MAPHEADERSEEK}; +constexpr inline Status SNR_STARTBYTE_MISMATCH = {StatusLevel::Failure, StatusMessages::SNR_STARTBYTE_MISMATCH}; +constexpr inline Status SNR_BADSTREAM_AT_MAP_READ = {StatusLevel::Failure, StatusMessages::SNR_BADSTREAM_AT_MAP_READ}; +constexpr inline Status SNR_INSUFFICIENT_STREAM_OFFTYPE = {StatusLevel::Failure, StatusMessages::SNR_INSUFFICIENT_STREAM_OFFTYPE}; +constexpr inline Status SNR_OBJECTCLASS_IDMISMATCH = {StatusLevel::Failure, StatusMessages::SNR_OBJECTCLASS_IDMISMATCH}; +constexpr inline Status SNR_TOO_MANY_ENTRIES_TO_READ = {StatusLevel::Failure, StatusMessages::SNR_TOO_MANY_ENTRIES_TO_READ}; +constexpr inline Status SNR_INSUFFICIENT_RPOSTYPE = {StatusLevel::Failure, StatusMessages::SNR_INSUFFICIENT_RPOSTYPE}; + +constexpr inline Status SNW_INSUFFICIENT_FIXEDSIZE = {StatusLevel::Failure, StatusMessages::SNW_INSUFFICIENT_FIXEDSIZE}; +constexpr inline Status SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = {StatusLevel::Failure, StatusMessages::SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING}; +constexpr inline Status SNW_DATASIZETYPE_OVERFLOW = {StatusLevel::Failure, StatusMessages::SNW_DATASIZETYPE_OVERFLOW}; +constexpr inline Status SNW_MAX_WRITE_COUNT_REACHED = {StatusLevel::Failure, StatusMessages::SNW_MAX_WRITE_COUNT_REACHED}; +constexpr inline Status SNW_INSUFFICIENT_DATASIZETYPE = {StatusLevel::Failure, StatusMessages::SNW_INSUFFICIENT_DATASIZETYPE}; + +constexpr inline Status SNRW_BADGIVEN_STREAM = {StatusLevel::Failure, StatusMessages::SNRW_BADGIVEN_STREAM}; + + +enum : uint16 { IdSizeVariable = std::numeric_limits::max(), IdSizeMaxFixedSize = (std::numeric_limits::max() >> 1) }; -typedef int32 SsbStatus; - - struct ReadEntry { - ReadEntry() : nIdpos(0), rposStart(0), nSize(invalidDatasize), nIdLength(0) {} - - uintptr_t nIdpos; // Index of id start in ID array. - RposType rposStart; // Entry start position. - DataSize nSize; // Entry size. - uint16 nIdLength; // Length of id. + std::size_t nIdpos = 0; // Index of id start in ID array. + std::streamoff rposStart = 0; // Entry start position. + std::size_t nSize = invalidDatasize; // Entry size. + uint16 nIdLength = 0; // Length of id. }; @@ -173,38 +210,34 @@ inline void Binaryread(std::istream& iStrm, double& data) //Read only given number of bytes to the beginning of data; data bytes are memset to 0 before reading. template -inline void Binaryread(std::istream& iStrm, T& data, const Offtype bytecount) +inline void Binaryread(std::istream& iStrm, T& data, const std::size_t bytecount) { - mpt::IO::ReadBinaryTruncatedLE(iStrm, data, static_cast(bytecount)); + mpt::IO::ReadBinaryTruncatedLE(iStrm, data, bytecount); } template <> -inline void Binaryread(std::istream& iStrm, float& data, const Offtype bytecount) +inline void Binaryread(std::istream& iStrm, float& data, const std::size_t bytecount) { - typedef IEEE754binary32LE T; - std::byte bytes[sizeof(T)]; - std::memset(bytes, 0, sizeof(T)); - mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast(bytecount), sizeof(T))); + using T = IEEE754binary32LE; + mpt::IO::SeekRelative(iStrm, std::min(bytecount, sizeof(T))); // There is not much we can sanely do for truncated floats, - // thus we ignore what we just read and return 0. + // thus we ignore what we could read and return 0. data = 0.0f; } template <> -inline void Binaryread(std::istream& iStrm, double& data, const Offtype bytecount) +inline void Binaryread(std::istream& iStrm, double& data, const std::size_t bytecount) { - typedef IEEE754binary64LE T; - std::byte bytes[sizeof(T)]; - std::memset(bytes, 0, sizeof(T)); - mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast(bytecount), sizeof(T))); + using T = IEEE754binary64LE; + mpt::IO::SeekRelative(iStrm, std::min(bytecount, sizeof(T))); // There is not much we can sanely do for truncated floats, - // thus we ignore what we just read and return 0. + // thus we ignore what we could read and return 0. data = 0.0; } template -inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize) +inline void ReadItem(std::istream& iStrm, T& data, const std::size_t nSize) { static_assert(std::is_trivial::value == true, ""); if (nSize == sizeof(T) || nSize == invalidDatasize) @@ -213,10 +246,10 @@ inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize) Binaryread(iStrm, data, nSize); } -void ReadItemString(std::istream& iStrm, std::string& str, const DataSize); +void ReadItemString(std::istream& iStrm, std::string& str, const std::size_t); template <> -inline void ReadItem(std::istream& iStrm, std::string& str, const DataSize nSize) +inline void ReadItem(std::istream& iStrm, std::string& str, const std::size_t nSize) { ReadItemString(iStrm, str, nSize); } @@ -228,23 +261,30 @@ class ID private: std::string m_ID; // NOTE: can contain null characters ('\0') public: - ID() { } + ID() = default; ID(const std::string &id) : m_ID(id) { } - ID(const char *beg, const char *end) : m_ID(beg, end) { } - ID(const char *id) : m_ID(id?id:"") { } - ID(const char * str, std::size_t len) : m_ID(str, str + len) { } + ID(const char *id) : m_ID(id ? id : "") { } + ID(const char * str, std::size_t len) : m_ID(str, len) { } template static ID FromInt(const T &val) { static_assert(std::numeric_limits::is_integer); typename mpt::make_le::type valle; valle = val; - return ID(std::string(mpt::byte_cast(mpt::as_raw_memory(valle).data()), mpt::byte_cast(mpt::as_raw_memory(valle).data() + sizeof(valle)))); + return ID(mpt::byte_cast(mpt::as_raw_memory(valle).data()), mpt::as_raw_memory(valle).size()); } +#ifdef SSB_LOGGING bool IsPrintable() const; mpt::ustring AsString() const; - const char *GetBytes() const { return m_ID.c_str(); } - std::size_t GetSize() const { return m_ID.length(); } +#endif + std::size_t GetSize() const + { + return m_ID.size(); + } + mpt::span AsSpan() const + { + return mpt::as_span(m_ID); + } bool operator == (const ID &other) const { return m_ID == other.m_ID; } bool operator != (const ID &other) const { return m_ID != other.m_ID; } }; @@ -260,30 +300,21 @@ protected: public: - SsbStatus GetStatus() const + bool HasFailed() const { - return m_Status; + return (m_Status.level >= StatusLevel::Failure); } protected: - // When writing, returns the number of entries written. - // When reading, returns the number of entries read not including unrecognized entries. - NumType GetCounter() const {return m_nCounter;} - - void SetFlag(Rwf flag, bool val) {m_Flags.set(flag, val);} - bool GetFlag(Rwf flag) const {return m_Flags[flag];} - -protected: - - SsbStatus m_Status; + Status m_Status; uint32 m_nFixedEntrySize; // Read/write: If > 0, data entries have given fixed size. - Postype m_posStart; // Read/write: Stream position at the beginning of object. + std::streamoff m_posStart; // Read/write: Stream position at the beginning of object. uint16 m_nIdbytes; // Read/Write: Tells map ID entry size in bytes. If size is variable, value is IdSizeVariable. - NumType m_nCounter; // Read/write: Keeps count of entries written/read. + std::size_t m_nCounter; // Read/write: Keeps count of entries written/read. std::bitset m_Flags; // Read/write: Various flags. @@ -302,16 +333,7 @@ class SsbRead public: - enum ReadRv // Read return value. - { - EntryRead, - EntryNotFound - }; - enum IdMatchStatus - { - IdMatch, IdMismatch - }; - typedef std::vector::const_iterator ReadIterator; + using ReadIterator = std::vector::const_iterator; SsbRead(std::istream& iStrm); @@ -319,7 +341,7 @@ public: void BeginRead(const ID &id, const uint64& nVersion); // After calling BeginRead(), this returns number of entries in the file. - NumType GetNumEntries() const {return m_nReadEntrycount;} + std::size_t GetNumEntries() const {return m_nReadEntrycount;} // Returns read iterator to the beginning of entries. // The behaviour of read iterators is undefined if map doesn't @@ -330,23 +352,23 @@ public: ReadIterator GetReadEnd(); // Compares given id with read entry id - IdMatchStatus CompareId(const ReadIterator& iter, const ID &id); + bool MatchesId(const ReadIterator& iter, const ID &id); uint64 GetReadVersion() {return m_nReadVersion;} // Read item using default read implementation. template - ReadRv ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem);} + bool ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem);} // Read item using given function. template - ReadRv ReadItem(T& obj, const ID &id, FuncObj); + bool ReadItem(T& obj, const ID &id, FuncObj); // Read item using read iterator. template - ReadRv ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem);} + bool ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem);} template - ReadRv ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func); + bool ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func); private: @@ -358,12 +380,14 @@ private: const ReadEntry* Find(const ID &id); // Called after reading an object. - ReadRv OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin); + void OnReadEntry(const ReadEntry* pE, const ID &id, const std::streamoff& posReadBegin); - void AddReadNote(const SsbStatus s); + void AddReadNote(const Status s); +#ifdef SSB_LOGGING // Called after reading entry. pRe is a pointer to associated map entry if exists. - void AddReadNote(const ReadEntry* const pRe, const NumType nNum); + void LogReadEntry(const ReadEntry &pRe, const std::size_t nNum); +#endif void ResetReadstatus(); @@ -383,13 +407,13 @@ private: std::vector mapData; // Read: Contains map information. uint64 m_nReadVersion; // Read: Version is placed here when reading. - RposType m_rposMapBegin; // Read: If map exists, rpos of map begin, else m_rposEndofHdrData. - Postype m_posMapEnd; // Read: If map exists, map end position, else pos of end of hdrData. - Postype m_posDataBegin; // Read: Data begin position. - RposType m_rposEndofHdrData; // Read: rpos of end of header data. - NumType m_nReadEntrycount; // Read: Number of entries. + std::streamoff m_rposMapBegin; // Read: If map exists, rpos of map begin, else m_rposEndofHdrData. + std::streamoff m_posMapEnd; // Read: If map exists, map end position, else pos of end of hdrData. + std::streamoff m_posDataBegin; // Read: Data begin position. + std::streamoff m_rposEndofHdrData; // Read: rpos of end of header data. + std::size_t m_nReadEntrycount; // Read: Number of entries. - NumType m_nNextReadHint; // Read: Hint where to start looking for the next read entry. + std::size_t m_nNextReadHint; // Read: Hint where to start looking for the next read entry. }; @@ -420,30 +444,34 @@ public: private: // Called after writing an item. - void OnWroteItem(const ID &id, const Postype& posBeforeWrite); + void OnWroteItem(const ID &id, const std::streamoff& posBeforeWrite); - void AddWriteNote(const SsbStatus s); - void AddWriteNote(const ID &id, - const NumType nEntryNum, - const DataSize nBytecount, - const RposType rposStart); + void AddWriteNote(const Status s); + +#ifdef SSB_LOGGING + void LogWriteEntry(const ID &id, + const std::size_t nEntryNum, + const std::size_t nBytecount, + const std::streamoff rposStart); +#endif // Writes mapping item to mapstream. void WriteMapItem(const ID &id, - const RposType& rposDataStart, - const DataSize& nDatasize, - const char* pszDesc); + const std::streamoff& rposDataStart, + const std::size_t& nDatasize, + const std::string &pszDesc); - void ResetWritestatus() {m_Status = SNT_NONE;} - - void IncrementWriteCounter(); + void ResetWritestatus() + { + m_Status = Status{}; + } private: std::ostream& oStrm; - Postype m_posEntrycount; // Write: Pos of entrycount field. - Postype m_posMapPosField; // Write: Pos of map position field. + std::streamoff m_posEntrycount; // Write: Pos of entrycount field. + std::streamoff m_posMapPosField; // Write: Pos of map position field. std::string m_MapStreamString; // Write: Map stream string. }; @@ -452,45 +480,53 @@ private: template void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func) { - const Postype pos = oStrm.tellp(); + const std::streamoff pos = static_cast(oStrm.tellp()); Func(oStrm, obj); OnWroteItem(id, pos); } template -SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func) +bool SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func) { const ReadEntry* pE = Find(id); - const Postype pos = iStrm.tellg(); - if (pE != nullptr || GetFlag(RwfRMapHasId) == false) + const std::streamoff pos = static_cast(iStrm.tellg()); + const bool entryFound = (pE || !m_Flags[RwfRMapHasId]); + if(entryFound) + { Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize); - return OnReadEntry(pE, id, pos); + } + OnReadEntry(pE, id, pos); + return entryFound; } template -SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func) +bool SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func) { iStrm.clear(); if (iter->rposStart != 0) - iStrm.seekg(m_posStart + Postype(iter->rposStart)); - const Postype pos = iStrm.tellg(); + iStrm.seekg(m_posStart + iter->rposStart); + const std::streamoff pos = static_cast(iStrm.tellg()); func(iStrm, obj, iter->nSize); - return OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos); + OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos); + return true; } -inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const ID &id) +inline bool SsbRead::MatchesId(const ReadIterator& iter, const ID &id) { - if(iter->nIdpos >= m_Idarray.size()) return IdMismatch; - return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)) ? IdMatch : IdMismatch; + if(iter->nIdpos >= m_Idarray.size()) + { + return false; + } + return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)); } inline SsbRead::ReadIterator SsbRead::GetReadBegin() { - MPT_ASSERT(GetFlag(RwfRMapHasId) && (GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0)); - if (GetFlag(RwfRMapCached) == false) + MPT_ASSERT(m_Flags[RwfRMapHasId] && (m_Flags[RwfRMapHasStartpos] || m_Flags[RwfRMapHasSize] || m_nFixedEntrySize > 0)); + if(!m_Flags[RwfRMapCached]) CacheMap(); return mapData.begin(); } @@ -498,7 +534,7 @@ inline SsbRead::ReadIterator SsbRead::GetReadBegin() inline SsbRead::ReadIterator SsbRead::GetReadEnd() { - if (GetFlag(RwfRMapCached) == false) + if(!m_Flags[RwfRMapCached]) CacheMap(); return mapData.end(); } diff --git a/Frameworks/OpenMPT/OpenMPT/common/stdafx.h b/Frameworks/OpenMPT/OpenMPT/common/stdafx.h index cf6645141..ebfff773b 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/stdafx.h +++ b/Frameworks/OpenMPT/OpenMPT/common/stdafx.h @@ -17,6 +17,11 @@ #include "openmpt/all/BuildSettings.hpp" +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + + #if defined(MODPLUG_TRACKER) #if defined(MPT_WITH_MFC) @@ -33,10 +38,10 @@ #include // cppcheck-suppress missingInclude #include -#ifdef MPT_MFC_FULL +#ifndef _AFX_NO_MFC_CONTROLS_IN_DIALOGS // cppcheck-suppress missingInclude #include -#endif // MPT_MFC_FULL +#endif // !_AFX_NO_MFC_CONTROLS_IN_DIALOGS // cppcheck-suppress missingInclude #include @@ -60,6 +65,7 @@ #include "mpt/base/span.hpp" +#include "mpt/check/compiler.hpp" #include "mpt/check/libc.hpp" #if defined(MPT_WITH_MFC) #include "mpt/check/mfc.hpp" @@ -67,8 +73,10 @@ #if MPT_OS_WINDOWS #include "mpt/check/windows.hpp" #endif -#include "mpt/exception_text/exception_text.hpp" +#include "mpt/exception/exception.hpp" +#include "mpt/exception/exception_text.hpp" #include "mpt/out_of_memory/out_of_memory.hpp" +#include "mpt/string/types.hpp" #include "mpt/system_error/system_error.hpp" #include "openmpt/base/Types.hpp" diff --git a/Frameworks/OpenMPT/OpenMPT/common/version.cpp b/Frameworks/OpenMPT/OpenMPT/common/version.cpp index e808e4336..ab10b1a9a 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/version.cpp +++ b/Frameworks/OpenMPT/OpenMPT/common/version.cpp @@ -10,12 +10,20 @@ #include "stdafx.h" #include "version.h" +#include "mpt/format/join.hpp" +#include "mpt/parse/parse.hpp" +#include "mpt/string/utility.hpp" + #include "mptString.h" #include "mptStringFormat.h" -#include "mptStringParse.h" #include "versionNumber.h" + +#if __has_include("svn_version.h") #include "svn_version.h" +#else +#include "../build/svn_version/svn_version.h" +#endif @@ -47,10 +55,10 @@ mpt::ustring Version::GetOpenMPTVersionString() const Version Version::Parse(const mpt::ustring &s) { uint32 result = 0; - std::vector numbers = mpt::String::Split(s, U_(".")); + std::vector numbers = mpt::split(s, U_(".")); for (std::size_t i = 0; i < numbers.size() && i < 4; ++i) { - result |= (mpt::String::Parse::Hex(numbers[i]) & 0xff) << ((3 - i) * 8); + result |= (mpt::parse_hex(numbers[i]) & 0xff) << ((3 - i) * 8); } return Version(result); } @@ -137,7 +145,7 @@ static int GetRevision() { svnversion = svnversion.substr(0, svnversion.find("P")); } - return ConvertStrTo(svnversion); + return mpt::parse(svnversion); #else MPT_WARNING_STATEMENT("SVN revision unknown. Please check your build system."); return 0; @@ -273,14 +281,14 @@ VersionWithRevision VersionWithRevision::Parse(const mpt::ustring &s) { Version version = Version::Parse(mpt::ustring()); uint64 revision = 0; - const auto tokens = mpt::String::Split(s, U_("-")); + const auto tokens = mpt::split(s, U_("-")); if(tokens.size() >= 1) { version = Version::Parse(tokens[0]); } if(tokens.size() >= 2) { - revision = ConvertStrTo(tokens[1].substr(1)); + revision = mpt::parse(tokens[1].substr(1)); } return {version, revision}; } @@ -513,7 +521,7 @@ mpt::ustring GetVersionString(FlagSet strings) { result.push_back(GetBuildFeaturesString()); } - return mpt::trim(mpt::String::Combine(result, U_(""))); + return mpt::trim(mpt::join_format(result, U_(""))); } mpt::ustring GetVersionStringPure() @@ -770,10 +778,10 @@ mpt::ustring GetFullCreditsString() "Daniel Collin (emoon/TBL) for providing test infrastructure\n" "https://twitter.com/daniel_collin\n" "\n" - "The people at ModPlug forums for crucial contribution\n" + "The people in the ModPlug community for crucial contribution\n" "in the form of ideas, testing and support;\n" "thanks particularly to:\n" - "33, 8bitbubsy, Anboi, BooT-SectoR-ViruZ, Bvanoudtshoorn\n" + "33, 8bitbubsy, AliceLR, Anboi, BooT-SectoR-ViruZ, Bvanoudtshoorn\n" "christofori, cubaxd, Diamond, Ganja, Georg, Goor00,\n" "Harbinger, jmkz, KrazyKatz, LPChip, Nofold, Rakib, Sam Zen\n" "Skaven, Skilletaudio, Snu, Squirrel Havoc, Teimoso, Waxhead\n" diff --git a/Frameworks/OpenMPT/OpenMPT/common/version.h b/Frameworks/OpenMPT/OpenMPT/common/version.h index e814de587..a734d1f96 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/version.h +++ b/Frameworks/OpenMPT/OpenMPT/common/version.h @@ -79,7 +79,7 @@ public: return m_Version; } - MPT_FORCEINLINE Version Masked(uint32 mask) const noexcept + MPT_CONSTEXPRINLINE Version Masked(uint32 mask) const noexcept { return Version(m_Version & mask); } @@ -205,7 +205,7 @@ MPT_CONSTEXPRINLINE bool operator > (const Version &a, const Version &b) noexcep } -MPT_CONSTEXPRINLINE Version operator "" _LiteralVersionImpl (const char * str, std::size_t len) +MPT_CONSTEVAL Version operator "" _LiteralVersionImpl (const char * str, std::size_t len) { return Version::LiteralParser::Parse(str, len); } @@ -213,7 +213,7 @@ MPT_CONSTEXPRINLINE Version operator "" _LiteralVersionImpl (const char * str, s // Create Version object from version string and check syntax, all at compile time. // cppcheck false-positive // cppcheck-suppress preprocessorErrorDirective -#define MPT_V(strver) MPT_FORCE_CONSTEXPR(Version{( strver ## _LiteralVersionImpl ).GetRawVersion()}) +#define MPT_V(strver) MPT_FORCE_CONSTEVAL_VALUE(Version{( strver ## _LiteralVersionImpl ).GetRawVersion()}) diff --git a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h index de55b06e8..2e0fc75d0 100644 --- a/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h +++ b/Frameworks/OpenMPT/OpenMPT/common/versionNumber.h @@ -16,8 +16,8 @@ OPENMPT_NAMESPACE_BEGIN // Version definitions. The only thing that needs to be changed when changing version number. #define VER_MAJORMAJOR 1 -#define VER_MAJOR 30 -#define VER_MINOR 10 +#define VER_MAJOR 31 +#define VER_MINOR 01 #define VER_MINORMINOR 00 OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict index e920f5059..ba8527e2e 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict +++ b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict @@ -1,8 +1,11 @@ +667="gf" + 669="if" 669="JN" amf="ASYLUM Music Format V1.0\x00" amf="AMF\x0A" +amf="DMF\x0E" ams="Extreme" ams="AMShdr\x1A\x02\x02" @@ -34,6 +37,8 @@ dmf="SMPD" dsm="RIFF" dsm="DSMF" +dsm="DSm\x1A " + dsym="\x02\x01\x13\x13\x14\x12\x01\x0B\x01" dtm="D.T." @@ -51,6 +56,26 @@ fmt="FMTracker\x01\x01" gdm="GDM\xFE" gdm="GMFS" +gtk="GTK\x04" + +gt2="GT2\x05" +gt2="XCOM" +gt2="TCN1" +gt2="TCN2" +gt2="TVOL" +gt2="MIXP" +#gt2="SONG" +gt2="PATS" +gt2="PATD" +gt2="TNAM" +#gt2="INST" +#gt2="VENV" +gt2="TENV" +#gt2="PENV" +#gt2="SAMP" +gt2="SAM2" +gt2="ENDC" + imf="IM10" imf="IS10" diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c index 653dab6d6..25095773a 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c +++ b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c @@ -25,6 +25,26 @@ static int16_t buffer[BUFFERSIZE]; +static int ErrFunc (int error, void *) +{ + switch (error) + { + case OPENMPT_ERROR_INVALID_ARGUMENT: + case OPENMPT_ERROR_OUT_OF_RANGE: + case OPENMPT_ERROR_LENGTH: + case OPENMPT_ERROR_DOMAIN: + case OPENMPT_ERROR_LOGIC: + case OPENMPT_ERROR_UNDERFLOW: + case OPENMPT_ERROR_OVERFLOW: + case OPENMPT_ERROR_RANGE: + case OPENMPT_ERROR_RUNTIME: + case OPENMPT_ERROR_EXCEPTION: + abort(); + default: + return OPENMPT_ERROR_FUNC_RESULT_NONE; + } +} + int main( int argc, char * argv[] ) { static FILE * file = NULL; static openmpt_module * mod = NULL; @@ -35,11 +55,17 @@ int main( int argc, char * argv[] ) { __AFL_INIT(); #endif file = fopen( argv[1], "rb" ); - mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL ); + mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, NULL, NULL, ErrFunc, NULL, NULL, NULL, NULL ); fclose( file ); - if ( mod == NULL ) return 1; + if ( mod == NULL ) + return 1; + + // verify API contract : If the file can be loaded, header probing must be successful too. + if ( openmpt_probe_file_header_from_stream( OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, openmpt_stream_get_file_callbacks(), file, NULL, NULL, ErrFunc, NULL, NULL, NULL ) == OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE ) + abort(); + openmpt_module_ctl_set( mod, "render.resampler.emulate_amiga", (openmpt_module_get_num_orders( mod ) & 1) ? "0" : "1" ); - /* render about a second of the module for fuzzing the actual mix routines */ + // render about a second of the module for fuzzing the actual mix routines for(; i < 50; i++) { count = openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer ); if ( count == 0 ) { @@ -51,7 +77,7 @@ int main( int argc, char * argv[] ) { openmpt_module_set_position_order_row( mod, 3, 16 ); openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer ); - /* fuzz string-related stuff */ + // fuzz string-related stuff openmpt_free_string ( openmpt_module_get_metadata( mod, "date" ) ); openmpt_free_string ( openmpt_module_get_metadata( mod, "message" ) ); openmpt_module_destroy( mod ); diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md index bb19163ec..e67be227b 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md +++ b/Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md @@ -13,7 +13,7 @@ Contents: * `fuzz-secondary[1|2].sh`: Scripts to launch the secondary fuzzing process. It is recommended to run at least two fuzzer instances, as the deterministic and random fuzz mode have been found to complement each other really well. The two - scripts are set up to use different exploration strategies + scripts are set up to use different exploration strategies. * `fuzz-settings.sh`: Set up your preferences and afl settings here before the first run. * `fuzz.c`: A tiny C program that is used by the fuzzer to test libopenmpt. @@ -45,7 +45,7 @@ How to use * Run `fuzz-main.sh` for the first (deterministic) instance of afl-fuzz. * For a "secondary" instance to run on another core, run `fuzz-secondary1.sh` and/or `fuzz-secondary2.sh`. -* If you want to make use of even more cores, create more copies +* If you want to make use of even more cores, create more copies of `fuzz-secondary2.sh` and adjust "infile03" / "fuzzer03" to - "infile04" / "fuzzer04" and so o (they need to be unique). Try variying the + "infile04" / "fuzzer04" and so on (they need to be unique). Try varying the fuzzing strategey (the -p parameter) to get results more quickly. diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug.c b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug.c index 51dd3d79f..f45f5f97c 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug.c +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug.c @@ -7,18 +7,10 @@ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ -#ifndef NO_LIBMODPLUG - #ifdef LIBOPENMPT_BUILD_DLL #undef LIBOPENMPT_BUILD_DLL #endif -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* _MSC_VER */ - #include #include @@ -29,19 +21,13 @@ #include #define MODPLUG_BUILD -#ifdef _MSC_VER -#ifdef MPT_BUILD_MSVC_SHARED -#define DLL_EXPORT -#endif /* MPT_BUILD_MSVC_SHARED */ -#ifdef MPT_BUILD_MSVC_STATIC + +#if defined(_WIN32) || defined(__CYGWIN__) #define MODPLUG_STATIC -#endif /* MPT_BUILD_MSVC_STATIC */ -#endif /* _MSC_VER */ -#ifdef _MSC_VER -#define LIBOPENMPT_MODPLUG_API -#else /* !_MSC_VER */ -#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT -#endif /* _MSC_VER */ +#endif /* _WIN32 || __CYGWIN__ */ + +#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_PUBLIC + #include "libmodplug/modplug.h" /* from libmodplug/sndfile.h */ @@ -600,5 +586,3 @@ LIBOPENMPT_MODPLUG_API char ModPlug_ExportIT(ModPlugFile* file, const char* file fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportIT(%s) not implemented.\n",filepath); return 0; } - -#endif /* NO_LIBMODPLUG */ diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug_cpp.cpp b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug_cpp.cpp index fd5375d3b..95fecdb85 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug_cpp.cpp +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/libopenmpt_modplug_cpp.cpp @@ -7,8 +7,6 @@ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ -#ifndef NO_LIBMODPLUG - /* *********************************************************************** @@ -23,19 +21,6 @@ Metadata and other state is not provided or updated. */ -#ifdef UNICODE -#undef UNICODE -#endif -#ifdef _UNICODE -#undef _UNICODE -#endif - -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* _MSC_VER */ - #include #include @@ -47,15 +32,13 @@ Metadata and other state is not provided or updated. #include #define MODPLUG_BUILD -#ifdef _MSC_VER -/* libmodplug C++ header is broken for MSVC DLL builds */ + +#if defined(_WIN32) || defined(__CYGWIN__) #define MODPLUG_STATIC -#endif /* _MSC_VER */ -#ifdef _MSC_VER -#define LIBOPENMPT_MODPLUG_API -#else /* !_MSC_VER */ -#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT -#endif /* _MSC_VER */ +#endif /* _WIN32 || __CYGWIN__ */ + +#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_PUBLIC + class LIBOPENMPT_MODPLUG_API CSoundFile; #include "libmodplug/stdafx.h" #include "libmodplug/sndfile.h" @@ -882,6 +865,3 @@ UINT CSoundFile::Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lm #elif defined(_MSC_VER) #pragma warning(pop) #endif - - -#endif // NO_LIBMODPLUG diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug.c b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug.c index 51dd3d79f..f45f5f97c 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug.c +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug.c @@ -7,18 +7,10 @@ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ -#ifndef NO_LIBMODPLUG - #ifdef LIBOPENMPT_BUILD_DLL #undef LIBOPENMPT_BUILD_DLL #endif -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* _MSC_VER */ - #include #include @@ -29,19 +21,13 @@ #include #define MODPLUG_BUILD -#ifdef _MSC_VER -#ifdef MPT_BUILD_MSVC_SHARED -#define DLL_EXPORT -#endif /* MPT_BUILD_MSVC_SHARED */ -#ifdef MPT_BUILD_MSVC_STATIC + +#if defined(_WIN32) || defined(__CYGWIN__) #define MODPLUG_STATIC -#endif /* MPT_BUILD_MSVC_STATIC */ -#endif /* _MSC_VER */ -#ifdef _MSC_VER -#define LIBOPENMPT_MODPLUG_API -#else /* !_MSC_VER */ -#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT -#endif /* _MSC_VER */ +#endif /* _WIN32 || __CYGWIN__ */ + +#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_PUBLIC + #include "libmodplug/modplug.h" /* from libmodplug/sndfile.h */ @@ -600,5 +586,3 @@ LIBOPENMPT_MODPLUG_API char ModPlug_ExportIT(ModPlugFile* file, const char* file fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportIT(%s) not implemented.\n",filepath); return 0; } - -#endif /* NO_LIBMODPLUG */ diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug_cpp.cpp b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug_cpp.cpp index fd5375d3b..95fecdb85 100644 --- a/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug_cpp.cpp +++ b/Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/libopenmpt_modplug_cpp.cpp @@ -7,8 +7,6 @@ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ -#ifndef NO_LIBMODPLUG - /* *********************************************************************** @@ -23,19 +21,6 @@ Metadata and other state is not provided or updated. */ -#ifdef UNICODE -#undef UNICODE -#endif -#ifdef _UNICODE -#undef _UNICODE -#endif - -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#endif /* _MSC_VER */ - #include #include @@ -47,15 +32,13 @@ Metadata and other state is not provided or updated. #include #define MODPLUG_BUILD -#ifdef _MSC_VER -/* libmodplug C++ header is broken for MSVC DLL builds */ + +#if defined(_WIN32) || defined(__CYGWIN__) #define MODPLUG_STATIC -#endif /* _MSC_VER */ -#ifdef _MSC_VER -#define LIBOPENMPT_MODPLUG_API -#else /* !_MSC_VER */ -#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT -#endif /* _MSC_VER */ +#endif /* _WIN32 || __CYGWIN__ */ + +#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_PUBLIC + class LIBOPENMPT_MODPLUG_API CSoundFile; #include "libmodplug/stdafx.h" #include "libmodplug/sndfile.h" @@ -882,6 +865,3 @@ UINT CSoundFile::Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lm #elif defined(_MSC_VER) #pragma warning(pop) #endif - - -#endif // NO_LIBMODPLUG diff --git a/Frameworks/OpenMPT/OpenMPT/contrib/premake/snapshot-premake-master.sh b/Frameworks/OpenMPT/OpenMPT/contrib/premake/snapshot-premake-master.sh new file mode 100644 index 000000000..5d503d7b3 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/contrib/premake/snapshot-premake-master.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +rm -rf premake.git +git clone --recursive https://github.com/premake/premake-core.git premake.git +cd premake.git +make -f Bootstrap.mak linux +echo | bin/release/premake5 package master source + +echo "Done." diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c.c index 8d06ef45d..a6401b477 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c.c @@ -11,6 +11,21 @@ * Usage: libopenmpt_example_c SOMEMODULE */ +#if defined( unix ) || defined( __unix__ ) || defined( __unix ) +#include +#if defined( _POSIX_VERSION ) +#if ( _POSIX_VERSION > 0 ) +#ifndef POSIX +#define POSIX +#endif +#endif +#endif +#endif + +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -18,9 +33,36 @@ #include #include +#if OPENMPT_API_VERSION_AT_LEAST( 0, 7, 0 ) +#if defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW ) && defined( __MINGW32__ ) +#include +#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT ) && ( defined( _MSC_VER ) || ( defined( __clang__ ) && defined( _WIN32 ) ) ) +#include +#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX ) && defined( POSIX ) && defined( _POSIX_C_SOURCE ) +#if ( _POSIX_C_SOURCE > 200112L ) +#include +#else #include +#endif +#else +#include +#endif +#else +#include +#endif +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif #include +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic pop +#endif + +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ #define BUFFERSIZE 480 #define SAMPLERATE 48000 @@ -72,6 +114,15 @@ static void libopenmpt_example_print_error( const char * func_name, int mod_err, } } +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -80,6 +131,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ int result = 0; FILE * file = 0; @@ -114,7 +170,24 @@ int main( int argc, char * argv[] ) { goto fail; } +#if OPENMPT_API_VERSION_AT_LEAST( 0, 7, 0 ) +#if defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW ) && defined( __MINGW32__ ) + mod = openmpt_module_create2( openmpt_stream_get_file_mingw_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT ) && ( defined( _MSC_VER ) || ( defined( __clang__ ) && defined( _WIN32 ) ) ) + mod = openmpt_module_create2( openmpt_stream_get_file_msvcrt_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#elif defined( LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX ) && defined( POSIX ) && defined( _POSIX_C_SOURCE ) +#if ( _POSIX_C_SOURCE > 200112L ) + mod = openmpt_module_create2( openmpt_stream_get_file_posix_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#else + mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#endif +#else + mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#endif +#else mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); +#endif + if ( !mod ) { libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str ); openmpt_free_string( mod_err_str ); diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_mem.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_mem.c index 6fcd17a9e..263a73b65 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_mem.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_mem.c @@ -11,6 +11,10 @@ * Usage: libopenmpt_example_c_mem SOMEMODULE */ +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -19,7 +23,18 @@ #include +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif #include +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic pop +#endif + +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ #define BUFFERSIZE 480 #define SAMPLERATE 48000 @@ -163,6 +178,15 @@ cleanup: return result; } +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -171,6 +195,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ int result = 0; blob_t * blob = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_pipe.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_pipe.c index c444893e0..2544dc650 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_pipe.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_pipe.c @@ -22,6 +22,10 @@ #include #include +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ + #define BUFFERSIZE 480 #define SAMPLERATE 48000 @@ -84,6 +88,15 @@ static ssize_t xwrite( int fd, const void * buffer, size_t size ) { static int16_t buffer[BUFFERSIZE * 2]; +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -92,6 +105,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ int result = 0; openmpt_module * mod = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_probe.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_probe.c index 058a7e1e3..348e4b093 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_probe.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_probe.c @@ -19,6 +19,10 @@ #define LIBOPENMPT_EXAMPLE_PROBE_RESULT LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -28,6 +32,10 @@ #include #include +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ + static void libopenmpt_example_logfunc( const char * message, void * userdata ) { (void)userdata; @@ -78,7 +86,7 @@ static int probe_file( const char * filename ) { } #if ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_BINARY ) - probe_file_header_result = openmpt_probe_file_header_from_stream( OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL ); + probe_file_header_result = openmpt_probe_file_header_from_stream( OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL ); probe_file_header_result_str = NULL; switch ( probe_file_header_result ) { case OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS: @@ -117,7 +125,7 @@ static int probe_file( const char * filename ) { result = 1; } #elif ( LIBOPENMPT_EXAMPLE_PROBE_RESULT == LIBOPENMPT_EXAMPLE_PROBE_RESULT_FLOAT ) - probability = openmpt_could_open_probability2( openmpt_stream_get_file_callbacks(), file, 0.25, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL ); + probability = openmpt_could_open_probability2( openmpt_stream_get_file_callbacks2(), file, 0.25, &libopenmpt_example_logfunc, NULL, &openmpt_error_func_default, NULL, &mod_err, NULL ); #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) fprintf( stdout, "%s: %f - %ls\n", "Result", probability, filename ); #else @@ -148,6 +156,15 @@ cleanup: return result; } +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -156,6 +173,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ int global_result = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_stdout.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_stdout.c index 664032fd1..d80332597 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_stdout.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_stdout.c @@ -11,6 +11,10 @@ * Usage: libopenmpt_example_c_stdout SOMEMODULE | aplay --file-type raw --format=dat */ +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -23,6 +27,10 @@ #include #include +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ + #define BUFFERSIZE 480 #define SAMPLERATE 48000 @@ -85,6 +93,15 @@ static ssize_t xwrite( int fd, const void * buffer, size_t size ) { static int16_t buffer[BUFFERSIZE * 2]; +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -93,6 +110,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ int result = 0; FILE * file = 0; @@ -125,7 +147,7 @@ int main( int argc, char * argv[] ) { goto fail; } - mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); + mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, &libopenmpt_example_logfunc, NULL, &libopenmpt_example_errfunc, NULL, &mod_err, &mod_err_str, NULL ); if ( !mod ) { libopenmpt_example_print_error( "openmpt_module_create2()", mod_err, mod_err_str ); openmpt_free_string( mod_err_str ); diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c index c2e0651c8..0512c5199 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_c_unsafe.c @@ -12,6 +12,10 @@ * CAUTION: This simple example does no error cheking at all. */ +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -21,7 +25,18 @@ #include #include +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif #include +#if defined( __GNUC__ ) && !defined( __clang__ ) && !defined( _MSC_VER ) +#pragma GCC diagnostic pop +#endif + +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ #define BUFFERSIZE 480 #define SAMPLERATE 48000 @@ -30,6 +45,15 @@ static int16_t left[BUFFERSIZE]; static int16_t right[BUFFERSIZE]; static int16_t * const buffers[2] = { left, right }; +#if defined( __DJGPP__ ) +/* clang-format off */ +int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __clang__ ) && !defined( _MSC_VER ) int wmain( int argc, wchar_t * argv[] ); @@ -38,6 +62,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ FILE * file = 0; openmpt_module * mod = 0; size_t count = 0; @@ -48,7 +77,7 @@ int main( int argc, char * argv[] ) { #else file = fopen( argv[1], "rb" ); #endif - mod = openmpt_module_create2( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + mod = openmpt_module_create2( openmpt_stream_get_file_callbacks2(), file, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); fclose( file ); Pa_Initialize(); Pa_OpenDefaultStream( &stream, 0, 2, paInt16 | paNonInterleaved, SAMPLERATE, paFramesPerBufferUnspecified, NULL, NULL ); diff --git a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_cxx.cpp b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_cxx.cpp index 81a140c34..0b456e576 100644 --- a/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_cxx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/examples/libopenmpt_example_cxx.cpp @@ -11,6 +11,10 @@ * Usage: libopenmpt_example_cxx SOMEMODULE */ +#if defined( __MINGW32__ ) && !defined( __MINGW64__ ) +#include +#endif + #include #include #include @@ -33,6 +37,19 @@ #endif #endif +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ + +#if defined( __DJGPP__ ) +/* clang-format off */ +extern "C" int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +/* clang-format on */ +#endif /* __DJGPP__ */ #if ( defined( _WIN32 ) || defined( WIN32 ) ) && ( defined( _UNICODE ) || defined( UNICODE ) ) #if defined( __GNUC__ ) || ( defined( __clang__ ) && !defined( _MSC_VER ) ) // mingw-w64 g++ does only default to special C linkage for "main", but not for "wmain" (see ). @@ -44,6 +61,11 @@ int wmain( int argc, wchar_t * argv[] ) { #else int main( int argc, char * argv[] ) { #endif +#if defined( __DJGPP__ ) + /* clang-format off */ + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + /* clang-format on */ +#endif /* __DJGPP__ */ try { if ( argc != 2 ) { throw std::runtime_error( "Usage: libopenmpt_example_cxx SOMEMODULE" ); diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt index 357607664..ff728e876 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/OpenMPT.txt @@ -2,3 +2,5 @@ minimp3 library from https://github.com/lieff/minimp3 commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27) The following changes have been made: * minimp3.c has been added + * some warnings have been fixed + * all modifications are marked by /* OpenMPT */ diff --git a/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h b/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h index 3220ae1a8..0ed72088f 100644 --- a/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h +++ b/Frameworks/OpenMPT/OpenMPT/include/minimp3/minimp3.h @@ -176,7 +176,11 @@ end: #define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) #define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) typedef float32x4_t f4; +#if 1 /* OpenMPT */ +static int have_simd(void) +#else /* OpenMPT */ static int have_simd() +#endif /* OpenMPT */ { /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ return 1; } diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/Doxyfile b/Frameworks/OpenMPT/OpenMPT/libopenmpt/Doxyfile index aa13040bc..bd3aad5f1 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/Doxyfile +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.9.1 +# Doxyfile 1.9.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,15 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -60,16 +69,28 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = bin/docs -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +102,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -248,16 +261,16 @@ TAB_SIZE = 2 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = @@ -302,8 +315,8 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files @@ -450,13 +463,13 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, -# which efficively disables parallel processing. Please report any issues you +# which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. @@ -575,7 +588,7 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On @@ -600,6 +613,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -757,7 +776,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -803,18 +823,26 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO @@ -834,13 +862,27 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -854,22 +896,26 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = libopenmpt/dox/index.dox \ +INPUT = doc/libopenmpt/index.dox \ README.md \ - libopenmpt/dox/dependencies.md \ - libopenmpt/dox/gettingstarted.md \ - libopenmpt/dox/packaging.md \ + doc/libopenmpt/dependencies.md \ + doc/libopenmpt/gettingstarted.md \ + doc/libopenmpt/packaging.md \ doc/contributing.md \ doc/libopenmpt_styleguide.md \ doc/openmpt_styleguide.md \ - libopenmpt/dox/tests.md \ - libopenmpt/dox/changelog.md \ + doc/libopenmpt/tests.md \ + doc/libopenmpt/changelog.md \ doc/module_formats.md \ libopenmpt/libopenmpt.hpp \ libopenmpt/libopenmpt.h \ libopenmpt/libopenmpt_stream_callbacks_buffer.h \ libopenmpt/libopenmpt_stream_callbacks_fd.h \ libopenmpt/libopenmpt_stream_callbacks_file.h \ + libopenmpt/libopenmpt_stream_callbacks_file_mingw.h \ + libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h \ + libopenmpt/libopenmpt_stream_callbacks_file_posix.h \ + libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h \ libopenmpt/libopenmpt_config.h \ libopenmpt/libopenmpt_version.h \ libopenmpt/libopenmpt_ext.hpp \ @@ -897,10 +943,10 @@ INPUT_ENCODING = UTF-8 # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -939,7 +985,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test +# ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* @@ -1134,9 +1180,11 @@ VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. # The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_ADD_INC_PATHS = YES @@ -1271,7 +1319,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1281,7 +1329,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1363,6 +1411,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1388,8 +1443,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1548,16 +1607,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1582,6 +1653,13 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for @@ -1630,11 +1708,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1647,15 +1743,21 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = @@ -1835,29 +1937,31 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1902,8 +2006,7 @@ USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1916,16 +2019,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -2006,16 +2099,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -2112,15 +2195,6 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- @@ -2207,7 +2281,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2299,15 +2374,6 @@ EXTERNAL_PAGES = YES # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = YES - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2364,11 +2430,14 @@ DOT_FONTSIZE = 10 DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. CLASS_GRAPH = YES @@ -2382,7 +2451,8 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2497,6 +2567,13 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: @@ -2504,10 +2581,9 @@ DIRECTORY_GRAPH = YES # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, -# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, -# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, +# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, +# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2552,10 +2628,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2617,6 +2693,8 @@ DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2625,8 +2703,8 @@ GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # -# Note: This setting is not only used for dot files but also for msc and -# plantuml temporary files. +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. DOT_CLEANUP = YES diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi index 8cfda23d2..41c754e48 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt.bi @@ -469,13 +469,13 @@ Const OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT = OPENMPT_PROBE_FILE_HEADER_FLAGS_ '* Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE = 0 -'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 +'* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file will most likely be supported by libopenmpt. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS = 1 -'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 +'* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file is not supported by libopenmpt. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE = 0 -'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 +'* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An answer could not be determined with the amount of data provided. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA = -1 -'* Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 +'* Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An internal error occurred. \since 0.3.0 Const OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR = -255 /'* \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it @@ -1076,9 +1076,18 @@ Declare Function openmpt_module_get_current_speed(ByVal module As openmpt_module \param module The module handle to work on. \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + \deprecated Please use openmpt_module_get_current_tempo2(). '/ Declare Function openmpt_module_get_current_tempo(ByVal module As openmpt_module Ptr) As Long +/'* \brief Get the current tempo + + \param module The module handle to work on. + \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + \since 0.7.0 +'/ +Declare Function openmpt_module_get_current_tempo2(ByVal module As openmpt_module Ptr) As Long + /'* \brief Get the current order \param module The module handle to work on. @@ -1357,11 +1366,11 @@ Declare Function openmpt_module_highlight_pattern_row_channel_ Alias "openmpt_mo - load.skip_patterns: Set to "1" to avoid loading patterns into memory - load.skip_plugins: Set to "1" to avoid loading plugins - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - - seek.sync_samples: Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. + - seek.sync_samples: Set to "0" to not sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. - - play.at_end: Chooses the behaviour when the end of song is reached: + - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt_module_set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. + - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumsed from the song start). - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo. - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt_ext.bi b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt_ext.bi index 07d869fc7..1edca98d3 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt_ext.bi +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/bindings/freebasic/libopenmpt_ext.bi @@ -134,6 +134,7 @@ Type openmpt_module_ext_interface_interactive \return 1 on success, 0 on failure. \remarks The tempo may be reset by pattern commands at any time. Use set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt_module_get_current_tempo + \deprecated Please use openmpt_module_ext_interface_interactive3.set_current_tempo2(). '/ set_current_tempo As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal tempo As Long) As Long @@ -348,6 +349,23 @@ Type openmpt_module_ext_interface_interactive2 get_note_finetune As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal channel As Long) As Double End Type +#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 "interactive3" + +Type openmpt_module_ext_interface_interactive3 + + /'* Set the current module tempo + + \param mod_ext The module handle to work on. + \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. + \return 1 on success, 0 on failure. + \remarks The tempo may be reset by pattern commands at any time. Use set_tempo_factor to apply a tempo factor that is independent of pattern commands. + \sa openmpt_module_get_current_tempo2 + \since 0.7.0 + '/ + set_current_tempo As Function(ByVal mod_ext As openmpt_module_ext Ptr, ByVal tempo As Double) As Long + +End Type + End Extern /'* \brief Construct an openmpt_module_ext diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/in_openmpt.txt b/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/in_openmpt.txt index 94ef4095b..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/in_openmpt.txt +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/in_openmpt.txt @@ -1,17 +0,0 @@ - -in_openmpt -========== - -in_openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input -plugin for Winamp >= 2.0 (or compatible players). in_openmpt is based on -libopenmpt. - - -Installation ------------- - -"in_openmpt.dll" must be placed into the Winamp "Plugins" directory, and -"openmpt-mpg123.dll" must be placed into the Winamp directory. - - -See https://lib.openmpt.org/ for documentation, FAQ and other details. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/xmp-openmpt.txt b/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/xmp-openmpt.txt index 6720bee2d..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/xmp-openmpt.txt +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/doc/xmp-openmpt.txt @@ -1,16 +0,0 @@ - -xmp-openmpt -=========== - -xmp-openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input -plugin for XMPlay >= 3.8.0.0. xmp-openmpt is based on libopenmpt. - - -Installation ------------- - -"xmp-openmpt.dll" and "openmpt-mpg123.dll" must both be placed into the XMPlay -plugins directory. - - -See https://lib.openmpt.org/ for documentation, FAQ and other details. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md index da0045bbb..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/changelog.md @@ -1,1115 +0,0 @@ - -Changelog {#changelog} -========= - -For fully detailed change log, please see the source repository directly. This -is just a high-level summary. - -### libopenmpt 0.6.8 (2023-01-29) - - * [**Bug**] DSYM: Loading DSYM files got broken in 0.6.7. - - * When seeking around in a module, the tempo was sometimes incorrectly limited - to 255 BPM. - * Initial instrument cutoff was broken for OPL instruments in - libopenmnpt 0.6.7. - - * mpg123: Update to v1.31.2 (2023-01-14). - -### libopenmpt 0.6.7 (2023-01-08) - - * [**Bug**] openmpt123: openmpt123 crashed on Windows 9x when showing any - console output. - - * IT: In sample mode, portamento to a different sample turns off the filter if - cutoff / resonance was previously 127 / 0. - * S3M Detect files saved with Graoumf Tracker instead of claiming they were - made with OpenMPT 4.47. - * S3M: Pattern loop state was not propagated anymore since libopenmpt 0.6.0, - leading to wrong song length calculation and SB0 + SBx being located on - different channels not working properly anymore. - - * mpg123: Update to v1.31.1 (2022-11-01). - * FLAC: Update to v1.4.2 (2022-10-22). - * pugixml: Update to v1.13 (2022-11-02). - -### libopenmpt 0.6.6 (2022-09-25) - - * [**Sec**] Possible crash when playing manipulated IT / MPTM files with a T00 - command. (r17789) - - * MTM: In MultiTracker, setting speed and tempo are mutually exclusive - commands. Still, some MultiTracker modules were made to be played with - external players such as DMP, so they actually rely on "standard" speed / - tempo behaviour. Decide which behaviour to use by checking of speed and - tempo commands are found on the same row. - * MTM: Ignore sample loops if the loop end is <= 2. - * Echo DMO: Migrate left and right delay values in modules made with OpenMPT - versions between 1.27.01.00 and 1.30.05.00 to the correct interpretation. - - * FLAC: Update to v1.4.1 (2022-09-22). - -### libopenmpt 0.6.5 (2022-08-21) - - * [**Bug**] `Makefile` now also uses `CC`, `CXX`, `LD`, and `AR` when set as - environment variables. - * [**Bug**] libopenmpt can now be built to target macOS down to version 10.13 - again. - - * [**New**] `Makefile` now uses `PKG_CONFIG` as path to `pkg-config`. - - * DBM: Sample middle-C frequencies were slightly off. - laffik_-_marynarze.dbm sounds much more bearable now. - * DBM: Fixed pattern break parameter interpretation. - * Echo DMO: Setting the delay parameter to 0 yielded a 2-second echo delay - instead of 1ms. - * Digi Booster Echo: Setting the delay parameter to 0 yielded a 510ms echo - delay instead of approximately 334ms. - - * mpg123: Update to v1.30.2 (2022-08-01). - -### libopenmpt 0.6.4 (2022-06-12) - - * [**Bug**] openmpt123: Linking failed when using Autotools build system - targeting MinGW. - * [**Bug**] tests: Linking failed when using Autotools build system targeting - MinGW. - * [**Bug**] examples: Linking failed when using Autotools build system - targeting MinGW. - - * [**Change**] Support for mingw-std-threads when building for MinGW targets - is now deprecated because this is not supported for GCC 11 or later (see - ). - - * Ping-pong sample loops sometimes stopped playing at the end of the loop. - -### libopenmpt 0.6.3 (2022-04-24) - - * Pitch / Pan Separation and Random Variation instrument properties were not - resetting properly when seeking, potentially causing instruments to be - played e.g. at a vastly different pan position compared to playing the - module continuously. - * MED: Stereo samples were not imported correctly. - - * zlib: Update to v1.2.12 (2022-03-27). - -### libopenmpt 0.6.2 (2022-03-13) - - * [**Sec**] Possible out-of-bounds write in malformed IT / XM / MPTM files - using the internal LFO plugin. (r17076) - * [**Sec**] Possible out-of-bounds read when using Amiga BLEP interpolation - with extremely high-pitched notes. (r17078, r17079) - - * ISO-8859-1-related charsets from Amiga OS and RISC OS are now handled more - accurately, thus avoiding some unwanted control characters. - * MO3: Pattern indices 254 / 255 were not treated as playable patterns even if - the original file was a MOD / XM. - * Correctly apply ST3-style effect memory when seeking in S3M files. - * Command S (S3M / IT style) effect memory was not applied when seeking. - * Initial channel mute status was not reported correctly in `get_channel_mute_status` - since libopenmpt 0.6.0. - - * FLAC: Update to v1.3.4 (2022-02-21). - * pugixml: Update to v1.12.1 (2022-02-16). - -### libopenmpt 0.6.1 (2022-01-30) - - * [**Bug**] Linking libmpg123 no longer fails on OpenBSD. - * [**Bug**] Possible hang with malformed DMF, DSM, MED, MUS, OKT and SymMOD - files containing 65536 or more patterns when destroying the module. - * [**Bug**] Avoid NaNs and infinite values with custom tunings and in the - I3DL2Reverb plugin. - - * MIDI macros are now evaluated when seeking. - * The letter "z" is now evaluated in fixed MIDI macros (Z80...ZFF) the same - way as in Impulse Tracker. - * MOD: Loosened VBlank timing heuristics so that "frame of mind" by Dascon - plays correctly. - * MOD: Validate the contents of "hidden" patterns beyond the end of the order - list when the file size matches the expected size when only taken "official" - patterns into account. This fixes Shofixti Ditty.mod from Star Control 2 - while keeping other (partly broken) modules working. - * MED: Command 20 (reverse sample) is now only applied when it's next to a - note. - * S3M: Introducing the "Send OPL key-off when triggering notes" compatibility - setting broke retrigger for OPL notes again (they retriggered rather than - not retriggering). - * S3M: Retriggering a note no longer resets its pitch after a portamento. - * S3M: Partially implement retrigger behaviour for stopped notes in - SoundBlaster mode: Like in IT, it is not possible to retrigger a sample that - has already stopped playing. - * DIGI: Improve compatibility with E3x reverse sample command. - * DSym: Tempos < 32 were treated as tempo slides. - * SymMOD: Key-off command was not implemented properly. - -### libopenmpt 0.6.0 (2021-12-23) - - * [**New**] `MUS` files from Psycho Pinball and Micro Machines 2 are now - supported. - * [**New**] `SymMOD` files created with Symphonie / Symphonie Pro are now - supported. - * [**New**] `FMT` files created with Davey W Taylor's FM Tracker are now - supported. - * [**New**] `DSYM` files created with Digital Symphony are now supported. - * [**New**] `STX` files (transitional format between Scream Tracker 2 and 3) - are now supported. - * [**New**] TakeTracker MODs with `TDZ1` to `TDZ3` magic bytes are now - supported. - * [**New**] openmpt123: openmpt123 will now expand file wildcards passed on - the command line in Windows when built with MSVC. - * [**New**] libopenmpt_ext: New interface `interactive2` adding - `openmpt::ext::interactive2::note_off()`, - `openmpt::ext::interactive2::note_fade()`, - `openmpt::ext::interactive2::set_channel_panning()`, - `openmpt::ext::interactive2::get_channel_panning()`, - `openmpt::ext::interactive2::set_note_finetune()`, and - `openmpt::ext::interactive2::get_note_finetune()` (C++) and - `openmpt_module_ext_interface_interactive2.note_off()`, - `openmpt_module_ext_interface_interactive2.note_fade()`, - `openmpt_module_ext_interface_interactive2.set_channel_panning()`, - `openmpt_module_ext_interface_interactive2.get_channel_panning()`, - `openmpt_module_ext_interface_interactive2.set_note_finetune()`, and - `openmpt_module_ext_interface_interactive2.get_note_finetune()` (C). - * [**New**] `Makefile` `CONFIG=emscripten` now supports - `EMSCRIPTEN_TARGET=audioworkletprocessor` which builds an ES6 module in - a single file with reduced dependencies suitable to be used in an - AudioWorkletProcessor. - * [**New**] `Makefile` `CONFIG=emscripten` now supports `EMSCRIPTEN_PORTS=1` - which uses dependencies (zlib, mp123, ogg, and vorbis) from Emscripten Ports - instead of using miniz, minimp3, and stb_vorbis locally or building zlib, - mp123, ogg, and vorbis locally. - * [**New**] `Makefile` `CONFIG=emscripten` and `CONFIG=djgpp` can now build - zlib, mpg123, and vorbis locally instead of only supporting miniz, minimp3, - and stb_vorbis via `ALLOW_LGPL=1`. - - * [**Change**] `Makefile` `CONFIG=emscripten` now supports - `EMSCRIPTEN_TARGET=all` which provides WebAssembly as well as fallback to - JavaScript in a single build. - * [**Change**] openmpt123: DOS builds now use the Mercury fork of - `liballegro 4.2` for improved hardware compatibility. - * [**Change**] libopenmpt no longer generates internal interpolation tables on - library load time, but instead only on first module load time. - - * [**Regression**] `Makefile` `CONFIG=emscripten` does not support - `EMSCRIPTEN_TARGET=asmjs` or `EMSCRIPTEN_TARGET=asmjs128m` any more because - support has been removed from current Emscripten versions. - * [**Regression**] Support for GCC 7 has been removed. - * [**Regression**] Support for Clang 5, 6 has been removed. - * [**Regression**] Support for Emscripten versions older than 1.39.7 has been - removed. - * [**Regression**] Building with Android NDK older than NDK r19c is not - supported any more. - - * libopenmpt can now detect infinite pattern loops and treats them as the song - end. This means that setting a repeat count other than -1 now always - guarantees that playback will eventually end. The song loop counter is - decremented each time it ends up at the start of the infinite loop, so the - song does not restart from the beginning even if the repeat count is not 0. - * `openmpt::module::set_position_seconds()` accuracy has been improved for - modules with pattern loops. - * Samples played at the wrong volume when rendering modules in mono. - * IT: Portamentos in files with Linear Slides disabled are now more accurate. - * IT: Pitch/Pan Separation was affected by note-off commands, and wasn't reset - by panning commands like in Impulse Tracker. - * IT: Even after libopenmpt 0.5.14 the filter reset logic was still not 100% - identical to Impulse Tracker: A note triggered on tick 0 of a row with a - Pattern Delay effect still caused the filter to be reset on repetitions of - that row even though the note wasn't retriggered. - * IT: Added read-only support for BeRoTracker commands 1 and 2 (equivalent to - XM commands K and L). - * XM: BeRoTracker saves smooth MIDI macros in a different way from OpenMPT. - This command is now imported correctly. - * XM: Emulate FT2 Tone Portamento quirk that inverts portamento direction - after the target was reached (if target note was higher than previous note). - * S3M files saved with Impulse Tracker and latest Schism Tracker now also - compute sample playback speed in Hertz. - * Depending on whether an S3M file was last saved in Scream Tracker with the - Sound Blaster or Gravis Ultrasound drivers loaded, different compatibility - flags are now applied. For files saved with the GUS, the sample volume - factor is now also ignored (fixes volume levels in S3Ms made on the GUS, in - particular if they use both samples and OPL instruments). - * S3M: Enforce the lower frequency bound. - * MOD: Loosened VBlank timing heuristics so that the original copy of - Guitar Slinger from Dizzy Tunes II plays correctly. - * FAR: Correct portamento depth is now used. - * DMF / IMF: Improved accuracy of finetune commands. - * MDL: Implemented finetune command. - * OKT: Various accuracy improvements such as: Sharing volume between mixed - channels, volume commands on mixed channels are permanent (not reset with - new notes), mixed channels do not support default sample volume, 7-bit - samples are actually supposed to be played as-is (not amplified to full - 8-bit range), reject speed command parameters >= 20. - - * zlib: v1.2.11 (2017-01-15). - * mpg123: v1.29.3 (2021-12-11). - * ogg: v1.3.5 (2021-06-04). - * vorbis: v1.3.7 (2020-07-04). - * miniz: v2.2.0 (2021-06-27). - * minimp3: commit 50d2aaf360a53653b718fead8e258d654c3a7e41 (2021-11-27). - * stb_vorbis: v1.22 commit 5a0bb8b1c1b1ca3f4e2485f4114c1c8ea021b781 - (2021-07-12). - * FLAC: v1.3.3 (2019-08-04). - * PortAudio: v19.7.0 (2021-04-06). - -### libopenmpt 0.5.0 (2020-05-24) - - * [**New**] OggMod compressed FastTracker 2 XM (OXM) modules are now - supported. - * [**New**] The emulated Amiga type when Amiga resampler emulation is enabled - can now be selected via ctl `render.resampler.emulate_amiga_type`. Possible - values are: `"auto"`, `"a500"`, `"a1200"`, and an experimental option - `"unfiltered"`. - * [**New**] libopenmpt: New API `openmpt::module::get_current_estimated_bpm()` - (C++), and `openmpt_module_get_current_estimated_bpm()` (C) which provides - accurate beats per minute information for module formats with time signature - and an educated guess based on speed and tempo for others. - * [**New**] libopenmpt: New type-aware ctl APIs that do not require memory - allocations and are thus realtime-safe: - `openmpt::module::ctl_get_boolean()`, `openmpt::module::ctl_get_integer()`, - `openmpt::module::ctl_get_floatingpoint()`, - `openmpt::module::ctl_get_text()`, `openmpt::module::ctl_set_boolean()`, - `openmpt::module::ctl_set_integer()`, - `openmpt::module::ctl_set_floatingpoint()` (C++), and - `openmpt_module_ctl_get_boolean()`, `openmpt_module_ctl_get_integer()`, - `openmpt_module_ctl_get_floatingpoint()`, `openmpt_module_ctl_get_text()`, - `openmpt_module_ctl_set_boolean()`, `openmpt_module_ctl_set_integer()`, - `openmpt_module_ctl_set_floatingpoint()` (C). - * [**New**] libopenmpt C++ New API `openmpt::is_extension_supported2()` which - takes a `std::string_view` parameter instead of `std::string`. - * [**New**] libopenmpt C++: New API - `openmpt::module::module(std::vector data)`, - `openmpt::module::module(const std::byte * data, std::size_t size)`, - `openmpt::module::module(const std::byte * beg, const std::byte * end)`. - * [**New**] libopenmpt C++: New API - `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size, filesize)`, - `openmpt::probe_file_header(flags, const std::byte * data, std::size_t size)`. - * [**New**] libopenmpt_ext C++: New API - `openmpt::module_ext::module_ext(std::vector data)`, - `openmpt::module_ext::module_ext(const std::byte * data, std::size_t size)`, - `openmpt::module_ext::module_ext(std::vector data)`, - `openmpt::module_ext::module_ext(const std::uint8_t * data, std::size_t size)`. - - * [**Change**] std::istream based file I/O has been speed up. - * [**Change**] Dependency on iconv on Linux has been removed. - - * [**Regression**] libmodplug: The libmodplug emulation layer has been removed - from the libopenmpt tree. Please use the separate `libopenmpt-modplug` - package instead. - * [**Regression**] foo_openmpt: foo_openmpt is discontinued. Please use - Kode54's fork foo_openmpt54: - . - * [**Regression**] Support for building with C++11 or C++14 has been removed. - C++17 is now required to build libopenmpt. - * [**Regression**] Support for client code using C++11 or C++ 14 has been - removed. C++17 is now required to build libopenmpt client applications. - * [**Regression**] Support for Visual Studio 2015 has been removed. - * [**Regression**] Support for GCC 4.8, 4.9, 5, 6 has been removed. - * [**Regression**] Support for Clang 3.6, 3.7, 3.8, 3.9, 4 has been removed. - * [**Regression**] Support for Emscripten versions older than 1.39.1 has been - removed. - * [**Regression**] Building with Android NDK older than NDK r18b is not - supported any more. - * [**Regression**] openmpt123: Support for SDL1 (but not SDL2) output has been - removed. - * [**Regression**] openmpt123: Support for SDL2 older than 2.0.4 has been - removed. - * [**Regression**] Windows XP and Windows Vista are no longer supported. - * [**Regression**] It is no longer possible to optionally use iconv for - character set conversions. - - * [**Bug**] openmpt123: openmpt123 now honors the current locale and outputs - text appropriately. - * [**Bug**] openmpt123: Piping text output to other than console window - targets on Windows has been fixed. - - * Greatly improved MED import. Synthesized instruments are still not supported - but support was added for: Multisampled instruments, delta samples, more - pattern commands, Hold and Decay, multiple songs and many other small - changes. - * Improved OPL channel allocation when more than 18 notes are active, so that - channels that have completely faded out are prioritized over channels that - have already been released but have not faded out yet. - * Interactively triggering an OPL instrument could cause the first pattern - channel to no longer be played back correctly. - * Fix some inaccuracies in OPL emulator. - * Fix overflow of OPL amplification happening at a synth volume level of 510. - * End-of-sample pop reduction of surround channels was applied to front - channels instead, causing a pop on the front channels instead of removing it - on the back channels. - * IT: Disable retrigger with short notes quirk for modules saved with - Chibi Tracker, as it does not implement that quirk. - * IT: Instrument and sample panning should not override channel panning for - following notes. - * IT: SBx is now prioritized over Bxx commands that are to the left of it. - * IT: Duplicate Check Type "Sample" should only be applied if the instruments - match, too. - * IT: Duplicate Check Type "Note" should compare pattern notes, but it was - comparing the new pattern note against the old translated note. - * IT: Various fixes for envelope resetting. - * IT / S3M: When combining SBx and EEx effects, don't skip the first row of - the loop like in FastTracker 2. - * S3M: Empty pattern commands now affect effect memory as well. - * S3M: Offset beyond loop end wraps around to loop start like in - Scream Tracker 3 + GUS (previously it just keep playing from the loop start, - which is neither what GUS nor Sound Blaster drivers do). - * S3M: Notes cannot be retriggered after they have been cut. - * S3M: Fix portamento after note cut (fixes antediluvian_song.s3m). - * S3M / MOD: Previous note offset is no longer used for retriggered notes if - there was no instrument number next to the Qxy effect. - * MOD: Sample swapping now also works if the sample that is being swapped from - does not loop. Swapping to a non-looped sample now stops playback once the - swapped-from sample reaches its (loop) end. - * MOD: Fix early song ending due to ProTracker pattern jump quirk - (EEx + Dxx on same row) if infinite looping is disabled. - Fixes Haunted Tracks.mod by Triace. - * MOD: Previous note offset is no longer used for retriggered notes if there - was no instrument number next to the E9x effect. - * MOD: Vibrato type "ramp down" was upside down. - * XM: If a file contains patterns longer than 1024 rows, they are now clamped - to 1024 rows instead of 64 rows. - * XM: Do not reset note-off status on portamento if there is no instrument - number. - - * mpg123: v1.26rc3. - * ogg: v1.3.4. - * vorbis: v1.3.6. - * zlib: v1.2.11. - * minimp3: commit 55da78cbeea5fb6757f8df672567714e1e8ca3e9 (2020-03-04). - * stb_vorbis: v1.19 commit 37b9b20fdec06c75a0493e0bb59e2d0f288bfb51 - (2020-02-05). - * miniz: v2.1.0. - * FLAC: v1.3.3. - * PortAudio: commit 799a6834a58592eadc5712cba73b35956dc51579 (2020-03-26). - -### libopenmpt 0.4.0 (2018-12-23) - - * [**New**] libopenmpt now includes emulation of the OPL chip and thus plays - OPL instruments in S3M, C67 and MPTM files. OPL chip emulation volume can be - changed with the new ctl `render.opl.volume_factor`. - * [**New**] libopenmpt now supports CDFM / Composer 670 module files. - * [**New**] Autotools `configure` and plain `Makefile` now honor the variable - `CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the - standard library (or libraries) required for static linking. The contents of - this variable will be put in `libopenmpt.pc` `Libs.private` and used for - nothing else. See \ref libopenmpt_c_staticlinking . - * [**New**] foo_openmpt: foo_openmpt now also works on Windows XP. - * [**New**] libopenmpt Emscripten builds now ship with MP3 support by - default, based on minimp3 by Lion (github.com/lieff). - * [**New**] libopenmpt: New ctl `play.at_end` can be used to change what - happens when the song end is reached: - * "fadeout": Fades the module out for a short while. Subsequent reads - after the fadeout will return 0 rendered frames. This is the default and - identical to the behaviour in previous libopenmpt versions. - * "continue": Returns 0 rendered frames when the song end is reached. - Subsequent reads will continue playing from the song start or loop - start. This can be used for custom loop logic, such as loop - auto-detection and longer fadeouts. - * "stop": Returns 0 rendered frames when the song end is reached. - Subsequent reads will return 0 rendered frames. - * [**New**] Add new metadata fields `"originaltype"` and `"originaltype_long"` - which allow more clearly reflecting what is going on with converted formats - like MO3 and GDM. - * [**New**] `Makefile` `CONFIG=emscripten` now can generate WebAssembly via - the additional option `EMSCRIPTEN_TARGET=wasm`. - * [**New**] Compiling for DOS is now experimentally supported via DJGPP GCC - 7.2 or later. - - * [**Change**] minimp3: Instead of the LGPL-2.1-licensed minimp3 by KeyJ, - libopenmpt now uses the CC0-1.0-licensed minimp3 by Lion (github.com/lieff) - as a fallback if libmpg123 is unavailable. The `USE_MINIMP3` `Makefile` - option is gone and minimp3 will be used automatically in the `Makefile` - build system if libmpg123 is not available. - * [**Change**] openmpt123: openmpt123 now rejects `--output-type` in `--ui` - and `--batch` modes and also rejects `--output` in `--render` mode. These - combinations of options really made no sense and were rather confusing. - * [**Change**] Android NDK build system now uses libc++ (`c++_shared`) instead - of GNU libstdc++ (`gnustl_shared`), as recommended by Android NDK r16b. - * [**Change**] xmp-openmpt: `openmpt-mpg123.dll` is no longer optional and - must be placed into the same directory as `xmp-openmpt.dll`. - * [**Change**] in_openmpt: `openmpt-mpg123.dll` is no longer optional and must - be placed either into the directory of the player itself or into the same - directory as `in_openmpt.dll`. This is dependent on how the player loads its - plugins. For WinAMP 5, `openmpt-mpg123.dll` needs to be in the directory - which contains `winamp.exe`. `in_openmpt.dll` needs to be in the `Plugins` - directory. - * [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component - package for easier installation. - * [**Change**] When building libopenmpt with MinGW-w64, it is now recommended - to use the posix thread model (as opposed to the win32 threading model), - because the former does support std::mutex while the latter does not. When - building with win32 threading model with the Autotools build system, it is - recommended to provide the `mingw-std-threads` package. Building libopenmpt - with MinGW-w64 without any `std::thread`/`std::mutex` support is deprecated - and support for such configurations will be removed in libopenmpt 0.5. - * [**Change**] `Makefile` `CONFIG=emscripten` now has 4 `EMSCRIPTEN_TARGET=` - settings: `wasm` generates WebAssembly, `asmjs128m` generates asm.js with a - fixed size 128MB heap, `asmjs` generates asm.js with a fixed default size - heap (as of Emscripten 1.38.11, this amounts to 16MB), `js` generates - JavaScript with dynamic heap growth and with compatibility for older VMs. - * [**Change**] libmodplug: Update public headers to libmodplug 0.8.8.5. This - adds support for kind-of automatic MODPLUG_EXPORT decoration on Windows. - - * [**Regression**] Support for Clang 3.4, 3.5 has been removed. - * [**Regression**] Building with Android NDK older than NDK r16b is not - supported any more. - * [**Regression**] Support for Emscripten versions older than 1.38.5 has been - removed. - * [**Regression**] Support for libmpg123 older than 1.14.0 has been removed. - * [**Regression**] Using MediaFoundation to decode MP3 samples is no longer - supported. Use libmpg123 or minimp3 instead. - * [**Regression**] libmodplug: Support for emulating libmodplug 0.8.7 API/ABI - has been removed. - - * [**Bug**] xmp-openmpt: Sample rate and number of output channels were not - applied correctly when using per-file settings. - * [**Bug**] Internal mixer state was not initialized properly when initially - rendering in 44100kHz stereo format. - * [**Bug**] openmpt123: Prevent libsdl2 and libsdl from being enabled at the - same time because they conflict with each other. - * [**Bug**] libmodplug: Setting `SNDMIX_NORESAMPLING` in the C++ API always - resulted in linear interpolation instead of nearest neighbour - - * IT: In Compatible Gxx mode, allow sample changes next to a tone portamento - effect if a previous sample has already stopped playing. - * IT: Fix broken volume envelopes with negative values as found in breakdwn.it - by Elysis. - * MOD: Slides and delayed notes are executed on every repetition of a row with - row delay (fixes "ode to protracker"). - * XM: If the sustain point of the panning envelope is reached before key-off, - it is never released. - * XM: Do not default recall volume / panning for delayed instrument-less notes - * XM :E60 loop bug was not considered in song length calucation. - * S3M: Notes without instrument number use previous note's sample offset. - * Tighten M15 and MOD file rejection heuristics. - * J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken - since libopenmpt-0.2.6401-beta17. - * STM: More accurate tempo calculation. - * STM: Better support for early format revisions (no such files have been - found in the wild, though). - * STM: Last character of sample name was missing. - * SFX: Work around bad conversions of the "Operation Stealth" soundtrack by - turning pattern breaks into note stops. - * IMF: Filter cutoff was upside down and the cutoff range was too small. - * ParamEq plugin center frequency was not limited correctly. - * Keep track of active SFx macro during seeking. - * The "note cut" duplicate note action did not volume-ramp the previously - playing sample. - * A song starting with non-existing patterns could not be played. - * DSM: Support restart position and 16-bit samples. - * DTM: Import global volume. - * MOD: Support notes in octave 2, like in FastTracker 2 (fixes DOPE.MOD). - * Do not apply Amiga playback heuristics to MOD files that have clearly been - written with a PC tracker. - * MPTM: More logical release node behaviour. - * Subsong search is now less thorough. It could previously find many subsongs - that are technically correct (unplayed rows at the beginning of patterns - that have been jumped over due to pattern breaks), but so far no real-world - module that would require such a thorough subsong detection was found. The - old mechanism caused way more false positives than intended with real-world - modules, though. - * Restrict the unpacked size of compressed DMF, IT, MDL and MO3 samples to - avoid huge allocations with malformed small files. - -### libopenmpt 0.3 (2017-09-27) - - * [**New**] New error handling functionality in the C API, which in particular - allows distinguishing potentially transient out-of-memory errors from parse - errors during module loading. - * [**New**] New API `openmpt::module::get_selected_subsong()` (C++) and - `openmpt_module_get_selected_subsong()` (C). - * [**New**] Faster file header probing API `openmpt::probe_file_header()` and - `openmpt::probe_file_header_get_recommended_size` (C++), and - `openmpt_probe_file_header()`, - `openmpt_probe_file_header_without_filesize()`, - `openmpt_probe_file_header_from_stream()` and - `openmpt_probe_file_header_get_recommended_size()` (C). - * [**New**] New API `openmpt::could_open_probability()` (C++) and - `openmpt_could_open_probability()` (C). This fixes a spelling error in the - old 0.2 API. - * [**New**] openmpt123: openmpt123 can now open M3U, M3U8, M3UEXT, M3U8EXT and - PLSv2 playlists via the `--playlist` option. - * [**New**] openmpt123: openmpt123 now supports very fast file header probing - via the `--probe` option. - * [**New**] Libopenmpt now supports building for Windows 10 Universal (Windows - Store 8.2) APIs with MSVC, and also for the older Windows Runtime APIs with - MinGW-w64. - * [**New**] New API header `libopenmpt_ext.h` which implements the libopenmpt - extension APIs also for the C interface. - * [**New**] The Reverb effect (S99 in S3M/IT/MPTM, and X99 in XM) is now - implemented in libopenmpt. - * [**New**] For Amiga modules, a new resampler based on the Amiga's sound - characteristics has been added. It can be activated by passing the - `render.resampler.emulate_amiga` ctl with a value of `1`. Non-Amiga modules - are not affected by this, and setting the ctl overrides the resampler choice - specified by `OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH` or - `openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH`. Support for the MOD - command E0x (Set LED Filter) is also available when the Amiga resampler is - enabled. - - * [**Change**] libopenmpt versioning changed and follows the more conventional - major.minor.patch as well as the recommendations of the - [SemVer](http://semver.org/) scheme now. In addition to the SemVer - requirements, pre-1.0.0 versions will also honor API and ABI stability in - libopenmpt (i.e. libopenmpt ignores SemVer Clause 4). - * [**Change**] The output directories of the MSVC build system were changed to - `bin/vs2015-shared/x86-64-win7/` (and similar) layout which allows building - in the same tree with different compiler versions without overwriting other - outputs. - * [**Change**] The emscripten build now exports libopenmpt as 'libopenmpt' - instead of the default 'Module'. - * [**Change**] Android: The build system changed. The various Android.mk files - have been merged into a single one which can be controlled using command - line options. - * [**Change**] The `Makefile` build system now passes `std=c++11` to the - compiler by default. Older compilers may still work if you pass - `STDCXX=c++0x` to the `make` invocation. - * [**Change**] The `Makefile` option `ANCIENT=1` is gone. - * [**Change**] The optional dependencies on `libltdl` or `libdl` are gone. - They are no longer needed for any functionality. - - * [**Regression**] Compiling client code using the C++ API now requires a - compiler running in C++11 mode. - * [**Regression**] Support for GCC 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7 has been - removed. - * [**Regression**] Support for Clang 3.0, 3.1, 3.2, 3.3 has been removed. - * [**Regression**] Support for Emscripten versions older than 1.31.0 has been - removed. - * [**Regression**] Support for Android NDK versions older than 11 has been - removed. - * [**Regression**] Visual Studio 2008, 2010, 2012, 2013 support has been - removed. - * [**Regression**] Dynamic run-time loading of libmpg123 is no longer - supported. Libmpg123 must be linked at link-time now. - * [**Regression**] xmp-openmpt: xmp-openmpt now requires XMPlay 3.8 or later - and compiling xmp-openmpt requires an appropriate XMPlay SDK with - `XMPIN_FACE` >= `4`. - * [**Regression**] Support for libmpg123 older than 1.13.0 has been removed. - * [**Regression**] Un4seen unmo3 support has been removed. - - * [**Bug**] C++ API: `openmpt::exception` did not define copy and move - constructors or copy and move assignment operators in libopenmpt 0.2. The - compiler-generated ones were not adequate though. libopenmpt 0.3 adds the - appropriate special member functions. This adds the respective symbol names - to the exported ABI, which, depending on the compiler, might or might not - have been there in libopenmpt 0.2. The possibly resulting possible ODR - violation only affects cases that did crash in the libopenmpt 0.2 API anyway - due to memory double-free, and does not cause any further problems in - practice for all known platforms and compilers. - * [**Bug**] The C API could crash instead of failing gracefully in - out-of-memory situations. - * [**Bug**] The test suite could fail on MacOSX or FreeBSD in non-fatal ways - when no locale was active. - * [**Bug**] `libopenmpt_stream_callbacks_fd.h` and - `libopenmpt_stream_callbacks_file.h` were missing in Windows development - packages. - * [**Bug**] libopenmpt on Windows did not properly guard against current - working directory DLL injection attacks. - * [**Bug**] localtime() was used to determine the version of Schism Tracker - used to save IT and S3M files. This function is not guaranteed to be - thread-safe by the standard and is now no longer used. - * [**Bug**] Possible crashes with malformed IT, ITP, AMS, MDL, MED, MPTM, PSM - and Startrekker files. - * [**Bug**] Possible hangs with malformed DBM, MPTM and PSM files. - * [**Bug**] Possible hangs with malformed files containing cyclic plugin - routings. - * [**Bug**] Excessive loading times with malformed ITP / truncated AMS files. - * [**Bug**] Plugins did not work correctly when changing the sample rate - between two render calls. - * [**Bug**] Possible NULL-pointer dereference read during obscure - out-of-memory situations while handling exceptions in the C API. - * [**Bug**] libmodplug: `libmodplug.pc` was wrong. - * [**Bug**] Cross-compiling libopenmpt with autotools for Windows now properly - sets `-municode` and `-mconsole` as well as all required Windows system - libraries. - * [**Bug**] foo_openmpt: Interpolation filter and volume ramping settings were - confused in previous versions. This version resets both to the defaults. - * [**Bug**] libmodplug: The CSoundFile::Read function in the emulated - libmodplug C++ API returned the wrong value, causing qmmp (and possibly - other software) to crash. - - * Support for SoundTracker Pro II (STP) and Digital Tracker (DTM) modules. - * Increased accuracy of the sample position and sample rate to drift less when - playing very long samples. - * Various playback improvements for IT and XM files. - * Channel frequency could wrap around after some excessive portamento / down - in some formats since libopenmpt 0.2-beta17. - * Playback improvements for S3M files made with Impulse Tracker and - Schism Tracker. - * ParamEq plugin emulation didn't do anything at full gain (+15dB). - * All standard DMO effects are now also emulated on non-Windows and non-MSVC - systems. - * Added `libopenmpt_stream_callbacks_buffer.h` which adds - `openmpt_stream_callbacks` support for in-memory buffers, possibly even only - using a truncated prefix view into a bigger file which is useful for - probing. - * Avoid enabling some ProTracker-specific quirks for MOD files most likely - created with ScreamTracker 3. - * Tremolo effect only had half the intended strength in MOD files. - * Pattern loops ending on the last row a pattern were not executed correctly - in S3M files. - * Work-around for reading MIDI macros and plugin settings in some malformed IT - files written by old UNMO3 versions. - * Improve tracker detection in IT format. - * Playback fixes for 8-channel MED files - * Do not set note volume to 0 on out-of-range offset in XM files. - * Better import of some slide commands in SFX files. - * Sample 15 in "Crew Generation" by Necros requires short loops at the - beginning of the sample to not be ignored. Since we need to ignore them in - some (non-ProTracker) modules, we heuristically disable the old loop - sanitization behaviour based on the module channel count. - * Both normal and percentage offset in PLM files were handled as percentage - offset. - * MT2 files with instruments that had both sample and plugin assignments were - not read correctly. - * Some valid FAR files were rejected erroneously. - * Support for VBlank timing flag and comment field in PT36 files. - * Improved accuracy of vibrato command in DIGI / DBM files. - * STM: Add support for "WUZAMOD!" magic bytes and allow some slightly - malformed STM files to load which were previously rejected. - * Detect whether "hidden" patterns in the order list of SoundTracker modules - should be taken into account or not. - * Tighten heuristics for rejecting invalid 669, M15, MOD and ICE files and - loosen them in other places to allow some valid MOD files to load. - * Improvements to seeking: Channel panning was not always updated from - instruments / samples when seeking, and out-of-range global volume was not - applied correctly in some formats. - * seek.sync_samples=1 did not apply PTM reverse offset effect and the volume - slide part of combined volume slide + vibrato commands. - * If the order list was longer than 256 items and there was a pattern break - effect without a position jump on the last pattern of the sequence, it did - not jump to the correct restart order. - * `Makefile` has now explicit support for FreeBSD with no special option or - configuration required. - * openmpt123: Improved section layout in man page. - * libmodplug: Added all missing C++ API symbols that are accessible via the - public libmodplug header file. - * Autotools build system now has options `--disable-openmpt123`, - `--disable-tests` and `--disable-examples` which may be desireable when - cross-compiling. - * Windows binary packages now ship with libmpg123 included. - -### libopenmpt 0.2-beta20 (2016-08-07) - - * [**Bug**] PSM loader was broken on big-endian platforms since forever. - * [**Bug**] `load.skip_samples` ctl did not work for PSM16 modules. - - * There is a new `subsong` ctl, which can return the currently selected - subsong. - * More accurate ProTracker arpeggio wrap-around emulation. - * More accurate sample tuning in PSM16 files. - * Samples in DSM files were sometimes detuned and some pattern commands were - not imported correctly. - * More accurate import of MDL 7-bit panning command. - * Only import pattern commands supported by the UltraTracker version that was - used to save ULT files. Add support for command 5-C (end loop). - * DMF sample loop lengths were off by one. - * Unis 669 pan slide effect was too deep. - * Several valid (but slightly corrupted possibly due to disk failures or data - transfer errors) SoundTracker files were no longer loading since libopenmpt - 0.2-beta18. - -### libopenmpt 0.2-beta19 (2016-07-23) - - * [**Change**] libopenmpt now uses C++14 `[[deprecated]]` attribute instead - of compiler-specific solutions when appropriate. - * [**Change**] libopenmpt C++ header now uses C++11 `noexcept` instead of - C++98 `throw()` exception specification when supported. `throw()` is - deprecated since C++11. This does not change API or ABI as they are - equivalent. Use `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` to override the - default. - * [**Change**] The preprocessor macro `LIBOPENMPT_ANCIENT_COMPILER_STDINT` is - gone. Please use `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT instead`. - Additionally, the typedefs moved from illegal namespace ::std into somewhat - less dangerous namespace ::openmpt::std. You can test - `#ifdef LIBOPENMPT_QUIRK_NO_CSTDINT` client-side to check whether - `libopenmpt.hpp` used the non-standard types. (Note: Of all supported - compilers, this change only affects the 3 compilers with only limited - support: MSVC 2008, GCC 4.1, GCC 4.2.) - - * [**Bug**] xmp-openmpt: Crash when viewing sample texts. - - * The public libopenmpt C++ header has auto-detection logic for the used C++ - standard now. In case your client code compiler misreports the standard - version or you want to override it for other reasons, - `#define LIBOPENMPT_ASSUME_CPLUSPLUS` to the value of the standard version - you desire to be used. There is also a macro for each individual aspect, - like `LIBOPENMPT_ASSUME_CPLUSPLUS_CSTDINT`, - `LIBOPENMPT_ASSUME_CPLUSPLUS_DEPRECATED`, - `LIBOPENMPT_ASSUME_CPLUSPLUS_NOEXCEPT` which take precedence over the - general macro. - * Portamento with sample swap behaviour was wrong for ProTracker MODs. - * Rewritten loader and various playback fixes for MDL files. - * libopenmpt 0.2-beta18 broke import of many pattern commands in DBM, DMF and - ULT files. - * ADPCM samples in MOD files were broken since libopenmpt 0.2-beta17. - -### libopenmpt 0.2-beta18 (2016-07-11) - - * [**Change**] openmpt123: Add PulseAudio output support. Autotools and - `Makefile` build systems now depend on `libpulse` and `libpulse-simple` by - default. Disable with `--without-pulseaudio` or `NO_PULSEAUDIO=1` - respectively. When enabled, PulseAudio will be the default output driver, - * [**Change**] xmp-openmpt: Settings are now stored in xmplay.ini like with - every other plugin. - - * [**Regression**] openmpt123: Support for FLAC < 1.3.0 has been removed. FLAC - before 1.3.0 is broken beyond repair as it provides `assert.h` in the - include path. - - * [**Bug**] Generated pkg-config file libopenmpt.pc by both `Makefile` and - Autotools build systems was totally broken. - * [**Bug**] libopenmpt no longer uses the non-thread-safe global std::rand() - function. - * [**Bug**] Sample loops in GDM modules did not work when using Emscripten. - * [**Bug**] XM and MO3 loaders could crash due to unaligned memory accesses. - * [**Bug**] Fixed incorrect handling of custom MPTM tunings on big endian - platforms. - * [**Bug**] Fixed various problems found with clang 3.8 static analyzer, - address sanitizer and undefined behaviour sanitizer. - * [**Bug**] File header probing functionality was broken for most formats. - * [**Bug**] With non-seekable streams, the entire file was almost always - cached even if it was not of any supported module type. - - * Seeking in allsubsongs-mode now works correctly. - * openmpt123: Added subsong support. - * Various playback fixes for 669, IT, MT2 and MTM files. - * Some MOD files with more than 128 patterns (e.g. NIETNU.MOD) were not loaded - correctly. - * A new example `libopenmpt_example_c_probe` has been added which demonstrates - the usage and flexibility of openmpt_could_open_propability() in the C API - under various constraints. - -### libopenmpt 0.2-beta17 (2016-05-21) - - * [**Change**] The Makefile and Autotools build systems now require to - explicitly specify `NO_LTDL=1` or `--without-ltdl` respectively if no - support for dynamic loading of third party libraries via libtool libltdl is - desired. - * [**Change**] In the Makefile build system option `USE_MO3` and the Autotools - build system option `--enable-mo3` are gone. Dynamic loading of un4seen - unmo3 is now always enabled when dynamic loading is possible and built-in - MO3 support is not possible because either a MP3 or a Vorbis decoder is - missing. - * [**Change**] The MSVC build system changed. The `libopenmptDLL` project is - gone. Use the new `ReleaseShared` configuration of the `libopenmpt` project - instead. libopenmpt now links against zlib by default. A separate project - with smaller footprint linking against miniz is still available as - `libopenmpt-small`. - * [**Change**] The constants used to query library information from - `openmpt_get_string()` and `openmpt::string::get()` (i.e. OPENMPT_STRING_FOO - and openmpt::string::FOO) have been deprecated because having syntactic - constants for theses keys makes extending the API in a backwards and - forwards compatible way harder than it should be. Please just use the string - literals directly. - * [**Change**] Deprecated API identifiers will now cause deprecation warnings - with MSVC, GCC and clang. `#define LIBOPENMPT_NO_DEPRECATE` to disable the - warnings. - * [**Change**] openmpt123: `--[no-]shuffle` option has been renamed to - `--[no-]randomize`. A new `--[no-]shuffle` option has been added which - shuffles randomly through the playlist as opposed to randomizing the - playlist upfront. - * [**Change**] Support for Un4seen unmo3 has generally been deprecated in - favour of the new internal mo3 decoder. Un4seen unmo3 support will be - removed on 2018-01-01. - - * [**Bug**] Memory consumption during loading has been reduced by about 1/3 in - case a seekable input stream is provided (either via C API callback open - functions or via C++ API iostream constructors). - * [**Bug**] Some samples in AMS modules were detuned when using Emscripten. - * [**Bug**] Possible crash with excessive portamento down in some formats. - * [**Bug**] Possible crashes with malformed AMF, AMS, DBM, IT, MDL, MED, MPTM, - MT2, PSM and MMCMP-, XPK- and PP20-compressed files. - * [**Bug**] `openmpt::module::format_pattern_row_channel` with `width == 0` - was returning an empty string instead of an string with unconstrained - length. - - * Support for ProTracker 3.6 IFF-style modules and SoundFX / MultiMedia Sound - (SFX / MMS) modules. - * libopenmpt now has support for DMO plugins on Windows when built with MSVC. - Additionally, the DMO Compression, Distortion, Echo, Gargle, ParamEQ and - WavesReverb DSPs are emulated on on all other platforms. - * libopenmpt now supports the DigiBooster Echo DSP. - * To avoid any of the aforementioned plugins to be used, the load.skip_plugins - ctl can be passed when loading a module. - * libopenmpt got native MO3 support with MP3 decoding either via libmpg123 or - MediaFoundation (on Windows 7 and up) and Vorbis decoding via libogg, - libvorbis, libvorbisfile or stb_vorbis. - * libopenmpt MSVC builds with Visual Studio 2010 or later on Windows 7 or - later now use an internal MO3 decoder with libogg, libvorbis, libvorbisfile, - and libmpg123 or minimp3 or MediaFoundation suppport by default. Visual - Studio 2008 builds still use unmo3.dll by default but also support the - built-in decoder in which case libmpg123 is required. - * libopenmpt with Makefile or Autotools build system can now also use - glibc/libdl instead of libtool/libltdl for dynamic loading of third-party - libraries. Options `NO_DL=1` and `--without-dl` have been added - respectively. - * The `Makefile` build system got 4 new options NO_MPG123, NO_OGG, NO_VORBIS, - NO_VORBISFILE. The default is to use the new dependencies automatically. - * The `Autotools` build system got 4 new options --without-mpg123, - --without-ogg, --without-vorbis, --without-vorbisfile. The default is to use - the new dependencies automatically. - * Makefile and Android builds got support for using minimp3 instead of - libmpg123. For Android, use `Android-minimp3-stbvorbis.mk`, for Makefile use - `USE_MINIMP3=1`. You have to download - [minimp3](http://keyj.emphy.de/minimp3/) yourself and put its contents into - `include/minimp3/`. - * `"source_url"`, `"source_date"` and `"build_compiler"` keys have been added - to `openmpt_string_get()` and `openmpt::string::get()`. - * openmpt123: Add new `--[no-]restart]` option which restarts the playlist - when finished. - * Improved Ultimate SoundTracker version detection heuristics. - * Playing a sample at a sample rate close to the mix rate could lead to small - clicks when using vibrato. - * More fine-grained internal legacy module compatibility settings to correctly - play back modules made with older versions of OpenMPT and a few other - trackers. - * The tail of compressed MDL samples was slightly off. - * Some probably hex-edited XM files (e.g. cybernostra weekend.xm) were not - loaded correctly. - * Countless other playback fixes for MOD, XM, S3M, IT and MT2 files. - -### libopenmpt 0.2-beta16 (2015-11-22) - - * [**Change**] The Autotools build system does strict checking of all - dependencies now. Instead of best effort auto-magic detection of all - potentially optional dependencies, the default set of dependencies is now - enforced unless each individual dependency gets explicitely disabled via - `--without-foo` or `--disable-foo` `./configure` switches. Run - `./configure --help` for the full list of options. - - * [**Bug**] Some MOD files were erroneously detected as 669 files. - * [**Bug**] Some malformed AMF files could result in very long loading times. - * [**Bug**] Fixed crashes in IMF and MT2 loaders. - * [**Bug**] MTM files generated by UNMO3 were not loaded properly. - - * Improved MTM playback. - * `make CONFIG=haiku` for Haiku has been added. - * Language bindings for FreeBASIC have been added (see - `libopenmpt/bindings/`). - -### libopenmpt 0.2-beta15 (2015-10-31) - - * [**Change**] openmpt123: SDL2 is now supported and preferred to SDL1 if - available with the `Makefile` build system. - - * [**Bug**] Emscripten support for older emscripten versions broke in -beta14. - These are now supported again when using `make CONFIG=emscripten-old`. - * [**Bug**] Fixed crashes in MED loader. - - * Playback improvements and loader fixes for MOD, MT2 and MED. - -### libopenmpt 0.2-beta14 (2015-09-13) - - * [**Change**] The C++ API example now uses the PortAudio C++ bindings - instead of the C API. - * [**Change**] Default compiler options for Emscripten have been changed to - more closely match the Emscripten recommendations. - - * [**Bug**] Client code compilation with C89 compilers was broken in beta13. - * [**Bug**] Test suite failed on certain Emscripten/node.js combinations. - * [**Bug**] Fixed various crashes or hangs in DMF, OKT, PLM, IT and MPTM - loaders. - - * Implemented error handling in the libopenmpt API examples. - * Various playback improvements and fixes for OKT, IT and MOD. - -### libopenmpt 0.2-beta13 (2015-08-16) - - * [**Change**] The MSVC build system has been redone. Solutions are now - located in `build/vsVERSION/`. - - * [**Bug**] get_current_channel_vu_left and get_current_channel_vu_right only - return the volume of the front left and right channels now. - get_current_channel_vu_rear_left and get_current_channel_vu_rear_right - do now actually work and return non-zero values. - * [**Bug**] Fix crashes and hangs in MED and MDL loaders and with some - truncated compressed IT samples. - * [**Bug**] Fix crash when playing extremely high-pitched samples. - - * Completed C and C++ documentation - * Added new key for openmpt::module::get_metadata, "message_raw", which - returns an empty string if there is no song message rather than a list of - instrument names. - * in_openmpt: Support for compiling with VS2008. - * xmp-openmpt: Support for compiling with VS2008. - * in_openmpt: Add a more readable file information window. - -### libopenmpt 0.2-beta12 (2015-04-19) - - * Playback fix when row delay effect is used together with offset command. - * A couple of fixes for the seek.sync_samples=1 case. - * IT compatibility fix for IT note delay. - * ProTracker MOD playback compatibility improvement. - -### libopenmpt 0.2-beta11 (2015-04-18) - - * [**Change**] openmpt_stream_seek_func() now gets called with - OPENMPT_STREAM_SEEK_SET, OPENMPT_STREAM_SEEK_CUR and - OPENMPT_STREAM_SEEK_END whence parameter instead of SEEK_SET, SEEK_CUR and - SEEK_END. These are defined to 0, 1 and 2 respectively which corresponds to - the definition in all common C libraries. If your C library uses different - constants, this theoretically breaks binary compatibility. The old - libopenmpt code, however, never actually called the seek function, thus, - there will be no problem in practice. - * [**Change**] openmpt123: When both SDL1.2 and PortAudio are available, - SDL is now the preferred backend because SDL is more widespread and better - tested on all kinds of different platforms, and in general, SDL is just - more reliable. - - * [**Bug**] libopenmpt now also compiles with GCC 4.3. - - * libopenmpt now supports PLM (Disorder Tracker 2) files. - * Various playback improvements and fixes for IT, S3M, XM, MOD, PTM and 669 - files. - -### libopenmpt 0.2-beta10 (2015-02-17) - - * [**Change**] Makefile configuration filenames changed from - `build/make/Makefile.config.*` to `build/make/config-*.mk`. - * [**Change**] libopenmpt for Android now supports unmo3 from un4seen. See - `build/android_ndk/README.AndroidNDK.txt` for details. - - * [**Bug**] Fix out-of-bounds read in mixer code for ProTracker-compatible - MOD files which was introduced back in r4223 / beta6. - - * Vibrato effect was too weak in beta8 and beta9 in IT linear slide mode. - * Very small fine portamento was wrong in beta8 and beta9 in IT linear slide - mode. - * Tiny IT playback compatibility improvements. - * STM playback improvements. - -### libopenmpt 0.2-beta9 (2014-12-21) - - * [**Bug**] libopenmpt_ext.hpp was missing from the Windows binary zip files. - -### libopenmpt 0.2-beta8 (2014-12-21) - - * [**Change**] foo_openmpt: Settings are now accessible via foobar2000 - advanced settings. - * [**Change**] Autotools based build now supports libunmo3. Specify - --enable-unmo3. - * [**Change**] Support for dynamic loading of libunmo3 on MacOS X. - * [**Change**] libopenmpt now uses libltld (from libtool) for dynamic loading - of libunmo3 on all non-Windows platforms. - * [**Change**] Support for older compilers: - * GCC 4.1.x to 4.3.x (use `make ANCIENT=1`) - * Microsoft Visual Studio 2008 (with latest Service Pack) - (see `build/vs2008`) - * [**Change**] libopenmpt_ext.hpp is now distributed by default. The API is - still considered experimental and not guaranteed to stay API or ABI - compatible. - * [**Change**] xmp-openmpt / in_openmpt: No more libopenmpt_settings.dll. - The settings dialog now uses a statically linked copy of MFC. - - * [**Bug**] The -autotools tarballs were not working at all. - - * Vastly improved MT2 loader. - * Improved S3M playback compatibility. - * Added openmpt::ext::interactive, an extension which adds a whole bunch of - new functionality to change playback in some way or another. - * Added possibility to sync sample playback when using - openmpt::module::set_position_* by setting the ctl value - seek.sync_samples=1 - * Support for "hidden" subsongs has been added. - They are accessible through the same interface as ordinary subsongs, i.e. - use openmpt::module::select_subsong to switch between any kind of subsongs. - * All subsongs can now be played consecutively by passing -1 as the subsong - index in openmpt::module::select_subsong. - * Added documentation for a couple of more functions. - -### libopenmpt 0.2-beta7 (2014-09-07) - - * [**Change**] libopenmpt now has an GNU Autotools based build system (in - addition to all previously supported ways of building libopenmpt). - Autotools support is packaged separately as tarballs ending in - `-autotools.tar.gz`. - - * [**Bug**] The distributed windows .zip file did not include pugixml. - - * [**Regression**] openmpt123: Support for writing WavPack (.wv) files has - been removed. - - Reasoning: - 1. WavPack support was incomplete and did not include support for writing - WavPack metadata at all. - 2. openmpt123 already supports libSndFile which can be used to write - uncompressed lossless WAV files which can then be encoded to whatever - format the user desires with other tools. - -### libopenmpt 0.2-beta6 (2014-09-06) - - * [**Change**] openmpt123: SDL is now also used by default if availble, in - addition to PortAudio. - * [**Change**] Support for emscripten is no longer experimental. - * [**Change**] libopenmpt itself can now also be compiled with VS2008. - - * [**Bug**] Fix all known crashes on platforms that do not support unaligned - memory access. - * [**Bug**] openmpt123: Effect column was always missing in pattern display. - -### libopenmpt 0.2-beta5 (2014-06-15) - - * [**Change**] Add unmo3 support for non-Windows builds. - * [**Change**] Namespace all internal functions in order to allow statically - linking against libopenmpt without risking duplicate symbols. - * [**Change**] Iconv is now completely optional and only used on Linux - systems by default. - * [**Change**] Added libopenmpt_example_c_stdout.c, an example without - requiring PortAudio. - * [**Change**] Add experimental support for building libopenmpt with - emscripten. - - * [**Bug**] Fix ping-pong loop behaviour which broke in 0.2-beta3. - * [**Bug**] Fix crashes when accessing invalid patterns through libopenmpt - API. - * [**Bug**] Makefile: Support building with missing optional dependencies - without them being stated explicitely. - * [**Bug**] openmpt123: Crash when quitting while playback is stopped. - * [**Bug**] openmpt123: Crash when writing output to a file in interactive UI - mode. - * [**Bug**] openmpt123: Wrong FLAC output filename in --render mode. - - * Various smaller playback accuracy improvements. - -### libopenmpt 0.2-beta4 (2014-02-25) - - * [**Bug**] Makefile: Dependency tracking for the test suite did not work. - -### libopenmpt 0.2-beta3 (2014-02-21) - - * [**Change**] The test suite is now built by default with Makefile based - builds. Use `TEST=0` to skip building the tests. `make check` runs the test - suite. - - * [**Bug**] Crash in MOD and XM loaders on architectures not supporting - unaligned memory access. - * [**Bug**] MMCMP, PP20 and XPK unpackers should now work on non-x86 hardware - and implement proper bounds checking. - * [**Bug**] openmpt_module_get_num_samples() returned the wrong value. - * [**Bug**] in_openmpt: DSP plugins did not work properly. - * [**Bug**] in_openmpt/xmp-openmpt: Setting name for stereo separation was - misspelled. This version will revert your stereo separation settings to - default. - * [**Bug**] Crash when loading some corrupted modules with stereo samples. - - * Support building on Android NDK. - * Avoid clicks in sample loops when using interpolation. - * IT filters are now done in integer instead of floating point. This improves - performance, especially on architectures with no or a slow FPU. - * MOD pattern break handling fixes. - * Various XM playback improvements. - * Improved and switchable dithering when using 16bit integer API. - -### libopenmpt 0.2-beta2 (2014-01-12) - - * [**Bug**] MT2 loader crash. - * [**Bug**] Saving settings in in_openmpt and xmp-openmpt did not work. - * [**Bug**] Load libopenmpt_settings.dll also from below Plugins directory in - Winamp. - - * DBM playback improvements. - -### libopenmpt 0.2-beta1 (2013-12-31) - - * First release. - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md index ab5c257b7..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/dependencies.md @@ -1,122 +0,0 @@ - -Dependencies {#dependencies} -============ - - -Dependencies ------------- - -### libopenmpt - - * Supported compilers for building libopenmpt: - * **Microsoft Visual Studio 2017** or higher, running on a amd64 build - system (other target systems are supported) - - Please note that we do not support building with a later Visual Studio - installation with an earlier compiler version. This is because, while - later Visual Studio versions allow installing earlier compilers to be - available via the later version's environment, in this configuration, - the earlier compiler will still use the later C and C++ runtime's - headers and implementation, which significantly increases the matrix of - possible configurations to test. - - * **GCC 8.1** or higher - * **Clang 7** or higher - * **MinGW-W64 8.1** or higher (it is recommended to preferably use - posix threading model as opposed to win32 threading model) - * **emscripten 1.39.1** or higher - * **DJGPP GCC 8.1** or higher - * any other **C++17 compliant** compiler - - libopenmpt makes the following assumptions about the C++ implementation - used for building: - * `std::numeric_limits::digits == 8` (enforced by - static_assert) - * existence of `std::uintptr_t` (enforced by static_assert) - * in C++20 mode, `std::endian::little != std::endian::big` (enforced - by static_assert) - * `wchar_t` encoding is either UTF-16 or UTF-32 (implicitly assumed) - * representation of basic source character set is ASCII (implicitly - assumed) - * representation of basic source character set is identical in char - and `wchar_t` (implicitly assumed) - - libopenmpt does not rely on any specific implementation defined or - undefined behaviour (if it does, that's a bug in libopenmpt). In - particular: - * `char` can be `signed` or `unsigned` - * shifting signed values is implementation defined - * `signed` integer overflow is undefined - * `float` and `double` can be non-IEEE754 - - libopenmpt can optionally support certain incomplete C++ - implementations: - * platforms without `wchar_t` support (like DJGPP) - * platforms without working `std::random_device` (like Emscripten when - running in `AudioWorkletProcessor` context) - * platforms without working `std::high_resolution_clock` (like - Emscripten when running in `AudioWorkletProcessor` context) - - * Required compilers to use libopenmpt: - * Any **C89** / **C99** / **C11** compatible compiler should work with - the C API as long as a **C99** compatible **stdint.h** is available. - * Any **C++17** compatible compiler should work with the C++ API. - * **J2B** support requires an inflate (deflate decompression) implementation: - * **zlib** (or **miniz** can be used internally) - * **MO3** support requires: - * **libmpg123 >= 1.14.0** (or **minimp3 by Lion (github.com/lieff)** can - be used internally) - * **libogg**, **libvorbis**, and **libvorbisfile** (or **stb_vorbis** can - be used internally) - * Building on Unix-like systems requires: - * **GNU make** - * **pkg-config** - * The Autotools-based build system requires: - * **pkg-config 0.24** or higher - * **zlib** - * **doxygen** - -### openmpt123 - - * Live sound output requires one of: - * **PulseAudio** - * **SDL 2** - * **PortAudio v19** - * **Win32** - * **liballegro 4.2** on DJGPP/DOS - - -Optional dependencies ---------------------- - -### libopenmpt - - * **doxygen 1.8** or higher is required to build the documentation. - -### openmpt123 - - * Rendering to PCM files can use: - * **FLAC 1.2** or higher - * **libsndfile** - * **Win32** for WAVE - * raw PCM has no external dependencies - * **help2man** is required to build the documentation. - - -Source packages ---------------- - -Building the source packages additionally requires: - * 7z (7-zip) - * autoconf - * autoconf-archive - * automake - * awk (mawk) - * git - * gzip - * help2man - * libtool - * subversion - * tar - * xpath (libxml-xpath-perl) - * zip diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/gettingstarted.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/gettingstarted.md index decf32e63..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/gettingstarted.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/gettingstarted.md @@ -1,207 +0,0 @@ - -Getting Started {#gettingstarted} -=============== - - -How to compile --------------- - - -### libopenmpt and openmpt123 - - - Autotools - - Grab a `libopenmpt-VERSION-autotools.tar.gz` tarball. - - ./configure - make - make check - sudo make install - - Cross-compilation is generally supported (although only tested for - targetting MinGW-w64). - - Note that some MinGW-w64 distributions come with the `win32` threading model - enabled by default instead of the `posix` threading model. The `win32` - threading model lacks proper support for C++11 `` and `` as - well as thread-safe magic statics. It is recommended to use the `posix` - threading model for libopenmpt for this reason. On Debian, the appropriate - configure command is - `./configure --host=x86_64-w64-mingw32 CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix` - for 64bit, or - `./configure --host=i686-w64-mingw32 CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix` - for 32bit. Other MinGW-w64 distributions may differ. - - - Visual Studio: - - - You will find solutions for Visual Studio in the matching - `build/vsVERSIONwinWINDOWSVERSION/` folder. - Minimal projects that target Windows 10 UWP are available in - `build/vsVERSIONuwp/`. - Most projects are supported with any of the mentioned Visual Studio - verions, with the following exceptions: - - - in_openmpt: Requires Visual Studio with MFC. - - - xmp-openmpt: Requires Visual Studio with MFC. - - - libopenmpt requires the compile host system to be amd64 or ARM64 when - building with Visual Studio. - - - In order to build libopenmpt for Windows XP, the Visual Studio 2017 XP - targetting toolset as well as the Windows 8.1 SDK need to be installed. - The SDK is optionally included with Visual Studio 2017, but must be - separately installed with later Visual Studio versions. - - The Windows 8.1 SDK is available from - - or directly from - - . - - - You will need the Winamp 5 SDK and the XMPlay SDK if you want to - compile the plugins for these 2 players. They can be downloaded - automatically on Windows 7 or later by just running the - `build/download_externals.cmd` script. - - If you do not want to or cannot use this script, you may follow these - manual steps instead: - - - Winamp 5 SDK: - - To build libopenmpt as a winamp input plugin, copy the contents of - `WA5.55_SDK.exe` to include/winamp/. - - Please visit - [winamp.com](http://wiki.winamp.com/wiki/Plug-in_Developer) to - download the SDK. - You can disable in_openmpt in the solution configuration. - - - XMPlay SDK: - - To build libopenmpt with XMPlay input plugin support, copy the - contents of xmp-sdk.zip into include/xmplay/. - - Please visit [un4seen.com](https://www.un4seen.com/xmplay.html) to - download the SDK. - You can disable xmp-openmpt in the solution configuration. - - - Makefile - - The makefile supports different build environments and targets via the - `CONFIG=` parameter directly to the make invocation. - Use `make CONFIG=$newconfig clean` when switching between different configs - because the makefile cleans only intermediates and target that are active - for the current config and no configuration state is kept around across - invocations. - - - native build: - - Simply run - - make - - which will try to guess the compiler based on your operating system. - - - gcc or clang (on Unix-like systems, including Mac OS X with MacPorts, - and Haiku (32-bit Hybrid and 64-bit)): - - The Makefile requires pkg-config for native builds. - For sound output in openmpt123, PortAudio or SDL is required. - openmpt123 can optionally use libflac and libsndfile to render PCM - files to disk. - - When you want to use gcc, run: - - make CONFIG=gcc - - When you want to use clang, it is recommended to do: - - make CONFIG=clang - - - mingw-w64: - - make CONFIG=mingw64-win32 # for win32 - - make CONFIG=mingw64-win64 # for win64 - - - emscripten (on Unix-like systems): - - Run: - - # generates WebAssembly with JavaScript fallback - make CONFIG=emscripten EMSCRIPTEN_TARGET=all - - or - - # generates WebAssembly - make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm - - or - - # generates JavaScript with compatibility for older VMs - make CONFIG=emscripten EMSCRIPTEN_TARGET=js - - Running the test suite on the command line is also supported by using - node.js. Depending on how your distribution calls the `node.js` binary, - you might have to edit `build/make/config-emscripten.mk`. - - - DJGPP / DOS - - Cross-compilation from Linux systems is supported with DJGPP GCC via - - make CONFIG=djgpp - - `openmpt123` can use liballegro 4.2 for sound output on DJGPP/DOS. - liballegro can either be installed system-wide in the DJGPP environment - or downloaded into the `libopenmpt` source tree. - - make CONFIG=djgpp USE_ALLEGRO42=1 # use installed liballegro - - or - - ./build/download_externals.sh # download liballegro source - make CONFIG=djgpp USE_ALLEGRO42=1 BUNDLED_ALLEGRO42=1 - - - American Fuzzy Lop: - - To compile libopenmpt with fuzzing instrumentation for afl-fuzz, run: - - make CONFIG=afl - - For more detailed instructions, read `contrib/fuzzing/readme.md`. - - - other compilers: - - To compile libopenmpt with other compliant compilers, run: - - make CONFIG=generic - - - The `Makefile` supports some customizations. You might want to read the top - which should get you some possible make settings, like e.g. - `make DYNLINK=0` or similar. Cross compiling or different compiler would - best be implemented via new `config-*.mk` files. - - The `Makefile` also supports building doxygen documentation by using - - make doc - - Binaries and documentation can be installed systen-wide with - - make PREFIX=/yourprefix install - make PREFIX=/yourprefix install-doc - - Some systems (i.e. Linux) require running - - sudo ldconfig - - in order for the system linker to be able to pick up newly installed - libraries. - - `PREFIX` defaults to `/usr/local`. A `DESTDIR=` parameter is also - supported. - - - Android NDK - - See `build/android_ndk/README.AndroidNDK.txt`. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/index.dox b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/index.dox index 4a73d7f14..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/index.dox +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/index.dox @@ -1,43 +0,0 @@ - -/*! - * \mainpage Contents - * - * libopenmpt is a cross-platform C++ and C library to decode tracked music files (modules) into a raw PCM audio stream. - * - * libopenmpt is based on the player code of the Open ModPlug Tracker project (OpenMPT, https://openmpt.org/) - * - * \section toc Contents - * - \ref md_README "README" - * - \ref dependencies "Dependencies" - * - \ref gettingstarted "Getting Started" - * - \ref packaging "Packaging" - * - \ref md_doc_contributing "Contributing" - * - \ref md_doc_libopenmpt_styleguide "libopenmpt Style Guide" - * - \ref md_doc_openmpt_styleguide "OpenMPT Style Guide" - * - \ref tests "Tests" - * - \ref changelog "Changelog" - * - \ref md_doc_module_formats "Implementing new Module Formats" - * - Issue Tracker - * \subsection toc_apis APIs - * - libopenmpt - * - \ref libopenmpt "Common Details" - * - libopenmpt C++ - * - \ref libopenmpt_cpp_overview "Overview" - * - \ref libopenmpt_cpp "Details" - * - libopenmpt C - * - \ref libopenmpt_c_overview "Overview" - * - \ref libopenmpt_c "Details" - * - libopenmpt_ext C++ - * - \ref libopenmpt_ext_cpp_overview "Overview" - * - \ref libopenmpt_ext_cpp "Details" - * - libopenmpt_ext C - * - \ref libopenmpt_ext_c_overview "Overview" - * - \ref libopenmpt_ext_c "Details" - * - * \section toc_website Website - * https://lib.openmpt.org/ - * - * \section toc_license License - * \include LICENSE - * - */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/packaging.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/packaging.md index f8cf97ba1..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/packaging.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/packaging.md @@ -1,38 +0,0 @@ -Packaging {#packaging} -========= - - -Packaging ---------- - - -### Packaging recommendations for distribution package maintainers - - * libopenmpt (since 0.3) uses SemVer 2.0.0 versioning. See - [semver.org](https://semver.org/spec/v2.0.0.html). Clause 4 is ignored for - libopenmpt, which means that libopenmpt will also provide API/ABI - compatibility semantics for pre-1.0.0 versions as required by SemVer 2.0.0 - only for post-1.0.0 versions. The SemVer versioning scheme is incompatible - with Debian/Ubuntu package versions, however it can easily be processed to - be compatible by replacing '-' (hyphen) with '~' (tilde). It is recommended - that you use this exact transformation if required. - * Use the autotools source package. - * Use the default set of dependencies required by the autotools package. - * Read \ref libopenmpt_c_staticlinking and thus possibly pass - `CXXSTDLIB_PCLIBSPRIVATE` variable to `configure` if appropriate and/or - desired. - * Run the test suite in your build process. - * Send any build system improvement patches upstream. - * Do not include the libmodplug emulation layer in the default libopenmpt - binary package. Either do not package it at all, or provide a separate - package named libopenmpt-modplug or libmodplug-openmpt (or similar), which - depends on libopenmpt, provides libmodplug, and conflicts with original - libmodplug. - * Split openmpt123 into its own binary package because it has more - dependencies than libopenmpt itself. - * Consider providing an additional openmpt123 package (in addition to the - default openmpt123 package with all audio output drivers), built with fewer - audio output drivers so it does not transitively depend on X11. Name that - package and its executable openmpt123-nox (or whatever else may be common - practice in your distribution). - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/tests.md b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/tests.md index 5b1c95957..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/tests.md +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/dox/tests.md @@ -1,44 +0,0 @@ - -Tests {#tests} -===== - - -libopenmpt provides some basic unit tests that check the platform for general -sanity and do some basic internal functionality testing. The test suite -requires a special libopenmpt build that includes file saving functionality -which is not included in normal builds. This is handled by all provided build -systems automatically. - -### Running Tests - -#### On Unix-like systems - -Compile with - - make $YOURMAKEOPTIONS clean - make $YOURMAKEOPTIONS - -and run - - make $YOURMAKEOPTIONS check - -As the build system retains no state between make invocations, you have to -provide your make options on every make invocation. - -#### Autotools-based build system - - ./configure - make check - -#### On Windows - -Using Visual Studio 20??, compile - - build\vs20??\libopenmpt_test.sln - -and run - - bin\$ARCH\libopenmpt_test.exe - -from the root of the source tree. - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp index 736c1c7e5..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt.cpp @@ -1,587 +0,0 @@ -/* - * in_openmpt.cpp - * -------------- - * Purpose: libopenmpt winamp input plugin implementation - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#ifndef NO_WINAMP - -#if defined(_MFC_VER) || 1 -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#if !defined(WINVER) && !defined(_WIN32_WINDOWS) -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP -#endif -#endif -#if !defined(MPT_BUILD_RETRO) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#else -#if defined(_WIN32_WINNT) -#if (_WIN32_WINNT >= 0x0501) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#endif -#endif -#endif -#if defined(MPT_WITH_MFC) -#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls -#endif // MPT_WITH_MFC -#ifndef NOMINMAX -#define NOMINMAX -#endif -#if defined(MPT_WITH_MFC) -#include -#include -#endif // MPT_WITH_MFC -#include -#endif // _MFC_VER - -#ifdef LIBOPENMPT_BUILD_DLL -#undef LIBOPENMPT_BUILD_DLL -#endif - -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#ifndef _SCL_SECURE_NO_WARNINGS -#define _SCL_SECURE_NO_WARNINGS -#endif -#endif // _MSC_VER - -#include "libopenmpt.hpp" - -#include "libopenmpt_plugin_settings.hpp" - -#include "libopenmpt_plugin_gui.hpp" - -#include "svn_version.h" -#if defined(OPENMPT_VERSION_REVISION) -static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION); -#else -static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING; -#endif - -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include - -#ifdef UNICODE -#define UNICODE_INPUT_PLUGIN -#endif -#ifndef _MSC_VER -#define _MSC_VER 1300 -#endif -#include "winamp/Winamp/IN2.H" -#include "winamp/Winamp/wa_ipc.h" - -#include -#include -#include -#include -#include - -#include - -#include - -#define BPS 16 - -#define WINAMP_DSP_HEADROOM_FACTOR 2 -#define WINAMP_BUFFER_SIZE_FRAMES 576 - -#define WM_OPENMPT_SEEK (WM_USER+3) - -#define SHORT_TITLE "in_openmpt" - -static void apply_options(); - -static std::string StringEncode( const std::wstring &src, UINT codepage ) -{ - int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, NULL, 0, NULL, NULL ); - if(required_size <= 0) - { - return std::string(); - } - std::vector encoded_string( required_size ); - WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), NULL, NULL ); - return &encoded_string[0]; -} - -static std::wstring StringDecode( const std::string & src, UINT codepage ) -{ - int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, NULL, 0 ); - if(required_size <= 0) - { - return std::wstring(); - } - std::vector decoded_string( required_size ); - MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() ); - return &decoded_string[0]; -} - -#if defined(UNICODE) - -static std::wstring StringToWINAPI( const std::wstring & src ) -{ - return src; -} - -#else - -static std::string StringToWINAPI( const std::wstring & src ) -{ - return StringEncode( src, CP_ACP ); -} - -#endif - -template -static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) { - std::size_t pos = 0; - const Tstring oldStr = oldStr_; - const Tstring newStr = newStr_; - while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) { - str.replace( pos, oldStr.length(), newStr ); - pos += newStr.length(); - } - return str; -} - -struct self_winamp_t { - std::vector filetypes_string; - libopenmpt::plugin::settings settings; - int samplerate; - int channels; - std::basic_string cached_filename; - std::basic_string cached_title; - int cached_length; - std::basic_string cached_infotext; - std::int64_t decode_position_frames; - openmpt::module * mod; - HANDLE PlayThread; - DWORD PlayThreadID; - bool paused; - std::vector buffer; - std::vector interleaved_buffer; - self_winamp_t() : settings(TEXT(SHORT_TITLE), true) { - filetypes_string.clear(); - settings.changed = apply_options; - settings.load(); - std::vector extensions = openmpt::get_supported_extensions(); - for ( std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext ) { - std::copy( (*ext).begin(), (*ext).end(), std::back_inserter( filetypes_string ) ); - filetypes_string.push_back('\0'); - std::copy( SHORT_TITLE, SHORT_TITLE + std::strlen(SHORT_TITLE), std::back_inserter( filetypes_string ) ); - filetypes_string.push_back('\0'); - } - filetypes_string.push_back('\0'); - samplerate = settings.samplerate; - channels = settings.channels; - cached_filename = std::basic_string(); - cached_title = std::basic_string(); - cached_length = 0; - cached_infotext = std::basic_string(); - decode_position_frames = 0; - mod = 0; - PlayThread = 0; - PlayThreadID = 0; - paused = false; - buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels ); - interleaved_buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels * WINAMP_DSP_HEADROOM_FACTOR ); - } - ~self_winamp_t() { - return; - } -}; - -static self_winamp_t * self = 0; - -static void apply_options() { - if ( self->mod ) { - self->mod->set_repeat_count( self->settings.repeatcount ); - self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel ); - self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation ); - self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength ); - self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping ); - self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false ); - switch ( self->settings.amiga_filter_type ) { - case 0: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" ); - break; - case 1: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" ); - break; - case 0xA500: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" ); - break; - case 0xA1200: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" ); - break; - } - } - self->settings.save(); -} - -extern In_Module inmod; - -static DWORD WINAPI DecodeThread( LPVOID ); - -static std::basic_string generate_infotext( const std::basic_string & filename, const openmpt::module & mod ) { - std::basic_ostringstream str; - str << TEXT("filename: ") << filename << std::endl; - str << TEXT("duration: ") << mod.get_duration_seconds() << TEXT("seconds") << std::endl; - std::vector metadatakeys = mod.get_metadata_keys(); - for ( std::vector::iterator key = metadatakeys.begin(); key != metadatakeys.end(); ++key ) { - if ( *key == "message_raw" ) { - continue; - } - str << StringToWINAPI( StringDecode( *key, CP_UTF8 ) ) << TEXT(": ") << StringToWINAPI( StringDecode( mod.get_metadata(*key), CP_UTF8 ) ) << std::endl; - } - return str.str(); -} - -static void config( HWND hwndParent ) { -#if 1 - libopenmpt::plugin::gui_edit_settings( &self->settings, hwndParent, TEXT(SHORT_TITLE) ); -#else - static_cast(hwndParent); -#endif - apply_options(); -} - -static void about( HWND hwndParent ) { - std::ostringstream about; - about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; - about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; - about << std::endl; - about << openmpt::string::get( "contact" ) << std::endl; - about << std::endl; - about << "Show full credits?" << std::endl; - if ( MessageBox( hwndParent, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) { - return; - } - std::ostringstream credits; - credits << openmpt::string::get( "credits" ); -#if 1 - libopenmpt::plugin::gui_show_file_info( hwndParent, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) ); -#else - MessageBox( hwndParent, StringToWINAPI( StringReplace(StringDecode(credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK ); -#endif -} - -static void init() { - if ( !self ) { - self = new self_winamp_t(); - inmod.FileExtensions = &(self->filetypes_string[0]); - } -} - -static void quit() { - if ( self ) { - inmod.FileExtensions = NULL; - delete self; - self = 0; - } -} - -static int isourfile( const in_char * /* fn */ ) { - return 0; -} - -static int play( const in_char * fn ) { - if ( !fn ) { - return -1; - } - try { - std::ifstream s( fn, std::ios::binary ); - std::map< std::string, std::string > ctls; - ctls["seek.sync_samples"] = "1"; - self->mod = new openmpt::module( s, std::clog, ctls ); - self->cached_filename = fn; - self->cached_title = StringToWINAPI( StringDecode( self->mod->get_metadata( "title" ), CP_UTF8 ) ); - self->cached_length = static_cast( self->mod->get_duration_seconds() * 1000.0 ); - self->cached_infotext = generate_infotext( self->cached_filename, *self->mod ); - apply_options(); - self->samplerate = self->settings.samplerate; - self->channels = self->settings.channels; - int maxlatency = inmod.outMod->Open( self->samplerate, self->channels, BPS, -1, -1 ); - std::ostringstream str; - str << maxlatency; - inmod.SetInfo( self->mod->get_num_channels(), self->samplerate/1000, self->channels, 1 ); - inmod.SAVSAInit( maxlatency, self->samplerate ); - inmod.VSASetInfo( self->channels, self->samplerate ); - inmod.outMod->SetVolume( -666 ); - inmod.outMod->SetPan( 0 ); - self->paused = false; - self->decode_position_frames = 0; - self->PlayThread = CreateThread( NULL, 0, DecodeThread, NULL, 0, &self->PlayThreadID ); - return 0; - } catch ( ... ) { - if ( self->mod ) { - delete self->mod; - self->mod = 0; - } - return -1; - } -} - -static void pause() { - self->paused = true; - inmod.outMod->Pause( 1 ); -} - -static void unpause() { - self->paused = false; - inmod.outMod->Pause( 0 ); -} - -static int ispaused() { - return self->paused ? 1 : 0; -} - -static void stop() { - PostThreadMessage( self->PlayThreadID, WM_QUIT, 0, 0 ); - WaitForSingleObject( self->PlayThread, INFINITE ); - CloseHandle( self->PlayThread ); - self->PlayThread = 0; - self->PlayThreadID = 0; - delete self->mod; - self->mod = 0; - inmod.outMod->Close(); - inmod.SAVSADeInit(); -} - -static int getlength() { - return self->cached_length; -} - -static int getoutputtime() { - //return (int)( self->decode_position_frames * 1000 / self->mod->get_render_param( openmpt::module::RENDER_SAMPLERATE_HZ ) /* + ( inmod.outMod->GetOutputTime() - inmod.outMod->GetWrittenTime() ) */ ); - return inmod.outMod->GetOutputTime(); -} - -static void setoutputtime( int time_in_ms ) { - PostThreadMessage( self->PlayThreadID, WM_OPENMPT_SEEK, 0, time_in_ms ); -} - -static void setvolume( int volume ) { - inmod.outMod->SetVolume( volume ); -} - -static void setpan( int pan ) { - inmod.outMod->SetPan( pan ); -} - -static int infobox( const in_char * fn, HWND hWndParent ) { - if ( fn && fn[0] != '\0' && self->cached_filename != std::basic_string(fn) ) { - try { - std::ifstream s( fn, std::ios::binary ); - openmpt::module mod( s ); -#if 1 - libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ) ); -#else - MessageBox( hWndParent, StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK ); -#endif - } catch ( ... ) { - } - } else { -#if 1 - libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ) ); -#else - MessageBox( hWndParent, StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK ); -#endif - } - return INFOBOX_UNCHANGED; -} - - -static void getfileinfo( const in_char * filename, in_char * title, int * length_in_ms ) { - if ( !filename || *filename == '\0' ) { - if ( length_in_ms ) { - *length_in_ms = self->cached_length; - } - if ( title ) { - std::basic_string truncated_title = self->cached_title; - if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) { - truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 ); - } - _tcscpy( title, truncated_title.c_str() ); - } - } else { - try { - std::ifstream s( filename, std::ios::binary ); - openmpt::module mod( s ); - if ( length_in_ms ) { - *length_in_ms = static_cast( mod.get_duration_seconds() * 1000.0 ); - } - if ( title ) { - std::basic_string truncated_title = StringToWINAPI( StringDecode( mod.get_metadata("title"), CP_UTF8 ) ); - if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) { - truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 ); - } - _tcscpy( title, truncated_title.c_str() ); - } - } catch ( ... ) { - } - } -} - -static void eq_set( int /* on */ , char /* data */ [10], int /* preamp */ ) { - return; -} - -static DWORD WINAPI DecodeThread( LPVOID ) { - MSG msg; - PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ); - bool eof = false; - while ( true ) { - bool quit = false; - while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { - if ( msg.message == WM_QUIT ) { - quit = true; - } else if ( msg.message == WM_OPENMPT_SEEK ) { - double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 ); - self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate); - eof = false; - inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) ); - } - } - if ( quit ) { - break; - } - if ( eof ) { - inmod.outMod->CanWrite(); // update output plugin state - if ( !inmod.outMod->IsPlaying() ) { - PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); - return 0; - } - Sleep( 10 ); - } else { - bool dsp_active = inmod.dsp_isactive() ? true : false; - if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) { - int frames = 0; - switch ( self->channels ) { - case 1: - frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES ); - for ( int frame = 0; frame < frames; frame++ ) { - self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; - } - break; - case 2: - frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES ); - for ( int frame = 0; frame < frames; frame++ ) { - self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; - self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; - } - break; - case 4: - frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+0*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+1*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+2*WINAMP_BUFFER_SIZE_FRAMES, (&(self->buffer[0]))+3*WINAMP_BUFFER_SIZE_FRAMES ); - for ( int frame = 0; frame < frames; frame++ ) { - self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; - self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; - self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame]; - self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame]; - } - break; - } - if ( frames == 0 ) { - eof = true; - } else { - self->decode_position_frames += frames; - std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate ); - inmod.SAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms ); - inmod.VSAAddPCMData( &( self->interleaved_buffer[0] ), self->channels, BPS, (int)decode_pos_ms ); - if ( dsp_active ) { - frames = inmod.dsp_dosamples( &( self->interleaved_buffer[0] ), frames, BPS, self->channels, self->samplerate ); - } - int bytes = frames * self->channels * sizeof( signed short ); - inmod.outMod->Write( (char*)&( self->interleaved_buffer[0] ), bytes ); - } - } else { - Sleep( 10 ); - } - } - } - return 0; -} - -#if defined(__GNUC__) -extern In_Module inmod; -#endif -In_Module inmod = { - IN_VER, - const_cast< char * >( in_openmpt_string ), // SHORT_TITLE, - 0, // hMainWindow - 0, // hDllInstance - NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0", - 1, // is_seekable - 1, // uses output - config, - about, - init, - quit, - getfileinfo, - infobox, - isourfile, - play, - pause, - unpause, - ispaused, - stop, - getlength, - getoutputtime, - setoutputtime, - setvolume, - setpan, - 0,0,0,0,0,0,0,0,0, // vis - 0,0, // dsp - eq_set, - NULL, // setinfo - 0 // out_mod -}; - -extern "C" __declspec(dllexport) In_Module * winampGetInModule2(); -extern "C" __declspec(dllexport) In_Module * winampGetInModule2() { - return &inmod; -} - - -#if defined(MPT_WITH_MFC) - -#ifdef _MFC_VER - -namespace libopenmpt { -namespace plugin { - -void DllMainAttach() { - // nothing -} - -void DllMainDetach() { - // nothing -} - -} // namespace plugin -} // namespace libopenmpt - -#else - -// nothing - -#endif - -#endif // MPT_WITH_MFC - - -#endif // NO_WINAMP diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp new file mode 100644 index 000000000..2a9993634 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.cpp @@ -0,0 +1,544 @@ +/* + * in_openmpt.cpp + * -------------- + * Purpose: libopenmpt winamp input plugin implementation + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + +#if defined(MPT_WITH_MFC) +#include +#include +#endif // MPT_WITH_MFC +#include + +#include "../libopenmpt.hpp" + +#include "../plugin-common/libopenmpt_plugin_settings.hpp" + +#include "../plugin-common/libopenmpt_plugin_gui.hpp" + +#if __has_include("svn_version.h") +#include "svn_version.h" +#else +#include "../../build/svn_version/svn_version.h" +#endif +#if defined(OPENMPT_VERSION_REVISION) +static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION); +#else +static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING; +#endif + +#include + +#ifdef UNICODE +#define UNICODE_INPUT_PLUGIN +#endif +#ifndef _MSC_VER +#define _MSC_VER 1300 +#endif +#include "winamp/Winamp/IN2.H" +#include "winamp/Winamp/wa_ipc.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#define BPS 16 + +#define WINAMP_DSP_HEADROOM_FACTOR 2 +#define WINAMP_BUFFER_SIZE_FRAMES 576 + +#define WM_OPENMPT_SEEK (WM_USER+3) + +#define SHORT_TITLE "in_openmpt" + +static void apply_options(); + +static std::string StringEncode( const std::wstring &src, UINT codepage ) +{ + int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, NULL, 0, NULL, NULL ); + if(required_size <= 0) + { + return std::string(); + } + std::vector encoded_string( required_size ); + WideCharToMultiByte( codepage, 0, src.c_str(), -1, encoded_string.data(), encoded_string.size(), NULL, NULL ); + return encoded_string.data(); +} + +static std::wstring StringDecode( const std::string & src, UINT codepage ) +{ + int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, NULL, 0 ); + if(required_size <= 0) + { + return std::wstring(); + } + std::vector decoded_string( required_size ); + MultiByteToWideChar( codepage, 0, src.c_str(), -1, decoded_string.data(), decoded_string.size() ); + return decoded_string.data(); +} + +#if defined(UNICODE) + +static std::wstring StringToWINAPI( const std::wstring & src ) +{ + return src; +} + +#else + +static std::string StringToWINAPI( const std::wstring & src ) +{ + return StringEncode( src, CP_ACP ); +} + +#endif + +template +static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) { + std::size_t pos = 0; + const Tstring oldStr = oldStr_; + const Tstring newStr = newStr_; + while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) { + str.replace( pos, oldStr.length(), newStr ); + pos += newStr.length(); + } + return str; +} + +struct self_winamp_t { + std::vector filetypes_string; + libopenmpt::plugin::settings settings; + int samplerate; + int channels; + std::basic_string cached_filename; + std::basic_string cached_title; + int cached_length; + std::basic_string cached_infotext; + std::int64_t decode_position_frames; + openmpt::module * mod; + HANDLE PlayThread; + DWORD PlayThreadID; + bool paused; + std::vector buffer; + std::vector interleaved_buffer; + self_winamp_t() : settings(TEXT(SHORT_TITLE), true) { + filetypes_string.clear(); + settings.changed = apply_options; + settings.load(); + std::vector extensions = openmpt::get_supported_extensions(); + for ( std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext ) { + std::copy( (*ext).begin(), (*ext).end(), std::back_inserter( filetypes_string ) ); + filetypes_string.push_back('\0'); + std::copy( SHORT_TITLE, SHORT_TITLE + std::strlen(SHORT_TITLE), std::back_inserter( filetypes_string ) ); + filetypes_string.push_back('\0'); + } + filetypes_string.push_back('\0'); + samplerate = settings.samplerate; + channels = settings.channels; + cached_filename = std::basic_string(); + cached_title = std::basic_string(); + cached_length = 0; + cached_infotext = std::basic_string(); + decode_position_frames = 0; + mod = 0; + PlayThread = 0; + PlayThreadID = 0; + paused = false; + buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels ); + interleaved_buffer.resize( WINAMP_BUFFER_SIZE_FRAMES * channels * WINAMP_DSP_HEADROOM_FACTOR ); + } + ~self_winamp_t() { + return; + } +}; + +static self_winamp_t * self = 0; + +static void apply_options() { + if ( self->mod ) { + self->mod->set_repeat_count( self->settings.repeatcount ); + self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel ); + self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation ); + self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength ); + self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping ); + self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false ); + switch ( self->settings.amiga_filter_type ) { + case 0: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" ); + break; + case 1: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" ); + break; + case 0xA500: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" ); + break; + case 0xA1200: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" ); + break; + } + } + self->settings.save(); +} + +extern In_Module inmod; + +static DWORD WINAPI DecodeThread( LPVOID ); + +static std::basic_string generate_infotext( const std::basic_string & filename, const openmpt::module & mod ) { + std::basic_ostringstream str; + str << TEXT("filename: ") << filename << std::endl; + str << TEXT("duration: ") << mod.get_duration_seconds() << TEXT("seconds") << std::endl; + std::vector metadatakeys = mod.get_metadata_keys(); + for ( std::vector::iterator key = metadatakeys.begin(); key != metadatakeys.end(); ++key ) { + if ( *key == "message_raw" ) { + continue; + } + str << StringToWINAPI( StringDecode( *key, CP_UTF8 ) ) << TEXT(": ") << StringToWINAPI( StringDecode( mod.get_metadata(*key), CP_UTF8 ) ) << std::endl; + } + return str.str(); +} + +static void config( HWND hwndParent ) { +#if 1 + libopenmpt::plugin::gui_edit_settings( &self->settings, hwndParent, TEXT(SHORT_TITLE) ); +#else + static_cast(hwndParent); +#endif + apply_options(); +} + +static void about( HWND hwndParent ) { + std::ostringstream about; + about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; + about << " Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; + about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; + about << std::endl; + about << openmpt::string::get( "contact" ) << std::endl; + about << std::endl; + about << "Show full credits?" << std::endl; + if ( MessageBox( hwndParent, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) { + return; + } + std::ostringstream credits; + credits << openmpt::string::get( "credits" ); +#if 1 + libopenmpt::plugin::gui_show_file_info( hwndParent, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) ); +#else + MessageBox( hwndParent, StringToWINAPI( StringReplace(StringDecode(credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK ); +#endif +} + +static void init() { + if ( !self ) { + self = new self_winamp_t(); + inmod.FileExtensions = self->filetypes_string.data(); + } +} + +static void quit() { + if ( self ) { + inmod.FileExtensions = NULL; + delete self; + self = 0; + } +} + +static int isourfile( const in_char * /* fn */ ) { + return 0; +} + +static int play( const in_char * fn ) { + if ( !fn ) { + return -1; + } + try { + std::ifstream s( fn, std::ios::binary ); + std::map< std::string, std::string > ctls; + self->mod = new openmpt::module( s, std::clog, ctls ); + self->cached_filename = fn; + self->cached_title = StringToWINAPI( StringDecode( self->mod->get_metadata( "title" ), CP_UTF8 ) ); + self->cached_length = static_cast( self->mod->get_duration_seconds() * 1000.0 ); + self->cached_infotext = generate_infotext( self->cached_filename, *self->mod ); + apply_options(); + self->samplerate = self->settings.samplerate; + self->channels = self->settings.channels; + int maxlatency = inmod.outMod->Open( self->samplerate, self->channels, BPS, -1, -1 ); + std::ostringstream str; + str << maxlatency; + inmod.SetInfo( self->mod->get_num_channels(), self->samplerate/1000, self->channels, 1 ); + inmod.SAVSAInit( maxlatency, self->samplerate ); + inmod.VSASetInfo( self->channels, self->samplerate ); + inmod.outMod->SetVolume( -666 ); + inmod.outMod->SetPan( 0 ); + self->paused = false; + self->decode_position_frames = 0; + self->PlayThread = CreateThread( NULL, 0, DecodeThread, NULL, 0, &self->PlayThreadID ); + return 0; + } catch ( ... ) { + if ( self->mod ) { + delete self->mod; + self->mod = 0; + } + return -1; + } +} + +static void pause() { + self->paused = true; + inmod.outMod->Pause( 1 ); +} + +static void unpause() { + self->paused = false; + inmod.outMod->Pause( 0 ); +} + +static int ispaused() { + return self->paused ? 1 : 0; +} + +static void stop() { + PostThreadMessage( self->PlayThreadID, WM_QUIT, 0, 0 ); + WaitForSingleObject( self->PlayThread, INFINITE ); + CloseHandle( self->PlayThread ); + self->PlayThread = 0; + self->PlayThreadID = 0; + delete self->mod; + self->mod = 0; + inmod.outMod->Close(); + inmod.SAVSADeInit(); +} + +static int getlength() { + return self->cached_length; +} + +static int getoutputtime() { + //return (int)( self->decode_position_frames * 1000 / self->mod->get_render_param( openmpt::module::RENDER_SAMPLERATE_HZ ) /* + ( inmod.outMod->GetOutputTime() - inmod.outMod->GetWrittenTime() ) */ ); + return inmod.outMod->GetOutputTime(); +} + +static void setoutputtime( int time_in_ms ) { + PostThreadMessage( self->PlayThreadID, WM_OPENMPT_SEEK, 0, time_in_ms ); +} + +static void setvolume( int volume ) { + inmod.outMod->SetVolume( volume ); +} + +static void setpan( int pan ) { + inmod.outMod->SetPan( pan ); +} + +static int infobox( const in_char * fn, HWND hWndParent ) { + if ( fn && fn[0] != '\0' && self->cached_filename != std::basic_string(fn) ) { + try { + std::ifstream s( fn, std::ios::binary ); + openmpt::module mod( s ); +#if 1 + libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ) ); +#else + MessageBox( hWndParent, StringReplace( generate_infotext( fn, mod ), TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK ); +#endif + } catch ( ... ) { + } + } else { +#if 1 + libopenmpt::plugin::gui_show_file_info( hWndParent, TEXT(SHORT_TITLE), StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ) ); +#else + MessageBox( hWndParent, StringReplace( self->cached_infotext, TEXT("\n"), TEXT("\r\n") ).c_str(), TEXT(SHORT_TITLE), MB_OK ); +#endif + } + return INFOBOX_UNCHANGED; +} + + +static void getfileinfo( const in_char * filename, in_char * title, int * length_in_ms ) { + if ( !filename || *filename == '\0' ) { + if ( length_in_ms ) { + *length_in_ms = self->cached_length; + } + if ( title ) { + std::basic_string truncated_title = self->cached_title; + if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) { + truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 ); + } + _tcscpy( title, truncated_title.c_str() ); + } + } else { + try { + std::ifstream s( filename, std::ios::binary ); + openmpt::module mod( s ); + if ( length_in_ms ) { + *length_in_ms = static_cast( mod.get_duration_seconds() * 1000.0 ); + } + if ( title ) { + std::basic_string truncated_title = StringToWINAPI( StringDecode( mod.get_metadata("title"), CP_UTF8 ) ); + if ( truncated_title.length() >= GETFILEINFO_TITLE_LENGTH ) { + truncated_title.resize( GETFILEINFO_TITLE_LENGTH - 1 ); + } + _tcscpy( title, truncated_title.c_str() ); + } + } catch ( ... ) { + } + } +} + +static void eq_set( int /* on */ , char /* data */ [10], int /* preamp */ ) { + return; +} + +static DWORD WINAPI DecodeThread( LPVOID ) { + MSG msg; + PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ); + bool eof = false; + while ( true ) { + bool quit = false; + while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { + if ( msg.message == WM_QUIT ) { + quit = true; + } else if ( msg.message == WM_OPENMPT_SEEK ) { + double pos_seconds = self->mod->set_position_seconds( msg.lParam * 0.001 ); + self->decode_position_frames = (std::int64_t)( pos_seconds * (double)self->samplerate); + eof = false; + inmod.outMod->Flush( (int)( pos_seconds * 1000.0 ) ); + } + } + if ( quit ) { + break; + } + if ( eof ) { + inmod.outMod->CanWrite(); // update output plugin state + if ( !inmod.outMod->IsPlaying() ) { + PostMessage( inmod.hMainWindow, WM_WA_MPEG_EOF, 0, 0 ); + return 0; + } + Sleep( 10 ); + } else { + bool dsp_active = inmod.dsp_isactive() ? true : false; + if ( inmod.outMod->CanWrite() >= (int)( WINAMP_BUFFER_SIZE_FRAMES * self->channels * sizeof( signed short ) ) * ( dsp_active ? WINAMP_DSP_HEADROOM_FACTOR : 1 ) ) { + int frames = 0; + switch ( self->channels ) { + case 1: + frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 0*WINAMP_BUFFER_SIZE_FRAMES ); + for ( int frame = 0; frame < frames; frame++ ) { + self->interleaved_buffer[frame*1+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; + } + break; + case 2: + frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 0*WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 1*WINAMP_BUFFER_SIZE_FRAMES ); + for ( int frame = 0; frame < frames; frame++ ) { + self->interleaved_buffer[frame*2+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; + self->interleaved_buffer[frame*2+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; + } + break; + case 4: + frames = self->mod->read( self->samplerate, WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 0*WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 1*WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 2*WINAMP_BUFFER_SIZE_FRAMES, self->buffer.data() + 3*WINAMP_BUFFER_SIZE_FRAMES ); + for ( int frame = 0; frame < frames; frame++ ) { + self->interleaved_buffer[frame*4+0] = self->buffer[0*WINAMP_BUFFER_SIZE_FRAMES+frame]; + self->interleaved_buffer[frame*4+1] = self->buffer[1*WINAMP_BUFFER_SIZE_FRAMES+frame]; + self->interleaved_buffer[frame*4+2] = self->buffer[2*WINAMP_BUFFER_SIZE_FRAMES+frame]; + self->interleaved_buffer[frame*4+3] = self->buffer[3*WINAMP_BUFFER_SIZE_FRAMES+frame]; + } + break; + } + if ( frames == 0 ) { + eof = true; + } else { + self->decode_position_frames += frames; + std::int64_t decode_pos_ms = (self->decode_position_frames * 1000 / self->samplerate ); + inmod.SAAddPCMData( self->interleaved_buffer.data(), self->channels, BPS, (int)decode_pos_ms ); + inmod.VSAAddPCMData( self->interleaved_buffer.data(), self->channels, BPS, (int)decode_pos_ms ); + if ( dsp_active ) { + frames = inmod.dsp_dosamples( self->interleaved_buffer.data(), frames, BPS, self->channels, self->samplerate ); + } + int bytes = frames * self->channels * sizeof( signed short ); + inmod.outMod->Write( (char*)self->interleaved_buffer.data(), bytes ); + } + } else { + Sleep( 10 ); + } + } + } + return 0; +} + +#if defined(__GNUC__) +extern In_Module inmod; +#endif +In_Module inmod = { + IN_VER, + const_cast< char * >( in_openmpt_string ), // SHORT_TITLE, + 0, // hMainWindow + 0, // hDllInstance + NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0", + 1, // is_seekable + 1, // uses output + config, + about, + init, + quit, + getfileinfo, + infobox, + isourfile, + play, + pause, + unpause, + ispaused, + stop, + getlength, + getoutputtime, + setoutputtime, + setvolume, + setpan, + 0,0,0,0,0,0,0,0,0, // vis + 0,0, // dsp + eq_set, + NULL, // setinfo + 0 // out_mod +}; + +extern "C" __declspec(dllexport) In_Module * winampGetInModule2(); +extern "C" __declspec(dllexport) In_Module * winampGetInModule2() { + return &inmod; +} + + +#if defined(MPT_WITH_MFC) + +#ifdef _MFC_VER + +namespace libopenmpt { +namespace plugin { + +void DllMainAttach() { + // nothing +} + +void DllMainDetach() { + // nothing +} + +} // namespace plugin +} // namespace libopenmpt + +#else + +// nothing + +#endif + +#endif // MPT_WITH_MFC diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.txt b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.txt new file mode 100644 index 000000000..94ef4095b --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/in_openmpt/in_openmpt.txt @@ -0,0 +1,17 @@ + +in_openmpt +========== + +in_openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input +plugin for Winamp >= 2.0 (or compatible players). in_openmpt is based on +libopenmpt. + + +Installation +------------ + +"in_openmpt.dll" must be placed into the Winamp "Plugins" directory, and +"openmpt-mpg123.dll" must be placed into the Winamp directory. + + +See https://lib.openmpt.org/ for documentation, FAQ and other details. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h index 0c1627223..20115190f 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.h @@ -568,13 +568,13 @@ LIBOPENMPT_API size_t openmpt_probe_file_header_get_recommended_size(void); /*! Probe for no formats in openmpt_probe_file_header() or openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_FLAGS_NONE 0x0ull -/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ +/*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file will most likely be supported by libopenmpt. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS 1 -/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ +/*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): The file is not supported by libopenmpt. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE 0 -/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ +/*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An answer could not be determined with the amount of data provided. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA (-1) -/*! Possible return values fo openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(). \since 0.3.0 */ +/*! Possible return values for openmpt_probe_file_header() and openmpt_probe_file_header_without_filesize(): An internal error occurred. \since 0.3.0 */ #define OPENMPT_PROBE_FILE_HEADER_RESULT_ERROR (-255) /*! \brief Probe the provided bytes from the beginning of a file for supported file format headers to find out whether libopenmpt might be able to open it @@ -1159,8 +1159,16 @@ LIBOPENMPT_API int32_t openmpt_module_get_current_speed( openmpt_module * mod ); * * \param mod The module handle to work on. * \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + * \deprecated Please use openmpt_module_get_current_tempo2(). */ -LIBOPENMPT_API int32_t openmpt_module_get_current_tempo( openmpt_module * mod ); +LIBOPENMPT_API LIBOPENMPT_DEPRECATED int32_t openmpt_module_get_current_tempo( openmpt_module * mod ); +/*! \brief Get the current tempo + * + * \param mod The module handle to work on. + * \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + * \since 0.7.0 + */ +LIBOPENMPT_API double openmpt_module_get_current_tempo2( openmpt_module * mod ); /*! \brief Get the current order * * \param mod The module handle to work on. @@ -1409,11 +1417,11 @@ LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel( openmp * - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory * - load.skip_plugins (boolean): Set to "1" to avoid loading plugins * - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - * - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. + * - seek.sync_samples (boolean): Set to "0" to not sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row. * - subsong (integer): The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong. - * - play.at_end (text): Chooses the behaviour when the end of song is reached: + * - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt_module_set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. * - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - * - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. + * - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumsed from the song start). * - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. * - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. * - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp index 922807168..06d847257 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt.hpp @@ -142,17 +142,17 @@ namespace openmpt { Base class used for all exceptions that are thrown by libopenmpt itself. Libopenmpt may additionally throw any exception thrown by the standard library which are all derived from std::exception. \sa \ref libopenmpt_cpp_error */ -class LIBOPENMPT_CXX_API exception : public std::exception { +class LIBOPENMPT_CXX_API_CLASS exception : public std::exception { private: char * text; public: - exception( const std::string & text ) noexcept; - exception( const exception & other ) noexcept; - exception( exception && other ) noexcept; - exception & operator = ( const exception & other ) noexcept; - exception & operator = ( exception && other ) noexcept; - virtual ~exception() noexcept; - const char * what() const noexcept override; + LIBOPENMPT_CXX_API_MEMBER exception( const std::string & text ) noexcept; + LIBOPENMPT_CXX_API_MEMBER exception( const exception & other ) noexcept; + LIBOPENMPT_CXX_API_MEMBER exception( exception && other ) noexcept; + LIBOPENMPT_CXX_API_MEMBER exception & operator = ( const exception & other ) noexcept; + LIBOPENMPT_CXX_API_MEMBER exception & operator = ( exception && other ) noexcept; + LIBOPENMPT_CXX_API_MEMBER virtual ~exception() noexcept; + LIBOPENMPT_CXX_API_MEMBER const char * what() const noexcept override; }; // class exception #if defined(_MSC_VER) #pragma warning(pop) @@ -298,8 +298,11 @@ enum probe_file_header_flags : std::uint64_t { //! Possible return values for openmpt::probe_file_header(). \since 0.3.0 enum probe_file_header_result { + //! The file will most likely be supported by libopenmpt. \since 0.3.0 probe_file_header_result_success = 1, + //! The file is not supported by libopenmpt. \since 0.3.0 probe_file_header_result_failure = 0, + //! An answer could not be determined with the amount of data provided. \since 0.3.0 probe_file_header_result_wantmoredata = -1 }; @@ -394,7 +397,7 @@ typedef std::map< std::string, std::string > initial_ctls_map; } // namespace detail -class LIBOPENMPT_CXX_API module { +class LIBOPENMPT_CXX_API_CLASS module { friend class module_ext; @@ -470,7 +473,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. @@ -480,7 +483,7 @@ public: \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ - module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. @@ -491,7 +494,7 @@ public: \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ - module( const std::byte * beg, const std::byte * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::byte * beg, const std::byte * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. @@ -502,7 +505,7 @@ public: \sa \ref libopenmpt_cpp_fileio \since 0.5.0 */ - module( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. @@ -511,7 +514,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. @@ -521,7 +524,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::uint8_t * beg, const std::uint8_t * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. @@ -531,7 +534,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param log Log where any warnings or errors are printed to. The lifetime of the reference has to be as long as the lifetime of the module instance. @@ -540,7 +543,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param beg Begin of data to load the module from. \param end End of data to load the module from. @@ -550,7 +553,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const char * beg, const char * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const char * beg, const char * end, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. @@ -560,7 +563,7 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); /*! \param data Data to load the module from. \param size Amount of data available. @@ -570,8 +573,8 @@ public: \remarks The input data can be discarded after an openmpt::module has been constructed successfully. \sa \ref libopenmpt_cpp_fileio */ - module( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - virtual ~module(); + LIBOPENMPT_CXX_API_MEMBER module( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER virtual ~module(); public: //! Select a sub-song from a multi-song module @@ -581,14 +584,14 @@ public: \sa openmpt::module::get_num_subsongs, openmpt::module::get_selected_subsong, openmpt::module::get_subsong_names \remarks Whether subsong -1 (all subsongs consecutively), subsong 0 or some other subsong is selected by default, is an implementation detail and subject to change. If you do not want to care about subsongs, it is recommended to just not call openmpt::module::select_subsong() at all. */ - void select_subsong( std::int32_t subsong ); + LIBOPENMPT_CXX_API_MEMBER void select_subsong( std::int32_t subsong ); //! Get currently selected sub-song from a multi-song module /*! \return Currently selected sub-song. -1 for all subsongs consecutively, 0 or greater for the current sub-song index. \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_subsong_names \since 0.3.0 */ - std::int32_t get_selected_subsong() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_selected_subsong() const; //! Set Repeat Count /*! \param repeat_count Repeat Count @@ -597,7 +600,7 @@ public: - n>0: play once and repeat n times after that \sa openmpt::module::get_repeat_count */ - void set_repeat_count( std::int32_t repeat_count ); + LIBOPENMPT_CXX_API_MEMBER void set_repeat_count( std::int32_t repeat_count ); //! Get Repeat Count /*! \return Repeat Count @@ -606,14 +609,14 @@ public: - n>0: play once and repeat n times after that \sa openmpt::module::set_repeat_count */ - std::int32_t get_repeat_count() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_repeat_count() const; //! Get approximate song duration /*! \return Approximate duration of current sub-song in seconds. \remarks The function may return infinity if the pattern data is too complex to evaluate. */ - double get_duration_seconds() const; + LIBOPENMPT_CXX_API_MEMBER double get_duration_seconds() const; //! Set approximate current song position /*! @@ -621,13 +624,13 @@ public: \return Approximate new song position in seconds. \sa openmpt::module::get_position_seconds */ - double set_position_seconds( double seconds ); + LIBOPENMPT_CXX_API_MEMBER double set_position_seconds( double seconds ); //! Get current song position /*! \return Current song position in seconds. \sa openmpt::module::set_position_seconds */ - double get_position_seconds() const; + LIBOPENMPT_CXX_API_MEMBER double get_position_seconds() const; //! Set approximate current song position /*! @@ -638,7 +641,7 @@ public: \sa openmpt::module::set_position_seconds \sa openmpt::module::get_position_seconds */ - double set_position_order_row( std::int32_t order, std::int32_t row ); + LIBOPENMPT_CXX_API_MEMBER double set_position_order_row( std::int32_t order, std::int32_t row ); //! Get render parameter /*! @@ -648,7 +651,7 @@ public: \sa openmpt::module::render_param \sa openmpt::module::set_render_param */ - std::int32_t get_render_param( int param ) const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_render_param( int param ) const; //! Set render parameter /*! \param param Parameter to set. See openmpt::module::render_param. @@ -657,7 +660,7 @@ public: \sa openmpt::module::render_param \sa openmpt::module::get_render_param */ - void set_render_param( int param, std::int32_t value ); + LIBOPENMPT_CXX_API_MEMBER void set_render_param( int param, std::int32_t value ); /*@{*/ //! Render audio data @@ -672,7 +675,7 @@ public: \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * mono ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -686,7 +689,7 @@ public: \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -702,7 +705,7 @@ public: \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, std::int16_t * left, std::int16_t * right, std::int16_t * rear_left, std::int16_t * rear_right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -715,7 +718,7 @@ public: \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, float * mono ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * mono ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -729,7 +732,7 @@ public: \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -745,7 +748,7 @@ public: \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read( std::int32_t samplerate, std::size_t count, float * left, float * right, float * rear_left, float * rear_right ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -758,7 +761,7 @@ public: \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_stereo ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -771,7 +774,7 @@ public: \remarks It is recommended to use the floating point API because of the greater dynamic range and no implied clipping. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, std::int16_t * interleaved_quad ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -784,7 +787,7 @@ public: \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_stereo( std::int32_t samplerate, std::size_t count, float * interleaved_stereo ); //! Render audio data /*! \param samplerate Sample rate to render output. Should be in [8000,192000], but this is not enforced. @@ -797,7 +800,7 @@ public: \remarks Floating point samples are in the [-1.0..1.0] nominal range. They are not clipped to that range though and thus might overshoot. \sa \ref libopenmpt_cpp_outputformat */ - std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ); + LIBOPENMPT_CXX_API_MEMBER std::size_t read_interleaved_quad( std::int32_t samplerate, std::size_t count, float * interleaved_quad ); /*@}*/ //! Get the list of supported metadata item keys @@ -805,7 +808,7 @@ public: \return Metadata item keys supported by openmpt::module::get_metadata \sa openmpt::module::get_metadata */ - std::vector get_metadata_keys() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_metadata_keys() const; //! Get a metadata item value /*! \param key Metadata item key to query. Use openmpt::module::get_metadata_keys to check for available keys. @@ -826,7 +829,7 @@ public: \return The associated value for key. \sa openmpt::module::get_metadata_keys */ - std::string get_metadata( const std::string & key ) const; + LIBOPENMPT_CXX_API_MEMBER std::string get_metadata( const std::string & key ) const; //! Get the current estimated beats per minute (BPM). /*! @@ -834,37 +837,44 @@ public: \remarks Due to the nature of how module tempo works, the estimate may change slightly after switching libopenmpt's output to a different sample rate. \return The current estimated BPM. */ - double get_current_estimated_bpm() const; + LIBOPENMPT_CXX_API_MEMBER double get_current_estimated_bpm() const; //! Get the current speed /*! \return The current speed in ticks per row. */ - std::int32_t get_current_speed() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_speed() const; //! Get the current tempo /*! \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + \deprecated Please use openmpt::module::get_current_tempo2(). */ - std::int32_t get_current_tempo() const; + LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED std::int32_t get_current_tempo() const; + //! Get the current tempo + /*! + \return The current tempo in tracker units. The exact meaning of this value depends on the tempo mode being used. + \since 0.7.0 + */ + LIBOPENMPT_CXX_API_MEMBER double get_current_tempo2() const; //! Get the current order /*! \return The current order at which the module is being played back. */ - std::int32_t get_current_order() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_order() const; //! Get the current pattern /*! \return The current pattern that is being played. */ - std::int32_t get_current_pattern() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_pattern() const; //! Get the current row /*! \return The current row at which the current pattern is being played. */ - std::int32_t get_current_row() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_row() const; //! Get the current amount of playing channels. /*! \return The amount of sample channels that are currently being rendered. */ - std::int32_t get_current_playing_channels() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_current_playing_channels() const; //! Get an approximate indication of the channel volume. /*! @@ -872,119 +882,119 @@ public: \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ - float get_current_channel_vu_mono( std::int32_t channel ) const; + LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_mono( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the front-left speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ - float get_current_channel_vu_left( std::int32_t channel ) const; + LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_left( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the front-right speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ - float get_current_channel_vu_right( std::int32_t channel ) const; + LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_right( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the rear-left speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ - float get_current_channel_vu_rear_left( std::int32_t channel ) const; + LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_rear_left( std::int32_t channel ) const; //! Get an approximate indication of the channel volume on the rear-right speaker. /*! \param channel The channel whose volume should be retrieved. \return The approximate channel volume. \remarks The returned value is solely based on the note velocity and does not take the actual waveform of the playing sample into account. */ - float get_current_channel_vu_rear_right( std::int32_t channel ) const; + LIBOPENMPT_CXX_API_MEMBER float get_current_channel_vu_rear_right( std::int32_t channel ) const; //! Get the number of sub-songs /*! \return The number of sub-songs in the module. This includes any "hidden" songs (songs that share the same sequence, but start at different order indices) and "normal" sub-songs or "sequences" (if the format supports them). \sa openmpt::module::get_subsong_names, openmpt::module::select_subsong, openmpt::module::get_selected_subsong */ - std::int32_t get_num_subsongs() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_subsongs() const; //! Get the number of pattern channels /*! \return The number of pattern channels in the module. Not all channels do necessarily contain data. \remarks The number of pattern channels is completely independent of the number of output channels. libopenmpt can render modules in mono, stereo or quad surround, but the choice of which of the three modes to use must not be made based on the return value of this function, which may be any positive integer amount. Only use this function for informational purposes. */ - std::int32_t get_num_channels() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_channels() const; //! Get the number of orders /*! \return The number of orders in the current sequence of the module. */ - std::int32_t get_num_orders() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_orders() const; //! Get the number of patterns /*! \return The number of distinct patterns in the module. */ - std::int32_t get_num_patterns() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_patterns() const; //! Get the number of instruments /*! \return The number of instrument slots in the module. Instruments are a layer on top of samples, and are not supported by all module formats. */ - std::int32_t get_num_instruments() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_instruments() const; //! Get the number of samples /*! \return The number of sample slots in the module. */ - std::int32_t get_num_samples() const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_num_samples() const; //! Get a list of sub-song names /*! \return All sub-song names. \sa openmpt::module::get_num_subsongs, openmpt::module::select_subsong, openmpt::module::get_selected_subsong */ - std::vector get_subsong_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_subsong_names() const; //! Get a list of channel names /*! \return All channel names. \sa openmpt::module::get_num_channels */ - std::vector get_channel_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_channel_names() const; //! Get a list of order names /*! \return All order names. \sa openmpt::module::get_num_orders */ - std::vector get_order_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_order_names() const; //! Get a list of pattern names /*! \return All pattern names. \sa openmpt::module::get_num_patterns */ - std::vector get_pattern_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_pattern_names() const; //! Get a list of instrument names /*! \return All instrument names. \sa openmpt::module::get_num_instruments */ - std::vector get_instrument_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_instrument_names() const; //! Get a list of sample names /*! \return All sample names. \sa openmpt::module::get_num_samples */ - std::vector get_sample_names() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_sample_names() const; //! Get pattern at order position /*! \param order The order item whose pattern index should be retrieved. \return The pattern index found at the given order position of the current sequence. */ - std::int32_t get_order_pattern( std::int32_t order ) const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_order_pattern( std::int32_t order ) const; //! Get the number of rows in a pattern /*! \param pattern The pattern whose row count should be retrieved. \return The number of rows in the given pattern. If the pattern does not exist, 0 is returned. */ - std::int32_t get_pattern_num_rows( std::int32_t pattern ) const; + LIBOPENMPT_CXX_API_MEMBER std::int32_t get_pattern_num_rows( std::int32_t pattern ) const; //! Get raw pattern content /*! @@ -994,7 +1004,7 @@ public: \param command The cell index at which the data should be retrieved. See openmpt::module::command_index \return The internal, raw pattern data at the given pattern position. */ - std::uint8_t get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; + LIBOPENMPT_CXX_API_MEMBER std::uint8_t get_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get formatted (human-readable) pattern content /*! @@ -1005,7 +1015,7 @@ public: \return The formatted pattern data at the given pattern position. See openmpt::module::command_index \sa openmpt::module::highlight_pattern_row_channel_command */ - std::string format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; + LIBOPENMPT_CXX_API_MEMBER std::string format_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get highlighting information for formatted pattern content /*! @@ -1027,7 +1037,7 @@ public: - "f" : generic effect column parameter \sa openmpt::module::get_pattern_row_channel_command */ - std::string highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; + LIBOPENMPT_CXX_API_MEMBER std::string highlight_pattern_row_channel_command( std::int32_t pattern, std::int32_t row, std::int32_t channel, int command ) const; //! Get formatted (human-readable) pattern content /*! @@ -1039,7 +1049,7 @@ public: \return The formatted pattern data at the given pattern position. \sa openmpt::module::highlight_pattern_row_channel */ - std::string format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; + LIBOPENMPT_CXX_API_MEMBER std::string format_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; //! Get highlighting information for formatted pattern content /*! \param pattern The pattern whose data should be retrieved. @@ -1050,7 +1060,7 @@ public: \return The highlighting string for the formatted pattern data as retrieved by openmpt::module::format_pattern_row_channel at the given pattern position. \sa openmpt::module::format_pattern_row_channel */ - std::string highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; + LIBOPENMPT_CXX_API_MEMBER std::string highlight_pattern_row_channel( std::int32_t pattern, std::int32_t row, std::int32_t channel, std::size_t width = 0, bool pad = true ) const; //! Retrieve supported ctl keys /*! @@ -1060,11 +1070,11 @@ public: - load.skip_patterns (boolean): Set to "1" to avoid loading patterns into memory - load.skip_plugins (boolean): Set to "1" to avoid loading plugins - load.skip_subsongs_init (boolean): Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking. - - seek.sync_samples (boolean): Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. + - seek.sync_samples (boolean): Set to "0" to not sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row. - subsong (integer): The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong. - - play.at_end (text): Chooses the behaviour when the end of song is reached: + - play.at_end (text): Chooses the behaviour when the end of song is reached. The song end is considered to be reached after the number of reptitions set by openmpt::module::set_repeat_count was played, so if the song is set to repeat infinitely, its end is never considered to be reached. - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames. - - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start. + - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the loop start (if the song is not programmed to loop, playback resumsed from the song start). - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames. - play.tempo_factor (floatingpoint): Set a floating point tempo factor. "1.0" is the default tempo. - play.pitch_factor (floatingpoint): Set a floating point pitch factor. "1.0" is the default pitch. @@ -1083,7 +1093,7 @@ public: An exclamation mark ("!") or a question mark ("?") can be appended to any ctl key in order to influence the behaviour in case of an unknown ctl key. "!" causes an exception to be thrown; "?" causes the ctl to be silently ignored. In case neither is appended to the key name, unknown init_ctls are ignored by default and other ctls throw an exception by default. */ - std::vector get_ctls() const; + LIBOPENMPT_CXX_API_MEMBER std::vector get_ctls() const; //! Get current ctl value /*! @@ -1092,7 +1102,7 @@ public: \sa openmpt::module::get_ctls \deprecated Please use openmpt::module::ctl_get_boolean(), openmpt::module::ctl_get_integer(), openmpt::module::ctl_get_floatingpoint(), or openmpt::module::ctl_get_text(). */ - LIBOPENMPT_ATTR_DEPRECATED std::string ctl_get( const std::string & ctl ) const; + LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED std::string ctl_get( const std::string & ctl ) const; //! Get current ctl boolean value /*! \param ctl The ctl key whose value should be retrieved. @@ -1100,7 +1110,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - bool ctl_get_boolean( std::string_view ctl ) const; + LIBOPENMPT_CXX_API_MEMBER bool ctl_get_boolean( std::string_view ctl ) const; //! Get current ctl integer value /*! \param ctl The ctl key whose value should be retrieved. @@ -1108,7 +1118,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - std::int64_t ctl_get_integer( std::string_view ctl ) const; + LIBOPENMPT_CXX_API_MEMBER std::int64_t ctl_get_integer( std::string_view ctl ) const; //! Get current ctl floatingpoint value /*! \param ctl The ctl key whose value should be retrieved. @@ -1116,7 +1126,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - double ctl_get_floatingpoint( std::string_view ctl ) const; + LIBOPENMPT_CXX_API_MEMBER double ctl_get_floatingpoint( std::string_view ctl ) const; //! Get current ctl text value /*! \param ctl The ctl key whose value should be retrieved. @@ -1124,7 +1134,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - std::string ctl_get_text( std::string_view ctl ) const; + LIBOPENMPT_CXX_API_MEMBER std::string ctl_get_text( std::string_view ctl ) const; //! Set ctl value /*! @@ -1134,7 +1144,7 @@ public: \sa openmpt::module::get_ctls \deprecated Please use openmpt::module::ctl_set_boolean(), openmpt::module::ctl_set_integer(), openmpt::module::ctl_set_floatingpoint(), or openmpt::module::ctl_set_text(). */ - LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value ); + LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_ATTR_DEPRECATED void ctl_set( const std::string & ctl, const std::string & value ); //! Set ctl boolean value /*! \param ctl The ctl key whose value should be set. @@ -1143,7 +1153,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - void ctl_set_boolean( std::string_view ctl, bool value ); + LIBOPENMPT_CXX_API_MEMBER void ctl_set_boolean( std::string_view ctl, bool value ); //! Set ctl integer value /*! \param ctl The ctl key whose value should be set. @@ -1152,7 +1162,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - void ctl_set_integer( std::string_view ctl, std::int64_t value ); + LIBOPENMPT_CXX_API_MEMBER void ctl_set_integer( std::string_view ctl, std::int64_t value ); //! Set ctl floatingpoint value /*! \param ctl The ctl key whose value should be set. @@ -1161,7 +1171,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - void ctl_set_floatingpoint( std::string_view ctl, double value ); + LIBOPENMPT_CXX_API_MEMBER void ctl_set_floatingpoint( std::string_view ctl, double value ); //! Set ctl text value /*! \param ctl The ctl key whose value should be set. @@ -1170,7 +1180,7 @@ public: \sa openmpt::module::get_ctls \since 0.5.0 */ - void ctl_set_text( std::string_view ctl, std::string_view value ); + LIBOPENMPT_CXX_API_MEMBER void ctl_set_text( std::string_view ctl, std::string_view value ); // remember to add new functions to both C and C++ interfaces and to increase OPENMPT_API_VERSION_MINOR diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp index 121a81992..9faab6a9a 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_c.cpp @@ -9,6 +9,10 @@ #include "openmpt/all/BuildSettings.hpp" +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + #include "libopenmpt_internal.h" #include "libopenmpt.h" #include "libopenmpt_ext.h" @@ -967,6 +971,15 @@ int32_t openmpt_module_get_current_tempo( openmpt_module * mod ) { } return 0; } +double openmpt_module_get_current_tempo2( openmpt_module * mod ) { + try { + openmpt::interface::check_soundfile( mod ); + return mod->impl->get_current_tempo2(); + } catch ( ... ) { + openmpt::report_exception( __func__, mod ); + } + return 0; +} int32_t openmpt_module_get_current_order( openmpt_module * mod ) { try { openmpt::interface::check_soundfile( mod ); @@ -1786,6 +1799,19 @@ static double get_note_finetune( openmpt_module_ext * mod_ext, int32_t channel ) +static int set_current_tempo2( openmpt_module_ext * mod_ext, double tempo ) { + try { + openmpt::interface::check_soundfile( mod_ext ); + mod_ext->impl->set_current_tempo2( tempo ); + return 1; + } catch ( ... ) { + openmpt::report_exception( __func__, mod_ext ? &mod_ext->mod : NULL ); + } + return 0; +} + + + /* add stuff here */ @@ -1844,6 +1870,13 @@ int openmpt_module_ext_get_interface( openmpt_module_ext * mod_ext, const char * + } else if ( !std::strcmp( interface_id, LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 ) && ( interface_size == sizeof( openmpt_module_ext_interface_interactive3 ) ) ) { + openmpt_module_ext_interface_interactive3 * i = static_cast< openmpt_module_ext_interface_interactive3 * >( interface ); + i->set_current_tempo2 = &set_current_tempo2; + result = 1; + + + /* add stuff here */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_config.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_config.h index 01ec4793f..ba6e33264 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_config.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_config.h @@ -32,11 +32,20 @@ @{ */ -/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. */ +/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_buffer.h exists. + * \remarks + * Use the following to check for availability: + * \code + * #include + * #if defined(LIBOPENMPT_STREAM_CALLBACKS_BUFFER) + * #include + * #endif + * \endcode + */ #define LIBOPENMPT_STREAM_CALLBACKS_BUFFER /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_fd.h exists. - * \since 0.3 + * \since 0.3.0 * \remarks * Use the following to check for availability: * \code @@ -49,7 +58,7 @@ #define LIBOPENMPT_STREAM_CALLBACKS_FD /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file.h exists. - * \since 0.3 + * \since 0.3.0 * \remarks * Use the following to check for availability: * \code @@ -61,6 +70,66 @@ */ #define LIBOPENMPT_STREAM_CALLBACKS_FILE + /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_mingw.h exists. + * \since 0.7.0 + * \remarks + * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. + * It is the libopenmpt user's responsibility to check for availability of the _off64_t, _ftelli64(), and _fseeki64(). + * Use the following to check for availability: + * \code + * #include + * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW) + * #include + * #endif + * \endcode + */ +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW + + /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h exists. + * \since 0.7.0 + * \remarks + * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. + * It is the libopenmpt user's responsibility to check for availability of the __int64, _ftelli64(), and _fseeki64(). + * Use the following to check for availability: + * \code + * #include + * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT) + * #include + * #endif + * \endcode + */ +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT + + /*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_posix.h exists. + * \since 0.7.0 + * \remarks + * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. + * It is the libopenmpt user's responsibility to check for availability of the _off_t, ftello(), and fseeko(). + * Use the following to check for availability: + * \code + * #include + * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW) + * #include + * #endif + * \endcode + */ +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX + +/*! \brief Defined if libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h exists. + * \since 0.7.0 + * \remarks + * This macro does not determine if the interfaces required to use libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h are available. + * It is the libopenmpt user's responsibility to check for availability of the off64_t, ftello64(), and fseeko64(). + * Use the following to check for availability: + * \code + * #include + * #if defined(LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64) + * #include + * #endif + * \endcode + */ +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64 + /*! @} */ @@ -80,8 +149,15 @@ #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport) -#define LIBOPENMPT_API_HELPER_PUBLIC -#define LIBOPENMPT_API_HELPER_LOCAL +#define LIBOPENMPT_API_HELPER_PUBLIC +#define LIBOPENMPT_API_HELPER_LOCAL + +#ifdef __cplusplus +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS +#endif #elif defined(__EMSCRIPTEN__) @@ -90,6 +166,17 @@ #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) __attribute__((used)) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) +#ifdef __cplusplus +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) +#define LIBOPENMPT_API_HELPER_EXPORT_MEMBER __attribute__((visibility("default"))) __attribute__((used)) +#define LIBOPENMPT_API_HELPER_IMPORT_MEMBER __attribute__((visibility("default"))) __attribute__((used)) +#define LIBOPENMPT_API_HELPER_PUBLIC_MEMBER __attribute__((visibility("default"))) __attribute__((used)) +#define LIBOPENMPT_API_HELPER_LOCAL_MEMBER __attribute__((visibility("hidden"))) +#endif + #elif (defined(__GNUC__) || defined(__clang__)) && defined(_WIN32) #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) @@ -97,6 +184,13 @@ #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) +#ifdef __cplusplus +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) +#endif + #elif defined(__GNUC__) || defined(__clang__) #define LIBOPENMPT_API_HELPER_EXPORT __attribute__((visibility("default"))) @@ -104,12 +198,28 @@ #define LIBOPENMPT_API_HELPER_PUBLIC __attribute__((visibility("default"))) #define LIBOPENMPT_API_HELPER_LOCAL __attribute__((visibility("hidden"))) +#ifdef __cplusplus +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS __attribute__((visibility("default"))) +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS __attribute__((visibility("hidden"))) +#endif + #elif defined(_WIN32) #define LIBOPENMPT_API_HELPER_EXPORT __declspec(dllexport) #define LIBOPENMPT_API_HELPER_IMPORT __declspec(dllimport) -#define LIBOPENMPT_API_HELPER_PUBLIC -#define LIBOPENMPT_API_HELPER_LOCAL +#define LIBOPENMPT_API_HELPER_PUBLIC +#define LIBOPENMPT_API_HELPER_LOCAL + +#ifdef __cplusplus + +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS __declspec(dllexport) +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS __declspec(dllimport) +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS + +#endif #else @@ -120,33 +230,71 @@ #endif +#ifdef __cplusplus + +#ifndef LIBOPENMPT_API_HELPER_EXPORT_CLASS +#define LIBOPENMPT_API_HELPER_EXPORT_CLASS +#endif +#ifndef LIBOPENMPT_API_HELPER_EXPORT_MEMBER +#define LIBOPENMPT_API_HELPER_EXPORT_MEMBER +#endif +#ifndef LIBOPENMPT_API_HELPER_IMPORT_CLASS +#define LIBOPENMPT_API_HELPER_IMPORT_CLASS +#endif +#ifndef LIBOPENMPT_API_HELPER_IMPORT_MEMBER +#define LIBOPENMPT_API_HELPER_IMPORT_MEMBER +#endif +#ifndef LIBOPENMPT_API_HELPER_PUBLIC_CLASS +#define LIBOPENMPT_API_HELPER_PUBLIC_CLASS +#endif +#ifndef LIBOPENMPT_API_HELPER_PUBLIC_MEMBER +#define LIBOPENMPT_API_HELPER_PUBLIC_MEMBER +#endif +#ifndef LIBOPENMPT_API_HELPER_LOCAL_CLASS +#define LIBOPENMPT_API_HELPER_LOCAL_CLASS +#endif +#ifndef LIBOPENMPT_API_HELPER_LOCAL_MEMBER +#define LIBOPENMPT_API_HELPER_LOCAL_MEMBER +#endif + +#endif + #if defined(LIBOPENMPT_BUILD_DLL) -#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_EXPORT +#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_EXPORT #elif defined(LIBOPENMPT_USE_DLL) -#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_IMPORT +#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_IMPORT #else -#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_PUBLIC +#define LIBOPENMPT_API LIBOPENMPT_API_HELPER_PUBLIC #endif #ifdef __cplusplus -#define LIBOPENMPT_CXX_API LIBOPENMPT_API +#if defined(LIBOPENMPT_BUILD_DLL) +#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_EXPORT +#define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_EXPORT_CLASS +#define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_EXPORT_MEMBER +#elif defined(LIBOPENMPT_USE_DLL) +#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_IMPORT +#define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_IMPORT_CLASS +#define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_IMPORT_MEMBER +#else +#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_PUBLIC +#define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_PUBLIC_CLASS +#define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_PUBLIC_MEMBER +#endif #if defined(LIBOPENMPT_USE_DLL) #if defined(_MSC_VER) && !defined(_DLL) #error "C++ interface is disabled if libopenmpt is built as a DLL and the runtime is statically linked. This is not supported by microsoft and cannot possibly work. Ever." #undef LIBOPENMPT_CXX_API #define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL +#undef LIBOPENMPT_CXX_API_CLASS +#define LIBOPENMPT_CXX_API_CLASS LIBOPENMPT_API_HELPER_LOCAL_CLASS +#undef LIBOPENMPT_CXX_API_MEMBER +#define LIBOPENMPT_CXX_API_MEMBER LIBOPENMPT_API_HELPER_LOCAL_MEMBER #endif #endif -#if defined(__EMSCRIPTEN__) - -/* Only the C API is supported for emscripten. Disable the C++ API. */ -#undef LIBOPENMPT_CXX_API -#define LIBOPENMPT_CXX_API LIBOPENMPT_API_HELPER_LOCAL -#endif - #endif /*! @@ -181,6 +329,16 @@ LIBOPENMPT_DEPRECATED static const int LIBOPENMPT_DEPRECATED_STRING_CONSTANT = 0 #define LIBOPENMPT_DEPRECATED_STRING( str ) str #endif +#if defined(__STDC__) && (__STDC__ == 1) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define LIBOPENMPT_C_INLINE inline +#else +#define LIBOPENMPT_C_INLINE +#endif +#else +#define LIBOPENMPT_C_INLINE +#endif + /* C++ */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_cxx.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_cxx.cpp index 7b743c379..4290b7bed 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_cxx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_cxx.cpp @@ -9,6 +9,10 @@ #include "openmpt/all/BuildSettings.hpp" +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + #include "libopenmpt_internal.h" #include "libopenmpt.hpp" #include "libopenmpt_ext.hpp" @@ -312,6 +316,9 @@ std::int32_t module::get_current_speed() const { std::int32_t module::get_current_tempo() const { return impl->get_current_tempo(); } +double module::get_current_tempo2() const { + return impl->get_current_tempo2(); +} std::int32_t module::get_current_order() const { return impl->get_current_order(); } diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.h index 82f500f25..5263c5bd9 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.h @@ -162,8 +162,9 @@ typedef struct openmpt_module_ext_interface_interactive { * \return 1 on success, 0 on failure. * \remarks The tempo may be reset by pattern commands at any time. Use openmpt_module_ext_interface_interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. * \sa openmpt_module_get_current_tempo + * \deprecated Please use openmpt_module_ext_interface_interactive3::set_current_tempo2(). */ - int ( * set_current_tempo ) ( openmpt_module_ext * mod_ext, int32_t tempo ); + LIBOPENMPT_DEPRECATED int ( * set_current_tempo ) ( openmpt_module_ext * mod_ext, int32_t tempo ); /*! Set the current module tempo factor without affecting playback pitch * @@ -389,6 +390,26 @@ typedef struct openmpt_module_ext_interface_interactive2 { +#ifndef LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 +#define LIBOPENMPT_EXT_C_INTERFACE_INTERACTIVE3 "interactive3" +#endif + +typedef struct openmpt_module_ext_interface_interactive3 { + + /*! Set the current module tempo + * + * \param mod_ext The module handle to work on. + * \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. + * \return 1 on success, 0 on failure. + * \remarks The tempo may be reset by pattern commands at any time. Use openmpt_module_ext_interface_interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. + * \sa openmpt_module_get_current_tempo2 + */ + int ( * set_current_tempo2 ) ( openmpt_module_ext * mod_ext, double tempo ); + +} openmpt_module_ext_interface_interactive3; + + + /* add stuff here */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.hpp index 85577d95b..71524d2b6 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext.hpp @@ -34,24 +34,24 @@ namespace openmpt { class module_ext_impl; -class LIBOPENMPT_CXX_API module_ext : public module { +class LIBOPENMPT_CXX_API_CLASS module_ext : public module { private: module_ext_impl * ext_impl; private: // non-copyable - module_ext( const module_ext & ); - void operator = ( const module_ext & ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const module_ext & ); + LIBOPENMPT_CXX_API_MEMBER void operator = ( const module_ext & ); public: - module_ext( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - module_ext( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); - virtual ~module_ext(); + LIBOPENMPT_CXX_API_MEMBER module_ext( std::istream & stream, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const std::vector & data, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const std::byte * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const std::uint8_t * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const char * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER module_ext( const void * data, std::size_t size, std::ostream & log = std::clog, const std::map< std::string, std::string > & ctls = detail::initial_ctls_map() ); + LIBOPENMPT_CXX_API_MEMBER virtual ~module_ext(); public: @@ -73,7 +73,7 @@ public: \param interface_id The name of the extension interface to retrieve. \return The interface object. This may be a nullptr if the extension was not found. */ - void * get_interface( const std::string & interface_id ); + LIBOPENMPT_CXX_API_MEMBER void * get_interface( const std::string & interface_id ); }; // class module_ext @@ -170,8 +170,9 @@ class interactive { \throws openmpt::exception Throws an exception derived from openmpt::exception if the tempo is outside the specified range. \remarks The tempo may be reset by pattern commands at any time. Use openmpt::ext:interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. \sa openmpt::module::get_current_tempo + \deprecated Please use openmpt::ext::interactive3::set_current_tempo2(). */ - virtual void set_current_tempo( std::int32_t tempo ) = 0; + LIBOPENMPT_ATTR_DEPRECATED virtual void set_current_tempo( std::int32_t tempo ) = 0; //! Set the current module tempo factor without affecting playback pitch /*! @@ -383,7 +384,31 @@ class interactive2 { */ virtual double get_note_finetune( int32_t channel ) = 0; -}; // class interactive +}; // class interactive2 + + +#ifndef LIBOPENMPT_EXT_INTERFACE_INTERACTIVE3 +#define LIBOPENMPT_EXT_INTERFACE_INTERACTIVE3 +#endif + +LIBOPENMPT_DECLARE_EXT_CXX_INTERFACE(interactive3) + +class interactive3 { + + LIBOPENMPT_EXT_CXX_INTERFACE(interactive3) + + //! Set the current module tempo + /*! + \param tempo The new tempo in range [32, 512]. The exact meaning of the value depends on the tempo mode used by the module. + \throws openmpt::exception Throws an exception derived from openmpt::exception if the tempo is outside the specified range. + \remarks The tempo may be reset by pattern commands at any time. Use openmpt::ext:interactive::set_tempo_factor to apply a tempo factor that is independent of pattern commands. + \sa openmpt::module::get_current_tempo2 + \since 0.7.0 + */ + virtual void set_current_tempo2( double tempo ) = 0; + +}; // class interactive3 + /* add stuff here */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.cpp index 1de804bb8..d108290b9 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.cpp @@ -85,6 +85,8 @@ namespace openmpt { return dynamic_cast< ext::interactive * >( this ); } else if ( interface_id == ext::interactive2_id ) { return dynamic_cast< ext::interactive2 * >( this ); + } else if ( interface_id == ext::interactive3_id ) { + return dynamic_cast< ext::interactive3 * >( this ); @@ -100,25 +102,25 @@ namespace openmpt { // pattern_vis module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const { - std::uint8_t byte = get_pattern_row_channel_command( pattern, row, channel, module::command_volumeffect ); - switch ( OpenMPT::ModCommand::GetVolumeEffectType( byte ) ) { - case OpenMPT::EFFECT_TYPE_NORMAL : return effect_general; break; - case OpenMPT::EFFECT_TYPE_GLOBAL : return effect_global ; break; - case OpenMPT::EFFECT_TYPE_VOLUME : return effect_volume ; break; - case OpenMPT::EFFECT_TYPE_PANNING: return effect_panning; break; - case OpenMPT::EFFECT_TYPE_PITCH : return effect_pitch ; break; + auto volcmd = static_cast( get_pattern_row_channel_command( pattern, row, channel, module::command_volumeffect ) ); + switch ( OpenMPT::ModCommand::GetVolumeEffectType( volcmd ) ) { + case OpenMPT::EffectType::Normal : return effect_general; break; + case OpenMPT::EffectType::Global : return effect_global ; break; + case OpenMPT::EffectType::Volume : return effect_volume ; break; + case OpenMPT::EffectType::Panning: return effect_panning; break; + case OpenMPT::EffectType::Pitch : return effect_pitch ; break; default: return effect_unknown; break; } } module_ext_impl::effect_type module_ext_impl::get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const { - std::uint8_t byte = get_pattern_row_channel_command( pattern, row, channel, module::command_effect ); - switch (OpenMPT::ModCommand::GetEffectType( byte ) ) { - case OpenMPT::EFFECT_TYPE_NORMAL : return effect_general; break; - case OpenMPT::EFFECT_TYPE_GLOBAL : return effect_global ; break; - case OpenMPT::EFFECT_TYPE_VOLUME : return effect_volume ; break; - case OpenMPT::EFFECT_TYPE_PANNING: return effect_panning; break; - case OpenMPT::EFFECT_TYPE_PITCH : return effect_pitch ; break; + auto command = static_cast( get_pattern_row_channel_command( pattern, row, channel, module::command_effect ) ); + switch (OpenMPT::ModCommand::GetEffectType( command ) ) { + case OpenMPT::EffectType::Normal : return effect_general; break; + case OpenMPT::EffectType::Global : return effect_global ; break; + case OpenMPT::EffectType::Volume : return effect_volume ; break; + case OpenMPT::EffectType::Panning: return effect_panning; break; + case OpenMPT::EffectType::Pitch : return effect_pitch ; break; default: return effect_unknown; break; } } @@ -344,6 +346,13 @@ namespace openmpt { return chn.microTuning / 32768.0; } + void module_ext_impl::set_current_tempo2( double tempo ) { + if ( tempo < 32.0 || tempo > 512.0 ) { + throw openmpt::exception("invalid tempo"); + } + m_sndFile->m_PlayState.m_nMusicTempo = decltype( m_sndFile->m_PlayState.m_nMusicTempo )( tempo ); + } + /* add stuff here */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.hpp index afc6520b7..478ab0de0 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_ext_impl.hpp @@ -21,6 +21,7 @@ class module_ext_impl , public ext::pattern_vis , public ext::interactive , public ext::interactive2 + , public ext::interactive3 @@ -112,6 +113,8 @@ public: double get_note_finetune( std::int32_t channel ) override; + void set_current_tempo2(double tempo) override; + /* add stuff here */ }; // class module_ext_impl diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp index 105d8e9d8..c14345807 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.cpp @@ -27,11 +27,13 @@ #include "mpt/audio/span.hpp" #include "mpt/base/algorithm.hpp" +#include "mpt/base/detect.hpp" #include "mpt/base/saturate_cast.hpp" #include "mpt/base/saturate_round.hpp" #include "mpt/format/default_integer.hpp" #include "mpt/format/default_floatingpoint.hpp" #include "mpt/format/default_string.hpp" +#include "mpt/format/join.hpp" #include "mpt/io_read/callbackstream.hpp" #include "mpt/io_read/filecursor_callbackstream.hpp" #include "mpt/io_read/filecursor_memory.hpp" @@ -59,36 +61,16 @@ OPENMPT_NAMESPACE_BEGIN #if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS) -#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT -#if defined(NTDDI_VERSION) -#if (NTDDI_VERSION < 0x06020000) +#if MPT_WINRT_BEFORE(MPT_WIN_8) MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define NTDDI_VERSION 0x0602000.") -#endif -#elif defined(_WIN32_WINNT) -#if (_WIN32_WINNT < 0x0602) -MPT_WARNING("Warning: libopenmpt for WinRT is built with reduced functionality. Please #define _WIN32_WINNT 0x0602.") -#endif // _WIN32_WINNT -#endif // _WIN32_WINNT -#endif // MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT - -#if defined(MPT_BUILD_MSVC) || defined(MPT_BUILD_VCPKG) -#if MPT_OS_WINDOWS_WINRT -#pragma comment(lib, "ole32.lib") -#else -#pragma comment(lib, "rpcrt4.lib") -#endif -#endif // MPT_BUILD_MSVC +#endif // MPT_WINRT_BEFORE(MPT_WIN_8) #if MPT_PLATFORM_MULTITHREADED && MPT_MUTEX_NONE MPT_WARNING("Warning: libopenmpt built in non thread-safe mode because mutexes are not supported by the C++ standard library available.") #endif // MPT_MUTEX_NONE -#if (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) -#if defined(MPT_WITH_MINGWSTDTHREADS) -MPT_WARNING("Warning: Building with mingw-std-threads is deprecated because this is not supported with GCC 11 or later.") -#else // !MINGWSTDTHREADS +#if MPT_OS_WINDOWS && (defined(__MINGW32__) || defined(__MINGW64__)) && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS) MPT_WARNING("Warning: Platform (Windows) supports multi-threading, however the toolchain (MinGW/GCC) does not. The resulting libopenmpt may not be thread-safe. This is a MinGW/GCC issue. You can avoid this warning by using a MinGW toolchain built with posix threading model as opposed to win32 threading model.") -#endif // MINGWSTDTHREADS #endif // MINGW #if MPT_CLANG_AT_LEAST(5,0,0) && MPT_CLANG_BEFORE(11,0,0) && defined(__powerpc__) && !defined(__powerpc64__) @@ -102,11 +84,11 @@ MPT_WARNING("Warning: libopenmpt is known to trigger bad code generation with Cl MPT_NOINLINE void AssertHandler(const mpt::source_location &loc, const char *expr, const char *msg) { if(msg) { mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT", - MPT_USTRING("ASSERTION FAILED: ") + mpt::ToUnicode(mpt::CharsetSource, msg) + MPT_USTRING(" (") + mpt::ToUnicode(mpt::CharsetSource, expr) + MPT_USTRING(")") + MPT_USTRING("ASSERTION FAILED: ") + mpt::transcode(mpt::source_encoding, msg) + MPT_USTRING(" (") + mpt::transcode(mpt::source_encoding, expr) + MPT_USTRING(")") ); } else { mpt::log::GlobalLogger().SendLogMessage(loc, LogError, "ASSERT", - MPT_USTRING("ASSERTION FAILED: ") + mpt::ToUnicode(mpt::CharsetSource, expr) + MPT_USTRING("ASSERTION FAILED: ") + mpt::transcode(mpt::source_encoding, expr) ); } #if defined(MPT_BUILD_FATAL_ASSERTS) @@ -157,62 +139,62 @@ static std::string get_library_version_string() { } if ( !fields.empty() ) { str += "+"; - str += OpenMPT::mpt::String::Combine( fields, std::string(".") ); + str += OpenMPT::mpt::join_format( fields, std::string(".") ); } return str; } static std::string get_library_features_string() { - return mpt::transcode( mpt::common_encoding::utf8, mpt::trim(OpenMPT::Build::GetBuildFeaturesString())); + return mpt::transcode( mpt::common_encoding::utf8, mpt::trim( OpenMPT::Build::GetBuildFeaturesString() ) ); } static std::string get_core_version_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetVersionStringExtended()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetVersionStringExtended() ); } static std::string get_source_url_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().GetUrlWithRevision()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().GetUrlWithRevision() ); } static std::string get_source_date_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().Date()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::SourceInfo::Current().Date() ); } static std::string get_source_revision_string() { const OpenMPT::SourceInfo sourceInfo = OpenMPT::SourceInfo::Current(); - return sourceInfo.Revision() ? mpt::format_value_default(sourceInfo.Revision()) : std::string(); + return sourceInfo.Revision() ? mpt::format_value_default( sourceInfo.Revision() ) : std::string(); } static std::string get_build_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildDateString()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildDateString() ); } static std::string get_build_compiler_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildCompilerString()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetBuildCompilerString() ); } static std::string get_credits_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetFullCreditsString()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetFullCreditsString() ); } static std::string get_contact_string() { - return mpt::transcode( mpt::common_encoding::utf8, MPT_USTRING("Forum: ") + OpenMPT::Build::GetURL(OpenMPT::Build::Url::Forum)); + return mpt::transcode( mpt::common_encoding::utf8, MPT_USTRING("Forum: ") + OpenMPT::Build::GetURL( OpenMPT::Build::Url::Forum ) ); } static std::string get_license_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetLicenseString()); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetLicenseString() ); } static std::string get_url_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Website)); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Website ) ); } static std::string get_support_forum_url_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Forum)); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Forum ) ); } static std::string get_bugtracker_url_string() { - return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL(OpenMPT::Build::Url::Bugtracker)); + return mpt::transcode( mpt::common_encoding::utf8, OpenMPT::Build::GetURL( OpenMPT::Build::Url::Bugtracker ) ); } std::string get_string( const std::string & key ) { @@ -480,7 +462,7 @@ void module_impl::ctor( const std::map< std::string, std::string > & ctls ) { m_ctl_load_skip_patterns = false; m_ctl_load_skip_plugins = false; m_ctl_load_skip_subsongs_init = false; - m_ctl_seek_sync_samples = false; + m_ctl_seek_sync_samples = true; // init member variables that correspond to ctls for ( const auto & ctl : ctls ) { ctl_set( ctl.first, ctl.second, false ); @@ -960,7 +942,7 @@ std::int32_t module_impl::get_render_param( int param ) const { void module_impl::set_render_param( int param, std::int32_t value ) { switch ( param ) { case module::RENDER_MASTERGAIN_MILLIBEL: { - m_Gain = static_cast( std::pow( 10.0f, value * 0.001f * 0.5f ) ); + m_Gain = std::pow( 10.0f, static_cast( value ) * 0.001f * 0.5f ); } break; case module::RENDER_STEREOSEPARATION_PERCENT: { std::int32_t newvalue = value * OpenMPT::MixerSettings::StereoSeparationScale / 100; @@ -1081,7 +1063,7 @@ std::size_t module_impl::read_interleaved_quad( std::int32_t samplerate, std::si double module_impl::get_duration_seconds() const { - std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); + std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( m_current_subsong == all_subsongs ) { // Play all subsongs consecutively. @@ -1094,7 +1076,7 @@ double module_impl::get_duration_seconds() const { return subsongs[m_current_subsong].duration; } void module_impl::select_subsong( std::int32_t subsong ) { - std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); + std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; if ( subsong != all_subsongs && ( subsong < 0 || subsong >= static_cast( subsongs.size() ) ) ) { throw openmpt::exception("invalid subsong"); @@ -1121,7 +1103,7 @@ double module_impl::get_position_seconds() const { return m_currentPositionSeconds; } double module_impl::set_position_seconds( double seconds ) { - std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); + std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; const subsong_data * subsong = 0; double base_seconds = 0.0; @@ -1241,7 +1223,7 @@ std::string module_impl::get_metadata( const std::string & key ) const { if ( m_sndFile->GetFileHistory().empty() || !m_sndFile->GetFileHistory().back().HasValidDate() ) { return std::string(); } - return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->GetFileHistory().back().AsISO8601() ); + return mpt::transcode( mpt::common_encoding::utf8, m_sndFile->GetFileHistory().back().AsISO8601( m_sndFile->GetTimezoneInternal() ) ); } else if ( key == std::string("message") ) { std::string retval = m_sndFile->m_songMessage.GetFormatted( OpenMPT::SongMessage::leLF ); if ( retval.empty() ) { @@ -1323,6 +1305,9 @@ std::int32_t module_impl::get_current_speed() const { std::int32_t module_impl::get_current_tempo() const { return static_cast( m_sndFile->m_PlayState.m_nMusicTempo.GetInt() ); } +double module_impl::get_current_tempo2() const { + return m_sndFile->m_PlayState.m_nMusicTempo.ToDouble(); +} std::int32_t module_impl::get_current_order() const { return m_sndFile->GetCurrentOrder(); } @@ -1378,7 +1363,7 @@ float module_impl::get_current_channel_vu_rear_right( std::int32_t channel ) con } std::int32_t module_impl::get_num_subsongs() const { - std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); + std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; return static_cast( subsongs.size() ); } @@ -1400,7 +1385,7 @@ std::int32_t module_impl::get_num_samples() const { std::vector module_impl::get_subsong_names() const { std::vector retval; - std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); + std::unique_ptr subsongs_temp = has_subsongs_inited() ? std::unique_ptr() : std::make_unique( get_subsongs() ); const subsongs_type & subsongs = has_subsongs_inited() ? m_subsongs : *subsongs_temp; retval.reserve( subsongs.size() ); for ( const auto & subsong : subsongs ) { @@ -1932,13 +1917,13 @@ void module_impl::ctl_set( std::string ctl, const std::string & value, bool thro } switch ( found_ctl->type ) { case ctl_type::boolean: - ctl_set_boolean( ctl, mpt::ConvertStringTo( value ), throw_if_unknown ); + ctl_set_boolean( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::integer: - ctl_set_integer( ctl, mpt::ConvertStringTo( value ), throw_if_unknown ); + ctl_set_integer( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::floatingpoint: - ctl_set_floatingpoint( ctl, mpt::ConvertStringTo( value ), throw_if_unknown ); + ctl_set_floatingpoint( ctl, mpt::parse( value ), throw_if_unknown ); break; case ctl_type::text: ctl_set_text( ctl, value, throw_if_unknown ); diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.hpp index d8c60452f..58018baa8 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_impl.hpp @@ -25,6 +25,11 @@ // forward declarations namespace mpt { inline namespace mpt_libopenmpt { +template +class BasicPathString; +struct NativePathTraits; +struct Utf8PathTraits; +using native_path = BasicPathString; namespace IO { class FileCursorTraitsFileData; template @@ -40,7 +45,11 @@ template using FileCursor = mpt::IO::FileCursor; } // namespace detail namespace mpt { -class PathString; +#if defined(MPT_ENABLE_CHARSET_LOCALE) +using PathString = mpt::native_path; +#else +using PathString = mpt::BasicPathString; +#endif } // namespace mpt using FileCursor = detail::FileCursor>; class CSoundFile; @@ -212,6 +221,7 @@ public: double get_current_estimated_bpm() const; std::int32_t get_current_speed() const; std::int32_t get_current_tempo() const; + double get_current_tempo2() const; std::int32_t get_current_order() const; std::int32_t get_current_pattern() const; std::int32_t get_current_row() const; diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.cpp index c185b21fd..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.cpp @@ -1,497 +0,0 @@ -/* - * libopenmpt_plugin_gui.cpp - * ------------------------- - * Purpose: libopenmpt plugin GUI - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#if !defined(WINVER) && !defined(_WIN32_WINDOWS) -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP -#endif -#endif -#if !defined(MPT_BUILD_RETRO) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#else -#if defined(_WIN32_WINNT) -#if (_WIN32_WINNT >= 0x0501) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#endif -#endif -#endif -#if defined(MPT_WITH_MFC) -#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls -#endif // MPT_WITH_MFC -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#if !defined(MPT_WITH_MFC) -#include -#include -#include -#include -#include -#endif - -#if !defined(MPT_WITH_MFC) -#include -#endif - -#if defined(MPT_WITH_MFC) -#include -#include -#endif // MPT_WITH_MFC - -#if defined(MPT_WITH_MFC) -#include "resource.h" -#endif // MPT_WITH_MFC - -#include "libopenmpt_plugin_gui.hpp" - - -namespace libopenmpt { -namespace plugin { - - -#if defined(MPT_WITH_MFC) - - -class CSettingsApp : public CWinApp { - -public: - - BOOL InitInstance() override { - if ( !CWinApp::InitInstance() ) - { - return FALSE; - } - DllMainAttach(); - return TRUE; - } - - int ExitInstance() override { - DllMainDetach(); - return CWinApp::ExitInstance(); - } - -}; - - -CSettingsApp theApp; - - -class CSettingsDialog : public CDialog { - -protected: - - DECLARE_MESSAGE_MAP() - - libopenmpt_settings * s; - - CString m_Title; - - CComboBox m_ComboBoxSamplerate; - CComboBox m_ComboBoxChannels; - CSliderCtrl m_SliderCtrlGain; - CComboBox m_ComboBoxInterpolation; - CButton m_CheckBoxAmigaResampler; - CComboBox m_ComboBoxAmigaFilter; - CComboBox m_ComboBoxRepeat; - CSliderCtrl m_SliderCtrlStereoSeparation; - CComboBox m_ComboBoxRamping; - -public: - - CSettingsDialog( libopenmpt_settings * s_, CString title, CWnd * parent = nullptr ) - : CDialog( IDD_SETTINGS, parent ) - , s( s_ ) - , m_Title( title ) - { - return; - } - -protected: - - void DoDataExchange( CDataExchange * pDX ) override - { - CDialog::DoDataExchange( pDX ); - DDX_Control( pDX, IDC_COMBO_SAMPLERATE, m_ComboBoxSamplerate ); - DDX_Control( pDX, IDC_COMBO_CHANNELS, m_ComboBoxChannels ); - DDX_Control( pDX, IDC_SLIDER_GAIN, m_SliderCtrlGain ); - DDX_Control( pDX, IDC_COMBO_INTERPOLATION, m_ComboBoxInterpolation ); - DDX_Control( pDX, IDC_CHECK_AMIGA_RESAMPLER, m_CheckBoxAmigaResampler ); - DDX_Control( pDX, IDC_COMBO_AMIGA_FILTER, m_ComboBoxAmigaFilter ); - DDX_Control( pDX, IDC_COMBO_REPEAT, m_ComboBoxRepeat ); - DDX_Control( pDX, IDC_SLIDER_STEREOSEPARATION, m_SliderCtrlStereoSeparation ); - DDX_Control( pDX, IDC_COMBO_RAMPING, m_ComboBoxRamping ); - } - - afx_msg BOOL OnInitDialog() override { - - CDialog::OnInitDialog(); - - SetWindowText( m_Title ); - EnableToolTips(); - - bool selected = false; - - selected = false; - if ( !s->no_default_format ) { - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"Default" ), 0 ); - } - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"6000" ), 6000 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"8000" ), 8000 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"11025" ), 11025 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"16000" ), 16000 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"22050" ), 22050 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"32000" ), 32000 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"44100" ), 44100 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"48000" ), 48000 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"88200" ), 88200 ); - m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"96000" ), 96000 ); - if ( !s->no_default_format && s->samplerate == 0 ) { - m_ComboBoxSamplerate.SelectString( 0, L"Default" ); - } - for ( int index = 0; index < m_ComboBoxSamplerate.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxSamplerate.GetItemData( index ) ) == s->samplerate ) { - m_ComboBoxSamplerate.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxSamplerate.SelectString( 0, L"48000" ); - } - - selected = false; - if ( !s->no_default_format ) { - m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Default" ), 0 ); - } - m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Mono" ), 1 ); - m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Stereo" ), 2 ); - m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Quad" ), 4 ); - if ( !s->no_default_format && s->channels == 0 ) { - m_ComboBoxChannels.SelectString( 0, L"Default" ); - } - for ( int index = 0; index < m_ComboBoxChannels.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxChannels.GetItemData( index ) ) == s->channels ) { - m_ComboBoxChannels.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxChannels.SelectString( 0, L"Stereo" ); - } - - m_SliderCtrlGain.SetRange( -1200, 1200 ); - m_SliderCtrlGain.SetTicFreq( 100 ); - m_SliderCtrlGain.SetPageSize( 300 ); - m_SliderCtrlGain.SetLineSize( 100 ); - m_SliderCtrlGain.SetPos( s->mastergain_millibel ); - - selected = false; - m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"Off / 1 Tap (Nearest)" ), 1 ); - m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"2 Tap (Linear)" ), 2 ); - m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"4 Tap (Cubic)" ), 4 ); - m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"8 Tap (Polyphase FIR)" ), 8 ); - for ( int index = 0; index < m_ComboBoxInterpolation.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxInterpolation.GetItemData( index ) ) == s->interpolationfilterlength ) { - m_ComboBoxInterpolation.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxInterpolation.SelectString( 0, L"8 Tap (Polyphase FIR)" ); - } - - m_CheckBoxAmigaResampler.SetCheck( s->use_amiga_resampler ? BST_CHECKED : BST_UNCHECKED ); - selected = false; - m_ComboBoxAmigaFilter.EnableWindow( s->use_amiga_resampler ? TRUE : FALSE ); - m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Default" ), 0 ); - m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A500 Filter" ), 0xA500 ); - m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A1200 Filter" ), 0xA1200 ); - m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Unfiltered" ), 1 ); - for ( int index = 0; index < m_ComboBoxAmigaFilter.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxAmigaFilter.GetItemData( index ) ) == s->amiga_filter_type ) { - m_ComboBoxAmigaFilter.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxAmigaFilter.SelectString( 0, L"Default" ); - } - - selected = false; - m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Forever" ), static_cast( -1 ) ); - m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Never" ), 0 ); - m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Once" ), 1 ); - for ( int index = 0; index < m_ComboBoxRepeat.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxRepeat.GetItemData( index ) ) == s->repeatcount ) { - m_ComboBoxRepeat.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxRepeat.SelectString( 0, L"Never" ); - } - - m_SliderCtrlStereoSeparation.SetRange( 0, 200 ); - m_SliderCtrlStereoSeparation.SetTicFreq( 100 ); - m_SliderCtrlStereoSeparation.SetPageSize( 25 ); - m_SliderCtrlStereoSeparation.SetLineSize( 5 ); - m_SliderCtrlStereoSeparation.SetPos( s->stereoseparation ); - - selected = false; - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Default" ), static_cast( -1 ) ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Off" ), 0 ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"1 ms" ), 1 ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"2 ms" ), 2 ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"3 ms" ), 3 ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"5 ms" ), 5 ); - m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"10 ms" ), 10 ); - for ( int index = 0; index < m_ComboBoxRamping.GetCount(); ++index ) { - if ( static_cast( m_ComboBoxRamping.GetItemData( index ) ) == s->ramping ) { - m_ComboBoxRamping.SetCurSel( index ); - selected = true; - } - } - if ( !selected ) { - m_ComboBoxRamping.SelectString( 0, L"Default" ); - } - - return TRUE; - - } - - void OnOK() override { - - s->samplerate = m_ComboBoxSamplerate.GetItemData( m_ComboBoxSamplerate.GetCurSel() ); - - s->channels = m_ComboBoxChannels.GetItemData( m_ComboBoxChannels.GetCurSel() ); - - s->mastergain_millibel = m_SliderCtrlGain.GetPos(); - - s->interpolationfilterlength = m_ComboBoxInterpolation.GetItemData( m_ComboBoxInterpolation.GetCurSel() ); - - s->use_amiga_resampler = ( m_CheckBoxAmigaResampler.GetCheck() != BST_UNCHECKED ) ? 1 : 0; - s->amiga_filter_type = m_ComboBoxAmigaFilter.GetItemData( m_ComboBoxAmigaFilter.GetCurSel() ); - - s->repeatcount = m_ComboBoxRepeat.GetItemData( m_ComboBoxRepeat.GetCurSel() ); - - s->stereoseparation = m_SliderCtrlStereoSeparation.GetPos(); - - s->ramping = m_ComboBoxRamping.GetItemData( m_ComboBoxRamping.GetCurSel() ); - - s->changed(); - - CDialog::OnOK(); - - } - - BOOL OnToolTipText( UINT, NMHDR * pNMHDR, LRESULT * pResult ) { - TOOLTIPTEXT * pTTT = reinterpret_cast( pNMHDR ); - - UINT_PTR nID = pNMHDR->idFrom; - if( pTTT->uFlags & TTF_IDISHWND ) - { - // idFrom is actually the HWND of the tool - nID = (UINT_PTR)::GetDlgCtrlID((HWND)nID); - } - - switch ( nID ) { - case IDC_SLIDER_GAIN: - swprintf( pTTT->szText, _countof(pTTT->szText), L"%.02f dB", m_SliderCtrlGain.GetPos() * 0.01f ); - break; - - case IDC_SLIDER_STEREOSEPARATION: - swprintf( pTTT->szText, _countof(pTTT->szText), L"%d %%", m_SliderCtrlStereoSeparation.GetPos()); - break; - - default: - return FALSE; - } - - *pResult = 0; - return TRUE; - } - - void OnAmigaResamplerChanged() { - m_ComboBoxAmigaFilter.EnableWindow( IsDlgButtonChecked( IDC_CHECK_AMIGA_RESAMPLER ) != BST_UNCHECKED ? TRUE : FALSE ); - } - -}; - -BEGIN_MESSAGE_MAP(CSettingsDialog, CDialog) - ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CSettingsDialog::OnToolTipText) - ON_COMMAND( IDC_CHECK_AMIGA_RESAMPLER, &CSettingsDialog::OnAmigaResamplerChanged ) -END_MESSAGE_MAP() - - - -class CInfoDialog : public CDialog { - -protected: - - CString m_Title; - CString m_FileInfo; - CEdit m_EditFileInfo; - -public: - - CInfoDialog( CString title, CString info, CWnd * parent = NULL ) - : CDialog( IDD_FILEINFO, parent ) - , m_Title( title ) - , m_FileInfo( info ) - { - return; - } - -protected: - - void DoDataExchange( CDataExchange * pDX ) override - { - CDialog::DoDataExchange( pDX ); - DDX_Control( pDX, IDC_FILEINFO, m_EditFileInfo ); - } - - afx_msg BOOL OnInitDialog() override { - - if ( !CDialog::OnInitDialog() ) { - return false; - } - - SetWindowText( m_Title ); - - m_EditFileInfo.SetWindowText( m_FileInfo ); - - return TRUE; - - } - -}; - - -#endif // MPT_WITH_MFC - - -#if defined(MPT_WITH_MFC) - -void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::wstring title ) { - AFX_MANAGE_STATE( AfxGetStaticModuleState() ); - CSettingsDialog dlg( s, title.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr ); - dlg.DoModal(); -} - - -void gui_show_file_info( HWND parent, std::wstring title, std::wstring info ) { - AFX_MANAGE_STATE( AfxGetStaticModuleState() ); - CInfoDialog dlg( title.c_str(), info.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr); - dlg.DoModal(); -} - - -#else // !MPT_WITH_MFC - - -static std::basic_string GetTempDirectory() { - DWORD size = GetTempPath(0, nullptr); - if (size) { - std::vector tempPath(size + 1); - if (GetTempPath(size + 1, tempPath.data())) { - return tempPath.data(); - } - } - return {}; -} - -static std::basic_string GetTempFilename( std::basic_string prefix ) { - std::vector buf(MAX_PATH); - if (GetTempFileName(GetTempDirectory().c_str(), prefix.c_str(), 0, buf.data()) == 0) { - return {}; - } - return buf.data(); -} - -template -static std::basic_string as_string( T x ) { - std::basic_ostringstream s; - s.imbue(std::locale::classic()); - s << x; - return s.str(); -} - - -void gui_edit_settings( libopenmpt_settings * s, HWND /* parent */ , std::basic_string title ) { - std::basic_string filename = GetTempFilename( title ); - WritePrivateProfileString( title.c_str(), TEXT("Samplerate_Hz"), as_string( s->samplerate ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("Channels"), as_string( s->channels ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("MasterGain_milliBel"), as_string( s->mastergain_millibel ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("StereoSeparation_Percent"), as_string( s->stereoseparation ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("RepeatCount"), as_string( s->repeatcount ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("InterpolationFilterLength"), as_string( s->interpolationfilterlength ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("UseAmigaResampler"), as_string( s->use_amiga_resampler ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("AmigaFilterType"), as_string( s->amiga_filter_type ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("VolumeRampingStrength"), as_string( s->ramping ).c_str(), filename.c_str() ); - WritePrivateProfileString( title.c_str(), TEXT("VisAllowScroll"), as_string( s->vis_allow_scroll ).c_str(), filename.c_str() ); - STARTUPINFO startupInfo = {}; - startupInfo.cb = sizeof(startupInfo); - PROCESS_INFORMATION processInformation = {}; - std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; - std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; - if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { - MessageBox(NULL, as_string(GetLastError()).c_str(), TEXT("fail"), 0); - return; - } - CloseHandle( processInformation.hThread ); - WaitForSingleObject( processInformation.hProcess, INFINITE ); - CloseHandle( processInformation.hProcess ); - s->samplerate = GetPrivateProfileInt( title.c_str(), TEXT("Samplerate_Hz"), libopenmpt_settings{}.samplerate, filename.c_str() ); - s->channels = GetPrivateProfileInt( title.c_str(), TEXT("Channels"), libopenmpt_settings{}.channels, filename.c_str() ); - s->mastergain_millibel = GetPrivateProfileInt( title.c_str(), TEXT("MasterGain_milliBel"), libopenmpt_settings{}.mastergain_millibel, filename.c_str() ); - s->stereoseparation = GetPrivateProfileInt( title.c_str(), TEXT("StereoSeparation_Percent"), libopenmpt_settings{}.stereoseparation, filename.c_str() ); - s->repeatcount = GetPrivateProfileInt( title.c_str(), TEXT("RepeatCount"), libopenmpt_settings{}.repeatcount, filename.c_str() ); - s->interpolationfilterlength = GetPrivateProfileInt( title.c_str(), TEXT("InterpolationFilterLength"), libopenmpt_settings{}.interpolationfilterlength, filename.c_str() ); - s->use_amiga_resampler = GetPrivateProfileInt( title.c_str(), TEXT("UseAmigaResampler"), libopenmpt_settings{}.use_amiga_resampler, filename.c_str() ); - s->amiga_filter_type = GetPrivateProfileInt( title.c_str(), TEXT("AmigaFilterType"), libopenmpt_settings{}.amiga_filter_type, filename.c_str() ); - s->ramping = GetPrivateProfileInt( title.c_str(), TEXT("VolumeRampingStrength"), libopenmpt_settings{}.ramping, filename.c_str() ); - s->vis_allow_scroll = GetPrivateProfileInt( title.c_str(), TEXT("VisAllowScroll"), libopenmpt_settings{}.vis_allow_scroll, filename.c_str() ); - DeleteFile( filename.c_str() ); -} - - -void gui_show_file_info( HWND /* parent */ , std::basic_string title, std::basic_string info ) { - std::basic_string filename = GetTempFilename( title ); - { - std::basic_ofstream f( filename.c_str(), std::ios::out ); - f << info; - } - STARTUPINFO startupInfo = {}; - startupInfo.cb = sizeof(startupInfo); - PROCESS_INFORMATION processInformation = {}; - std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; - std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; - if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { - return; - } - CloseHandle( processInformation.hThread ); - WaitForSingleObject( processInformation.hProcess, INFINITE ); - CloseHandle( processInformation.hProcess ); - DeleteFile( filename.c_str() ); -} - - -#endif // MPT_WITH_MFC - - -} // namespace plugin -} // namespace libopenmpt - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.hpp index 1cc387865..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.hpp @@ -1,36 +0,0 @@ -/* - * libopenmpt_plugin_gui.hpp - * ------------------------- - * Purpose: libopenmpt plugin GUI - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#ifndef LIBOPENMPT_PLUGIN_GUI_HPP -#define LIBOPENMPT_PLUGIN_GUI_HPP - -#include "libopenmpt_plugin_settings.hpp" - -#include - -#include - -namespace libopenmpt { -namespace plugin { - -#if defined(MPT_WITH_MFC) - -void DllMainAttach(); -void DllMainDetach(); - -#endif // MPT_WITH_MFC - -void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::basic_string title ); - -void gui_show_file_info( HWND parent, std::basic_string title, std::basic_string info ); - -} // namespace plugin -} // namespace libopenmpt - -#endif // LIBOPENMPT_PLUGIN_GUI_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.rc b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.rc index a618fd3be..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.rc +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_gui.rc @@ -1,147 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// German (Germany) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) -LANGUAGE LANG_GERMAN, SUBLANG_GERMAN -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_SETTINGS DIALOGEX 0, 0, 201, 200 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "&OK",IDOK,78,180,54,14 - PUSHBUTTON "&Cancel",IDCANCEL,138,180,54,14 - LTEXT "&Samplerate",IDC_STATIC,6,6,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_SAMPLERATE,72,6,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "C&hannels",IDC_STATIC,6,24,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_CHANNELS,72,24,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Gain",IDC_STATIC,6,42,60,12,SS_CENTERIMAGE - CONTROL "",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,42,120,15 - LTEXT "&Interpolation",IDC_STATIC,6,60,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_INTERPOLATION,72,60,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "Use &Amiga resampler for Amiga modules",IDC_CHECK_AMIGA_RESAMPLER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,186,12 - LTEXT "Amiga &Filter Type:",IDC_STATIC,6,96,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_AMIGA_FILTER,72,96,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&Repeat",IDC_STATIC,6,114,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_REPEAT,72,114,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "S&tereo Separation",IDC_STATIC,6,132,60,12,SS_CENTERIMAGE - CONTROL "",IDC_SLIDER_STEREOSEPARATION,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,132,126,15 - LTEXT "&Volume Ramping",IDC_STATIC,6,151,60,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_RAMPING,72,151,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,6,175,186,1 -END - -IDD_FILEINFO DIALOGEX 0, 0, 310, 174 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,258,156,48,12 - EDITTEXT IDC_FILEINFO,6,6,300,144,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_SETTINGS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 194 - TOPMARGIN, 7 - BOTTOMMARGIN, 193 - END - - IDD_FILEINFO, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 303 - TOPMARGIN, 7 - BOTTOMMARGIN, 167 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_SETTINGS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_FILEINFO AFX_DIALOG_LAYOUT -BEGIN - 0, - 100, 100, 0, 0, - 0, 0, 100, 100 -END - -#endif // German (Germany) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_settings.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_settings.hpp index d77ca022f..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_settings.hpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_plugin_settings.hpp @@ -1,130 +0,0 @@ -/* - * libopenmpt_plugin_settings.hpp - * ------------------------------ - * Purpose: libopenmpt plugin settings - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#ifndef LIBOPENMPT_PLUGIN_SETTINGS_HPP -#define LIBOPENMPT_PLUGIN_SETTINGS_HPP - -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include - -#include - - -namespace libopenmpt { -namespace plugin { - - -typedef void (*changed_func)(); - -struct libopenmpt_settings { - bool no_default_format = true; - int samplerate = 48000; - int channels = 2; - int mastergain_millibel = 0; - int stereoseparation = 100; - int use_amiga_resampler = 0; - int amiga_filter_type = 0; - int repeatcount = 0; - int interpolationfilterlength = 8; - int ramping = -1; - int vis_allow_scroll = 1; - changed_func changed = nullptr; -}; - - -class settings : public libopenmpt_settings { -private: - std::basic_string subkey; -protected: - virtual void read_setting( const std::string & /* key */ , const std::basic_string & key, int & val ) { - HKEY regkey = HKEY(); - if ( RegOpenKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, KEY_READ, ®key ) == ERROR_SUCCESS ) { - DWORD v = val; - DWORD type = REG_DWORD; - DWORD typesize = sizeof(v); - if ( RegQueryValueEx( regkey, key.c_str(), NULL, &type, (BYTE *)&v, &typesize ) == ERROR_SUCCESS ) - { - val = v; - } - RegCloseKey( regkey ); - regkey = HKEY(); - } - } - virtual void write_setting( const std::string & /* key */, const std::basic_string & key, int val ) { - HKEY regkey = HKEY(); - if ( RegCreateKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®key, NULL ) == ERROR_SUCCESS ) { - DWORD v = val; - DWORD type = REG_DWORD; - DWORD typesize = sizeof(v); - if ( RegSetValueEx( regkey, key.c_str(), 0, type, (const BYTE *)&v, typesize ) == ERROR_SUCCESS ) - { - // ok - } - RegCloseKey( regkey ); - regkey = HKEY(); - } - } -public: - settings( const std::basic_string & subkey, bool no_default_format_ ) - : subkey(subkey) - { - no_default_format = no_default_format_; - } - void load() - { - #ifdef UNICODE - #define read_setting(a,b,c) read_setting( b , L ## b , c) - #else - #define read_setting(a,b,c) read_setting( b , b , c) - #endif - read_setting( subkey, "Samplerate_Hz", samplerate ); - read_setting( subkey, "Channels", channels ); - read_setting( subkey, "MasterGain_milliBel", mastergain_millibel ); - read_setting( subkey, "StereoSeparation_Percent", stereoseparation ); - read_setting( subkey, "RepeatCount", repeatcount ); - read_setting( subkey, "InterpolationFilterLength", interpolationfilterlength ); - read_setting( subkey, "UseAmigaResampler", use_amiga_resampler ); - read_setting( subkey, "AmigaFilterType", amiga_filter_type ); - read_setting( subkey, "VolumeRampingStrength", ramping ); - read_setting( subkey, "VisAllowScroll", vis_allow_scroll ); - #undef read_setting - } - void save() - { - #ifdef UNICODE - #define write_setting(a,b,c) write_setting( b , L ## b , c) - #else - #define write_setting(a,b,c) write_setting( b , b , c) - #endif - write_setting( subkey, "Samplerate_Hz", samplerate ); - write_setting( subkey, "Channels", channels ); - write_setting( subkey, "MasterGain_milliBel", mastergain_millibel ); - write_setting( subkey, "StereoSeparation_Percent", stereoseparation ); - write_setting( subkey, "RepeatCount", repeatcount ); - write_setting( subkey, "InterpolationFilterLength", interpolationfilterlength ); - write_setting( subkey, "UseAmigaResampler", use_amiga_resampler ); - write_setting( subkey, "AmigaFilterType", amiga_filter_type ); - write_setting( subkey, "VolumeRampingStrength", ramping ); - write_setting( subkey, "VisAllowScroll", vis_allow_scroll ); - #undef write_setting - } - virtual ~settings() - { - return; - } -}; - - -} // namespace plugin -} // namespace libopenmpt - - -#endif // LIBOPENMPT_PLUGIN_SETTINGS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_buffer.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_buffer.h index 575049e4d..d6e03ff34 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_buffer.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_buffer.h @@ -12,17 +12,6 @@ #include "libopenmpt.h" -/* The use of this header requires: - -#include -#if defined( LIBOPENMPT_STREAM_CALLBACKS_BUFFER ) -#include -#else -#error "libopenmpt too old." -#endif - -*/ - #include #include #include @@ -43,7 +32,7 @@ typedef struct openmpt_stream_buffer { int overflow; } openmpt_stream_buffer; -static size_t openmpt_stream_buffer_read_func( void * stream, void * dst, size_t bytes ) { +static LIBOPENMPT_C_INLINE size_t openmpt_stream_buffer_read_func( void * stream, void * dst, size_t bytes ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; int64_t offset = 0; int64_t begpos = 0; @@ -87,7 +76,7 @@ static size_t openmpt_stream_buffer_read_func( void * stream, void * dst, size_t return bytes; } -static int openmpt_stream_buffer_seek_func( void * stream, int64_t offset, int whence ) { +static LIBOPENMPT_C_INLINE int openmpt_stream_buffer_seek_func( void * stream, int64_t offset, int whence ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; int result = -1; if ( !s ) { @@ -142,7 +131,7 @@ static int openmpt_stream_buffer_seek_func( void * stream, int64_t offset, int w return result; } -static int64_t openmpt_stream_buffer_tell_func( void * stream ) { +static LIBOPENMPT_C_INLINE int64_t openmpt_stream_buffer_tell_func( void * stream ) { openmpt_stream_buffer * s = (openmpt_stream_buffer*)stream; if ( !s ) { return -1; @@ -150,7 +139,7 @@ static int64_t openmpt_stream_buffer_tell_func( void * stream ) { return s->file_pos; } -static void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const void * file_data, int64_t file_size ) { +LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const void * file_data, int64_t file_size ) { memset( buffer, 0, sizeof( openmpt_stream_buffer ) ); buffer->file_data = file_data; buffer->file_size = file_size; @@ -169,6 +158,7 @@ static void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const vo /*! \brief Provide openmpt_stream_callbacks for in-memoy buffers * * Fills openmpt_stream_callbacks suitable for passing an in-memory buffer as a stream parameter to functions doing file input/output. + * A suitable openmpt_stream_buffer object may be initialized with openmpt_stream_buffer_init(). * * \remarks The stream argument must be passed as `(void*)(openmpt_stream_buffer*)stream_buffer`. * \sa \ref libopenmpt_c_fileio @@ -176,8 +166,10 @@ static void openmpt_stream_buffer_init( openmpt_stream_buffer * buffer, const vo * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 + * \sa openmpt_stream_buffer_init + * \deprecated Please use openmpt_stream_get_buffer_callbacks2(). */ -static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) { +LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_buffer_read_func; @@ -186,6 +178,137 @@ static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) { return retval; } +typedef struct openmpt_stream_buffer2 { + const void * file_data; + int64_t file_size; + int64_t file_pos; +} openmpt_stream_buffer2; + +static size_t openmpt_stream_buffer_read_func2( void * stream, void * dst, size_t bytes ) { + openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; + int64_t offset = 0; + int64_t begpos = 0; + int64_t endpos = 0; + if ( !s ) { + return 0; + } + offset = bytes; + begpos = s->file_pos; + endpos = s->file_pos; + endpos = (uint64_t)endpos + (uint64_t)offset; + if ( ( offset > 0 ) && !( (uint64_t)endpos > (uint64_t)begpos ) ) { + /* integer wrapped */ + return 0; + } + if ( bytes == 0 ) { + return 0; + } + if ( begpos >= s->file_size ) { + return 0; + } + if ( endpos > s->file_size ) { + /* clip to eof */ + bytes = bytes - (size_t)( endpos - s->file_size ); + endpos = endpos - ( endpos - s->file_size ); + } + memcpy( dst, (const char*)s->file_data + s->file_pos, bytes ); + s->file_pos = s->file_pos + bytes; + return bytes; +} + +static int openmpt_stream_buffer_seek_func2( void * stream, int64_t offset, int whence ) { + openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; + int result = -1; + if ( !s ) { + return -1; + } + switch ( whence ) { + case OPENMPT_STREAM_SEEK_SET: + if ( offset < 0 ) { + return -1; + } + if ( offset > s->file_size ) { + return -1; + } + s->file_pos = offset; + result = 0; + break; + case OPENMPT_STREAM_SEEK_CUR: + do { + int64_t oldpos = s->file_pos; + int64_t pos = s->file_pos; + pos = (uint64_t)pos + (uint64_t)offset; + if ( ( offset > 0 ) && !( (uint64_t)pos > (uint64_t)oldpos ) ) { + /* integer wrapped */ + return -1; + } + if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { + /* integer wrapped */ + return -1; + } + s->file_pos = pos; + } while(0); + result = 0; + break; + case OPENMPT_STREAM_SEEK_END: + if ( offset > 0 ) { + return -1; + } + do { + int64_t oldpos = s->file_pos; + int64_t pos = s->file_pos; + pos = s->file_size; + pos = (uint64_t)pos + (uint64_t)offset; + if ( ( offset < 0 ) && !( (uint64_t)pos < (uint64_t)oldpos ) ) { + /* integer wrapped */ + return -1; + } + s->file_pos = pos; + } while(0); + result = 0; + break; + } + return result; +} + +static int64_t openmpt_stream_buffer_tell_func2( void * stream ) { + openmpt_stream_buffer2 * s = (openmpt_stream_buffer2*)stream; + if ( !s ) { + return -1; + } + return s->file_pos; +} + +static void openmpt_stream_buffer_init2( openmpt_stream_buffer2 * buffer, const void * file_data, int64_t file_size ) { + memset( buffer, 0, sizeof( openmpt_stream_buffer2 ) ); + buffer->file_data = file_data; + buffer->file_size = file_size; + buffer->file_pos = 0; +} + +/*! \brief Provide openmpt_stream_callbacks for in-memoy buffers + * + * Fills openmpt_stream_callbacks suitable for passing an in-memory buffer as a stream parameter to functions doing file input/output. + * A suitable openmpt_stream_buffer2 object can be initialized with openmpt_stream_buffer_init2(). + * + * \remarks The stream argument must be passed as `(void*)(openmpt_stream_buffer2*)stream_buffer`. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + * \sa openmpt_stream_buffer_init2 + * \since 0.7.0 + */ +static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks2(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_buffer_read_func2; + retval.seek = openmpt_stream_buffer_seek_func2; + retval.tell = openmpt_stream_buffer_tell_func2; + return retval; +} + #ifdef __cplusplus } #endif @@ -195,4 +318,3 @@ static openmpt_stream_callbacks openmpt_stream_get_buffer_callbacks(void) { */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_BUFFER_H */ - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_fd.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_fd.h index 46b39f129..c0f80c3d9 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_fd.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_fd.h @@ -12,6 +12,9 @@ #include "libopenmpt.h" +#ifndef _MSC_VER +#include +#endif #ifdef _MSC_VER #include #endif @@ -63,7 +66,9 @@ static size_t openmpt_stream_fd_read_func( void * stream, void * dst, size_t byt retval += ret_read; } #else - retval = read( fd, dst, bytes ); + do { + retval = read( fd, dst, bytes ); + } while ( ( retval == -1 ) && ( errno == EINTR ) ); #endif if ( retval <= 0 ) { return 0; @@ -98,4 +103,3 @@ static openmpt_stream_callbacks openmpt_stream_get_fd_callbacks(void) { */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FD_H */ - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file.h index 643049153..a922d1539 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file.h @@ -12,13 +12,9 @@ #include "libopenmpt.h" -#include #include #include #include -#ifdef _MSC_VER -#include /* off_t */ -#endif /*! \addtogroup libopenmpt_c * @{ @@ -52,48 +48,38 @@ static int openmpt_stream_file_seek_func( void * stream, int64_t offset, int whe return -1; } switch ( whence ) { -#if defined(SEEK_SET) case OPENMPT_STREAM_SEEK_SET: fwhence = SEEK_SET; break; -#endif -#if defined(SEEK_CUR) case OPENMPT_STREAM_SEEK_CUR: fwhence = SEEK_CUR; break; -#endif -#if defined(SEEK_END) case OPENMPT_STREAM_SEEK_END: fwhence = SEEK_END; break; -#endif default: return -1; break; } - #if defined(_MSC_VER) - return _fseeki64( f, offset, fwhence ) ? -1 : 0; - #elif defined(_POSIX_SOURCE) && (_POSIX_SOURCE == 1) - return fseeko( f, offset, fwhence ) ? -1 : 0; - #else - return fseek( f, offset, fwhence ) ? -1 : 0; - #endif + if ( (long)offset != offset ) { + return -1; + } + return fseek( f, (long)offset, fwhence ) ? -1 : 0; } static int64_t openmpt_stream_file_tell_func( void * stream ) { FILE * f = 0; + long result = 0; int64_t retval = 0; f = (FILE*)stream; if ( !f ) { return -1; } - #if defined(_MSC_VER) - retval = _ftelli64( f ); - #elif defined(_POSIX_SOURCE) && (_POSIX_SOURCE == 1) - retval = ftello( f ); - #else - retval = ftell( f ); - #endif + result = ftell( f ); + if ( (int64_t)result != result ) { + return -1; + } + retval = (int64_t)result; if ( retval < 0 ) { return -1; } @@ -103,6 +89,9 @@ static int64_t openmpt_stream_file_tell_func( void * stream ) { /*! \brief Provide openmpt_stream_callbacks for standard C FILE objects * * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * Since 0.7.0, it does not try to use platform-specific file seeking any more, + * but sticks to standard C fseek/ftell only, which means on platforms where + * long is 32bit, there is no 64bit file access possible any more. * * \remarks The stream argument must be passed as `(void*)(FILE*)file`. * \sa \ref libopenmpt_c_fileio @@ -110,8 +99,37 @@ static int64_t openmpt_stream_file_tell_func( void * stream ) { * \sa openmpt_could_open_probability2 * \sa openmpt_probe_file_header_from_stream * \sa openmpt_module_create2 + * \sa openmpt_stream_get_file_callbacks2() + * \sa openmpt_stream_get_file_mingw_callbacks() + * \sa openmpt_stream_get_file_msvcrt_callbacks() + * \sa openmpt_stream_get_file_posix_callbacks() + * \sa openmpt_stream_get_file_posix_lfs64_callbacks() + * \deprecated Please use openmpt_stream_get_file_callbacks2(). */ -static openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void) { +LIBOPENMPT_DEPRECATED static LIBOPENMPT_C_INLINE openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_file_read_func; + retval.seek = openmpt_stream_file_seek_func; + retval.tell = openmpt_stream_file_tell_func; + return retval; +} + +/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects + * + * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * This function uses the standard C fseek and ftell, thus platform-specific file size limits apply accordingly. + * + * \remarks The stream argument must be passed as `(void*)(FILE*)file`. + * \remarks The provided callbacks are limited to handling files up to the size representable in the platform's long type. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + * \since 0.7.0 + */ +static openmpt_stream_callbacks openmpt_stream_get_file_callbacks2(void) { openmpt_stream_callbacks retval; memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); retval.read = openmpt_stream_file_read_func; @@ -129,4 +147,3 @@ static openmpt_stream_callbacks openmpt_stream_get_file_callbacks(void) { */ #endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_H */ - diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_mingw.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_mingw.h new file mode 100644 index 000000000..871af4dab --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_mingw.h @@ -0,0 +1,115 @@ +/* + * libopenmpt_stream_callbacks_file_mingw.h + * ---------------------------------------- + * Purpose: libopenmpt public c interface + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H + +#include "libopenmpt.h" + +#include +#include +#include + +/*! \addtogroup libopenmpt_c + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +static size_t openmpt_stream_file_mingw_read_func( void * stream, void * dst, size_t bytes ) { + FILE * f = 0; + size_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return 0; + } + retval = fread( dst, 1, bytes, f ); + if ( retval <= 0 ) { + return 0; + } + return retval; +} + +static int openmpt_stream_file_mingw_seek_func( void * stream, int64_t offset, int whence ) { + FILE * f = 0; + int fwhence = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + switch ( whence ) { + case OPENMPT_STREAM_SEEK_SET: + fwhence = SEEK_SET; + break; + case OPENMPT_STREAM_SEEK_CUR: + fwhence = SEEK_CUR; + break; + case OPENMPT_STREAM_SEEK_END: + fwhence = SEEK_END; + break; + default: + return -1; + break; + } + if ( (_off64_t)offset != offset ) { + return -1; + } + return fseeko64( f, (_off64_t)offset, fwhence ) ? -1 : 0; +} + +static int64_t openmpt_stream_file_mingw_tell_func( void * stream ) { + FILE * f = 0; + _off64_t result = 0; + int64_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + result = ftello64( f ); + if ( (int64_t)result != result ) { + return -1; + } + retval = (int64_t)result; + if ( retval < 0 ) { + return -1; + } + return retval; +} + +/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects + * + * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * + * \remarks The stream argument must be passed as `(void*)(FILE*)file`. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + */ +static openmpt_stream_callbacks openmpt_stream_get_file_mingw_callbacks(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_file_mingw_read_func; + retval.seek = openmpt_stream_file_mingw_seek_func; + retval.tell = openmpt_stream_file_mingw_tell_func; + return retval; +} + +#ifdef __cplusplus +} +#endif + +/*! + * @} + */ + +#endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_MINGW_H */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h new file mode 100644 index 000000000..d84dfc69b --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_msvcrt.h @@ -0,0 +1,115 @@ +/* + * libopenmpt_stream_callbacks_file_msvcrt.h + * ----------------------------------------- + * Purpose: libopenmpt public c interface + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H + +#include "libopenmpt.h" + +#include +#include +#include + +/*! \addtogroup libopenmpt_c + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +static size_t openmpt_stream_file_msvcrt_read_func( void * stream, void * dst, size_t bytes ) { + FILE * f = 0; + size_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return 0; + } + retval = fread( dst, 1, bytes, f ); + if ( retval <= 0 ) { + return 0; + } + return retval; +} + +static int openmpt_stream_file_msvcrt_seek_func( void * stream, int64_t offset, int whence ) { + FILE * f = 0; + int fwhence = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + switch ( whence ) { + case OPENMPT_STREAM_SEEK_SET: + fwhence = SEEK_SET; + break; + case OPENMPT_STREAM_SEEK_CUR: + fwhence = SEEK_CUR; + break; + case OPENMPT_STREAM_SEEK_END: + fwhence = SEEK_END; + break; + default: + return -1; + break; + } + if ( (__int64)offset != offset ) { + return -1; + } + return _fseeki64( f, (__int64)offset, fwhence ) ? -1 : 0; +} + +static int64_t openmpt_stream_file_msvcrt_tell_func( void * stream ) { + FILE * f = 0; + __int64 result = 0; + int64_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + result = _ftelli64( f ); + if ( (int64_t)result != result ) { + return -1; + } + retval = (int64_t)result; + if ( retval < 0 ) { + return -1; + } + return retval; +} + +/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects + * + * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * + * \remarks The stream argument must be passed as `(void*)(FILE*)file`. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + */ +static openmpt_stream_callbacks openmpt_stream_get_file_msvcrt_callbacks(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_file_msvcrt_read_func; + retval.seek = openmpt_stream_file_msvcrt_seek_func; + retval.tell = openmpt_stream_file_msvcrt_tell_func; + return retval; +} + +#ifdef __cplusplus +} +#endif + +/*! + * @} + */ + +#endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_MSVCRT_H */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix.h new file mode 100644 index 000000000..a3d94ef61 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix.h @@ -0,0 +1,115 @@ +/* + * libopenmpt_stream_callbacks_file_posix.h + * ---------------------------------------- + * Purpose: libopenmpt public c interface + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H + +#include "libopenmpt.h" + +#include +#include +#include + +/*! \addtogroup libopenmpt_c + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +static size_t openmpt_stream_file_posix_read_func( void * stream, void * dst, size_t bytes ) { + FILE * f = 0; + size_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return 0; + } + retval = fread( dst, 1, bytes, f ); + if ( retval <= 0 ) { + return 0; + } + return retval; +} + +static int openmpt_stream_file_posix_seek_func( void * stream, int64_t offset, int whence ) { + FILE * f = 0; + int fwhence = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + switch ( whence ) { + case OPENMPT_STREAM_SEEK_SET: + fwhence = SEEK_SET; + break; + case OPENMPT_STREAM_SEEK_CUR: + fwhence = SEEK_CUR; + break; + case OPENMPT_STREAM_SEEK_END: + fwhence = SEEK_END; + break; + default: + return -1; + break; + } + if ( (off_t)offset != offset ) { + return -1; + } + return fseeko( f, (off_t)offset, fwhence ) ? -1 : 0; +} + +static int64_t openmpt_stream_file_posix_tell_func( void * stream ) { + FILE * f = 0; + off_t result = 0; + int64_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + result = ftello( f ); + if ( (int64_t)result != result ) { + return -1; + } + retval = (int64_t)result; + if ( retval < 0 ) { + return -1; + } + return retval; +} + +/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects + * + * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * + * \remarks The stream argument must be passed as `(void*)(FILE*)file`. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + */ +static openmpt_stream_callbacks openmpt_stream_get_file_posix_callbacks(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_file_posix_read_func; + retval.seek = openmpt_stream_file_posix_seek_func; + retval.tell = openmpt_stream_file_posix_tell_func; + return retval; +} + +#ifdef __cplusplus +} +#endif + +/*! + * @} + */ + +#endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_H */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h new file mode 100644 index 000000000..a5df246ee --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_stream_callbacks_file_posix_lfs64.h @@ -0,0 +1,115 @@ +/* + * libopenmpt_stream_callbacks_file_posix_lfs64.h + * ---------------------------------------------- + * Purpose: libopenmpt public c interface + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H +#define LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H + +#include "libopenmpt.h" + +#include +#include +#include + +/*! \addtogroup libopenmpt_c + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +static size_t openmpt_stream_file_posix_lfs64_read_func( void * stream, void * dst, size_t bytes ) { + FILE * f = 0; + size_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return 0; + } + retval = fread( dst, 1, bytes, f ); + if ( retval <= 0 ) { + return 0; + } + return retval; +} + +static int openmpt_stream_file_posix_lfs64_seek_func( void * stream, int64_t offset, int whence ) { + FILE * f = 0; + int fwhence = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + switch ( whence ) { + case OPENMPT_STREAM_SEEK_SET: + fwhence = SEEK_SET; + break; + case OPENMPT_STREAM_SEEK_CUR: + fwhence = SEEK_CUR; + break; + case OPENMPT_STREAM_SEEK_END: + fwhence = SEEK_END; + break; + default: + return -1; + break; + } + if ( (off64_t)offset != offset ) { + return -1; + } + return fseeko64( f, (off64_t)offset, fwhence ) ? -1 : 0; +} + +static int64_t openmpt_stream_file_posix_lfs64_tell_func( void * stream ) { + FILE * f = 0; + off64_t result = 0; + int64_t retval = 0; + f = (FILE*)stream; + if ( !f ) { + return -1; + } + result = ftello64( f ); + if ( (int64_t)result != result ) { + return -1; + } + retval = (int64_t)result; + if ( retval < 0 ) { + return -1; + } + return retval; +} + +/*! \brief Provide openmpt_stream_callbacks for standard C FILE objects + * + * Fills openmpt_stream_callbacks suitable for passing a standard C FILE object as a stream parameter to functions doing file input/output. + * + * \remarks The stream argument must be passed as `(void*)(FILE*)file`. + * \sa \ref libopenmpt_c_fileio + * \sa openmpt_stream_callbacks + * \sa openmpt_could_open_probability2 + * \sa openmpt_probe_file_header_from_stream + * \sa openmpt_module_create2 + */ +static openmpt_stream_callbacks openmpt_stream_get_file_posix_lfs64_callbacks(void) { + openmpt_stream_callbacks retval; + memset( &retval, 0, sizeof( openmpt_stream_callbacks ) ); + retval.read = openmpt_stream_file_posix_lfs64_read_func; + retval.seek = openmpt_stream_file_posix_lfs64_seek_func; + retval.tell = openmpt_stream_file_posix_lfs64_tell_func; + return retval; +} + +#ifdef __cplusplus +} +#endif + +/*! + * @} + */ + +#endif /* LIBOPENMPT_STREAM_CALLBACKS_FILE_POSIX_LFS64_H */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_test.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_test.cpp index 90822c999..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_test.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_test.cpp @@ -1,69 +0,0 @@ -/* - * libopenmpt_test.cpp - * ------------------- - * Purpose: libopenmpt test suite driver - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#include "openmpt/all/BuildSettings.hpp" - -#include "libopenmpt_internal.h" - -#include "test/test.h" - -#include -#include - -#include -#include - -using namespace OpenMPT; - -#if defined( LIBOPENMPT_BUILD_TEST ) - -#if (defined(_WIN32) || defined(WIN32)) && (defined(_UNICODE) || defined(UNICODE)) -#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) -// mingw-w64 g++ does only default to special C linkage for "main", but not for "wmain" (see ). -extern "C" int wmain( int /*argc*/ , wchar_t * /*argv*/ [] ); -extern "C" -#endif -int wmain( int /*argc*/ , wchar_t * /*argv*/ [] ) { -#else -int main( int /*argc*/ , char * /*argv*/ [] ) { -#endif - try { - - // run test with "C" / classic() locale - Test::DoTests(); - - // try setting the C locale to the user locale - setlocale( LC_ALL, "" ); - - // run all tests again with a set C locale - Test::DoTests(); - - // try to set the C and C++ locales to the user locale - try { - std::locale old = std::locale::global( std::locale( "" ) ); - (void)old; - } catch ( ... ) { - // Setting c++ global locale does not work. - // This is no problem for libopenmpt, just continue. - } - - // and now, run all tests once again - Test::DoTests(); - - } catch ( const std::exception & e ) { - std::cerr << "TEST ERROR: exception: " << ( e.what() ? e.what() : "" ) << std::endl; - return -1; - } catch ( ... ) { - std::cerr << "TEST ERROR: unknown exception" << std::endl; - return -1; - } - return 0; -} - -#endif // LIBOPENMPT_BUILD_TEST diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h index 726bb311c..162257a41 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.h @@ -19,9 +19,9 @@ /*! \brief libopenmpt major version number */ #define OPENMPT_API_VERSION_MAJOR 0 /*! \brief libopenmpt minor version number */ -#define OPENMPT_API_VERSION_MINOR 6 +#define OPENMPT_API_VERSION_MINOR 7 /*! \brief libopenmpt patch version number */ -#define OPENMPT_API_VERSION_PATCH 8 +#define OPENMPT_API_VERSION_PATCH 0 /*! \brief libopenmpt pre-release tag */ #define OPENMPT_API_VERSION_PREREL "" /*! \brief libopenmpt pre-release flag */ diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk index 870f86c09..20880be06 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/libopenmpt_version.mk @@ -1,8 +1,8 @@ LIBOPENMPT_VERSION_MAJOR=0 -LIBOPENMPT_VERSION_MINOR=6 -LIBOPENMPT_VERSION_PATCH=8 +LIBOPENMPT_VERSION_MINOR=7 +LIBOPENMPT_VERSION_PATCH=0 LIBOPENMPT_VERSION_PREREL= -LIBOPENMPT_LTVER_CURRENT=3 -LIBOPENMPT_LTVER_REVISION=8 -LIBOPENMPT_LTVER_AGE=3 +LIBOPENMPT_LTVER_CURRENT=4 +LIBOPENMPT_LTVER_REVISION=0 +LIBOPENMPT_LTVER_AGE=4 diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.cpp new file mode 100644 index 000000000..f8d3cae1a --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.cpp @@ -0,0 +1,473 @@ +/* + * libopenmpt_plugin_gui.cpp + * ------------------------- + * Purpose: libopenmpt plugin GUI + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + +#if !defined(MPT_WITH_MFC) +#include +#include +#include +#include +#include +#endif + +#if !defined(MPT_WITH_MFC) +#include +#endif + +#if defined(MPT_WITH_MFC) +#include +#include +#endif // MPT_WITH_MFC + +#if defined(MPT_WITH_MFC) +#include "resource.h" +#endif // MPT_WITH_MFC + +#include "libopenmpt_plugin_gui.hpp" + + +namespace libopenmpt { +namespace plugin { + + +#if defined(MPT_WITH_MFC) + + +class CSettingsApp : public CWinApp { + +public: + + BOOL InitInstance() override { + if ( !CWinApp::InitInstance() ) + { + return FALSE; + } + DllMainAttach(); + return TRUE; + } + + int ExitInstance() override { + DllMainDetach(); + return CWinApp::ExitInstance(); + } + +}; + + +CSettingsApp theApp; + + +class CSettingsDialog : public CDialog { + +protected: + + DECLARE_MESSAGE_MAP() + + libopenmpt_settings * s; + + CString m_Title; + + CComboBox m_ComboBoxSamplerate; + CComboBox m_ComboBoxChannels; + CSliderCtrl m_SliderCtrlGain; + CComboBox m_ComboBoxInterpolation; + CButton m_CheckBoxAmigaResampler; + CComboBox m_ComboBoxAmigaFilter; + CComboBox m_ComboBoxRepeat; + CSliderCtrl m_SliderCtrlStereoSeparation; + CComboBox m_ComboBoxRamping; + +public: + + CSettingsDialog( libopenmpt_settings * s_, CString title, CWnd * parent = nullptr ) + : CDialog( IDD_SETTINGS, parent ) + , s( s_ ) + , m_Title( title ) + { + return; + } + +protected: + + void DoDataExchange( CDataExchange * pDX ) override + { + CDialog::DoDataExchange( pDX ); + DDX_Control( pDX, IDC_COMBO_SAMPLERATE, m_ComboBoxSamplerate ); + DDX_Control( pDX, IDC_COMBO_CHANNELS, m_ComboBoxChannels ); + DDX_Control( pDX, IDC_SLIDER_GAIN, m_SliderCtrlGain ); + DDX_Control( pDX, IDC_COMBO_INTERPOLATION, m_ComboBoxInterpolation ); + DDX_Control( pDX, IDC_CHECK_AMIGA_RESAMPLER, m_CheckBoxAmigaResampler ); + DDX_Control( pDX, IDC_COMBO_AMIGA_FILTER, m_ComboBoxAmigaFilter ); + DDX_Control( pDX, IDC_COMBO_REPEAT, m_ComboBoxRepeat ); + DDX_Control( pDX, IDC_SLIDER_STEREOSEPARATION, m_SliderCtrlStereoSeparation ); + DDX_Control( pDX, IDC_COMBO_RAMPING, m_ComboBoxRamping ); + } + + afx_msg BOOL OnInitDialog() override { + + CDialog::OnInitDialog(); + + SetWindowText( m_Title ); + EnableToolTips(); + + bool selected = false; + + selected = false; + if ( !s->no_default_format ) { + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"Default" ), 0 ); + } + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"6000" ), 6000 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"8000" ), 8000 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"11025" ), 11025 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"16000" ), 16000 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"22050" ), 22050 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"32000" ), 32000 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"44100" ), 44100 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"48000" ), 48000 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"88200" ), 88200 ); + m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"96000" ), 96000 ); + if ( !s->no_default_format && s->samplerate == 0 ) { + m_ComboBoxSamplerate.SelectString( 0, L"Default" ); + } + for ( int index = 0; index < m_ComboBoxSamplerate.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxSamplerate.GetItemData( index ) ) == s->samplerate ) { + m_ComboBoxSamplerate.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxSamplerate.SelectString( 0, L"48000" ); + } + + selected = false; + if ( !s->no_default_format ) { + m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Default" ), 0 ); + } + m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Mono" ), 1 ); + m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Stereo" ), 2 ); + m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Quad" ), 4 ); + if ( !s->no_default_format && s->channels == 0 ) { + m_ComboBoxChannels.SelectString( 0, L"Default" ); + } + for ( int index = 0; index < m_ComboBoxChannels.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxChannels.GetItemData( index ) ) == s->channels ) { + m_ComboBoxChannels.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxChannels.SelectString( 0, L"Stereo" ); + } + + m_SliderCtrlGain.SetRange( -1200, 1200 ); + m_SliderCtrlGain.SetTicFreq( 100 ); + m_SliderCtrlGain.SetPageSize( 300 ); + m_SliderCtrlGain.SetLineSize( 100 ); + m_SliderCtrlGain.SetPos( s->mastergain_millibel ); + + selected = false; + m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"Off / 1 Tap (Nearest)" ), 1 ); + m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"2 Tap (Linear)" ), 2 ); + m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"4 Tap (Cubic)" ), 4 ); + m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"8 Tap (Polyphase FIR)" ), 8 ); + for ( int index = 0; index < m_ComboBoxInterpolation.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxInterpolation.GetItemData( index ) ) == s->interpolationfilterlength ) { + m_ComboBoxInterpolation.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxInterpolation.SelectString( 0, L"8 Tap (Polyphase FIR)" ); + } + + m_CheckBoxAmigaResampler.SetCheck( s->use_amiga_resampler ? BST_CHECKED : BST_UNCHECKED ); + selected = false; + m_ComboBoxAmigaFilter.EnableWindow( s->use_amiga_resampler ? TRUE : FALSE ); + m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Default" ), 0 ); + m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A500 Filter" ), 0xA500 ); + m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A1200 Filter" ), 0xA1200 ); + m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Unfiltered" ), 1 ); + for ( int index = 0; index < m_ComboBoxAmigaFilter.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxAmigaFilter.GetItemData( index ) ) == s->amiga_filter_type ) { + m_ComboBoxAmigaFilter.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxAmigaFilter.SelectString( 0, L"Default" ); + } + + selected = false; + m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Forever" ), static_cast( -1 ) ); + m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Never" ), 0 ); + m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Once" ), 1 ); + for ( int index = 0; index < m_ComboBoxRepeat.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxRepeat.GetItemData( index ) ) == s->repeatcount ) { + m_ComboBoxRepeat.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxRepeat.SelectString( 0, L"Never" ); + } + + m_SliderCtrlStereoSeparation.SetRange( 0, 200 ); + m_SliderCtrlStereoSeparation.SetTicFreq( 100 ); + m_SliderCtrlStereoSeparation.SetPageSize( 25 ); + m_SliderCtrlStereoSeparation.SetLineSize( 5 ); + m_SliderCtrlStereoSeparation.SetPos( s->stereoseparation ); + + selected = false; + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Default" ), static_cast( -1 ) ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Off" ), 0 ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"1 ms" ), 1 ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"2 ms" ), 2 ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"3 ms" ), 3 ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"5 ms" ), 5 ); + m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"10 ms" ), 10 ); + for ( int index = 0; index < m_ComboBoxRamping.GetCount(); ++index ) { + if ( static_cast( m_ComboBoxRamping.GetItemData( index ) ) == s->ramping ) { + m_ComboBoxRamping.SetCurSel( index ); + selected = true; + } + } + if ( !selected ) { + m_ComboBoxRamping.SelectString( 0, L"Default" ); + } + + return TRUE; + + } + + void OnOK() override { + + s->samplerate = m_ComboBoxSamplerate.GetItemData( m_ComboBoxSamplerate.GetCurSel() ); + + s->channels = m_ComboBoxChannels.GetItemData( m_ComboBoxChannels.GetCurSel() ); + + s->mastergain_millibel = m_SliderCtrlGain.GetPos(); + + s->interpolationfilterlength = m_ComboBoxInterpolation.GetItemData( m_ComboBoxInterpolation.GetCurSel() ); + + s->use_amiga_resampler = ( m_CheckBoxAmigaResampler.GetCheck() != BST_UNCHECKED ) ? 1 : 0; + s->amiga_filter_type = m_ComboBoxAmigaFilter.GetItemData( m_ComboBoxAmigaFilter.GetCurSel() ); + + s->repeatcount = m_ComboBoxRepeat.GetItemData( m_ComboBoxRepeat.GetCurSel() ); + + s->stereoseparation = m_SliderCtrlStereoSeparation.GetPos(); + + s->ramping = m_ComboBoxRamping.GetItemData( m_ComboBoxRamping.GetCurSel() ); + + s->changed(); + + CDialog::OnOK(); + + } + + BOOL OnToolTipText( UINT, NMHDR * pNMHDR, LRESULT * pResult ) { + TOOLTIPTEXT * pTTT = reinterpret_cast( pNMHDR ); + + UINT_PTR nID = pNMHDR->idFrom; + if( pTTT->uFlags & TTF_IDISHWND ) + { + // idFrom is actually the HWND of the tool + nID = (UINT_PTR)::GetDlgCtrlID((HWND)nID); + } + + switch ( nID ) { + case IDC_SLIDER_GAIN: + swprintf( pTTT->szText, _countof(pTTT->szText), L"%.02f dB", m_SliderCtrlGain.GetPos() * 0.01f ); + break; + + case IDC_SLIDER_STEREOSEPARATION: + swprintf( pTTT->szText, _countof(pTTT->szText), L"%d %%", m_SliderCtrlStereoSeparation.GetPos()); + break; + + default: + return FALSE; + } + + *pResult = 0; + return TRUE; + } + + void OnAmigaResamplerChanged() { + m_ComboBoxAmigaFilter.EnableWindow( IsDlgButtonChecked( IDC_CHECK_AMIGA_RESAMPLER ) != BST_UNCHECKED ? TRUE : FALSE ); + } + +}; + +BEGIN_MESSAGE_MAP(CSettingsDialog, CDialog) + ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CSettingsDialog::OnToolTipText) + ON_COMMAND( IDC_CHECK_AMIGA_RESAMPLER, &CSettingsDialog::OnAmigaResamplerChanged ) +END_MESSAGE_MAP() + + + +class CInfoDialog : public CDialog { + +protected: + + CString m_Title; + CString m_FileInfo; + CEdit m_EditFileInfo; + +public: + + CInfoDialog( CString title, CString info, CWnd * parent = NULL ) + : CDialog( IDD_FILEINFO, parent ) + , m_Title( title ) + , m_FileInfo( info ) + { + return; + } + +protected: + + void DoDataExchange( CDataExchange * pDX ) override + { + CDialog::DoDataExchange( pDX ); + DDX_Control( pDX, IDC_FILEINFO, m_EditFileInfo ); + } + + afx_msg BOOL OnInitDialog() override { + + if ( !CDialog::OnInitDialog() ) { + return false; + } + + SetWindowText( m_Title ); + + m_EditFileInfo.SetWindowText( m_FileInfo ); + + return TRUE; + + } + +}; + + +#endif // MPT_WITH_MFC + + +#if defined(MPT_WITH_MFC) + +void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::wstring title ) { + AFX_MANAGE_STATE( AfxGetStaticModuleState() ); + CSettingsDialog dlg( s, title.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr ); + dlg.DoModal(); +} + + +void gui_show_file_info( HWND parent, std::wstring title, std::wstring info ) { + AFX_MANAGE_STATE( AfxGetStaticModuleState() ); + CInfoDialog dlg( title.c_str(), info.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr); + dlg.DoModal(); +} + + +#else // !MPT_WITH_MFC + + +static std::basic_string GetTempDirectory() { + DWORD size = GetTempPath(0, nullptr); + if (size) { + std::vector tempPath(size + 1); + if (GetTempPath(size + 1, tempPath.data())) { + return tempPath.data(); + } + } + return {}; +} + +static std::basic_string GetTempFilename( std::basic_string prefix ) { + std::vector buf(MAX_PATH); + if (GetTempFileName(GetTempDirectory().c_str(), prefix.c_str(), 0, buf.data()) == 0) { + return {}; + } + return buf.data(); +} + +template +static std::basic_string as_string( T x ) { + std::basic_ostringstream s; + s.imbue(std::locale::classic()); + s << x; + return s.str(); +} + + +void gui_edit_settings( libopenmpt_settings * s, HWND /* parent */ , std::basic_string title ) { + std::basic_string filename = GetTempFilename( title ); + WritePrivateProfileString( title.c_str(), TEXT("Samplerate_Hz"), as_string( s->samplerate ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("Channels"), as_string( s->channels ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("MasterGain_milliBel"), as_string( s->mastergain_millibel ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("StereoSeparation_Percent"), as_string( s->stereoseparation ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("RepeatCount"), as_string( s->repeatcount ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("InterpolationFilterLength"), as_string( s->interpolationfilterlength ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("UseAmigaResampler"), as_string( s->use_amiga_resampler ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("AmigaFilterType"), as_string( s->amiga_filter_type ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("VolumeRampingStrength"), as_string( s->ramping ).c_str(), filename.c_str() ); + WritePrivateProfileString( title.c_str(), TEXT("VisAllowScroll"), as_string( s->vis_allow_scroll ).c_str(), filename.c_str() ); + STARTUPINFO startupInfo = {}; + startupInfo.cb = sizeof(startupInfo); + PROCESS_INFORMATION processInformation = {}; + std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; + std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; + if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { + MessageBox(NULL, as_string(GetLastError()).c_str(), TEXT("fail"), 0); + return; + } + CloseHandle( processInformation.hThread ); + WaitForSingleObject( processInformation.hProcess, INFINITE ); + CloseHandle( processInformation.hProcess ); + s->samplerate = GetPrivateProfileInt( title.c_str(), TEXT("Samplerate_Hz"), libopenmpt_settings{}.samplerate, filename.c_str() ); + s->channels = GetPrivateProfileInt( title.c_str(), TEXT("Channels"), libopenmpt_settings{}.channels, filename.c_str() ); + s->mastergain_millibel = GetPrivateProfileInt( title.c_str(), TEXT("MasterGain_milliBel"), libopenmpt_settings{}.mastergain_millibel, filename.c_str() ); + s->stereoseparation = GetPrivateProfileInt( title.c_str(), TEXT("StereoSeparation_Percent"), libopenmpt_settings{}.stereoseparation, filename.c_str() ); + s->repeatcount = GetPrivateProfileInt( title.c_str(), TEXT("RepeatCount"), libopenmpt_settings{}.repeatcount, filename.c_str() ); + s->interpolationfilterlength = GetPrivateProfileInt( title.c_str(), TEXT("InterpolationFilterLength"), libopenmpt_settings{}.interpolationfilterlength, filename.c_str() ); + s->use_amiga_resampler = GetPrivateProfileInt( title.c_str(), TEXT("UseAmigaResampler"), libopenmpt_settings{}.use_amiga_resampler, filename.c_str() ); + s->amiga_filter_type = GetPrivateProfileInt( title.c_str(), TEXT("AmigaFilterType"), libopenmpt_settings{}.amiga_filter_type, filename.c_str() ); + s->ramping = GetPrivateProfileInt( title.c_str(), TEXT("VolumeRampingStrength"), libopenmpt_settings{}.ramping, filename.c_str() ); + s->vis_allow_scroll = GetPrivateProfileInt( title.c_str(), TEXT("VisAllowScroll"), libopenmpt_settings{}.vis_allow_scroll, filename.c_str() ); + DeleteFile( filename.c_str() ); +} + + +void gui_show_file_info( HWND /* parent */ , std::basic_string title, std::basic_string info ) { + std::basic_string filename = GetTempFilename( title ); + { + std::basic_ofstream f( filename.c_str(), std::ios::out ); + f << info; + } + STARTUPINFO startupInfo = {}; + startupInfo.cb = sizeof(startupInfo); + PROCESS_INFORMATION processInformation = {}; + std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; + std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; + if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { + return; + } + CloseHandle( processInformation.hThread ); + WaitForSingleObject( processInformation.hProcess, INFINITE ); + CloseHandle( processInformation.hProcess ); + DeleteFile( filename.c_str() ); +} + + +#endif // MPT_WITH_MFC + + +} // namespace plugin +} // namespace libopenmpt + diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.hpp new file mode 100644 index 000000000..1cc387865 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.hpp @@ -0,0 +1,36 @@ +/* + * libopenmpt_plugin_gui.hpp + * ------------------------- + * Purpose: libopenmpt plugin GUI + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_PLUGIN_GUI_HPP +#define LIBOPENMPT_PLUGIN_GUI_HPP + +#include "libopenmpt_plugin_settings.hpp" + +#include + +#include + +namespace libopenmpt { +namespace plugin { + +#if defined(MPT_WITH_MFC) + +void DllMainAttach(); +void DllMainDetach(); + +#endif // MPT_WITH_MFC + +void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::basic_string title ); + +void gui_show_file_info( HWND parent, std::basic_string title, std::basic_string info ); + +} // namespace plugin +} // namespace libopenmpt + +#endif // LIBOPENMPT_PLUGIN_GUI_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.rc b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.rc new file mode 100644 index 000000000..a618fd3be --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_gui.rc @@ -0,0 +1,147 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SETTINGS DIALOGEX 0, 0, 201, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "&OK",IDOK,78,180,54,14 + PUSHBUTTON "&Cancel",IDCANCEL,138,180,54,14 + LTEXT "&Samplerate",IDC_STATIC,6,6,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_SAMPLERATE,72,6,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "C&hannels",IDC_STATIC,6,24,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_CHANNELS,72,24,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&Gain",IDC_STATIC,6,42,60,12,SS_CENTERIMAGE + CONTROL "",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,42,120,15 + LTEXT "&Interpolation",IDC_STATIC,6,60,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_INTERPOLATION,72,60,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Use &Amiga resampler for Amiga modules",IDC_CHECK_AMIGA_RESAMPLER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,78,186,12 + LTEXT "Amiga &Filter Type:",IDC_STATIC,6,96,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_AMIGA_FILTER,72,96,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&Repeat",IDC_STATIC,6,114,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_REPEAT,72,114,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "S&tereo Separation",IDC_STATIC,6,132,60,12,SS_CENTERIMAGE + CONTROL "",IDC_SLIDER_STEREOSEPARATION,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | TBS_TOOLTIPS | WS_TABSTOP,72,132,126,15 + LTEXT "&Volume Ramping",IDC_STATIC,6,151,60,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_RAMPING,72,151,120,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,6,175,186,1 +END + +IDD_FILEINFO DIALOGEX 0, 0, 310, 174 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,258,156,48,12 + EDITTEXT IDC_FILEINFO,6,6,300,144,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_SETTINGS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 194 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END + + IDD_FILEINFO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 303 + TOPMARGIN, 7 + BOTTOMMARGIN, 167 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_SETTINGS AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +IDD_FILEINFO AFX_DIALOG_LAYOUT +BEGIN + 0, + 100, 100, 0, 0, + 0, 0, 100, 100 +END + +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_settings.hpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_settings.hpp new file mode 100644 index 000000000..b77ad1a1c --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/libopenmpt_plugin_settings.hpp @@ -0,0 +1,127 @@ +/* + * libopenmpt_plugin_settings.hpp + * ------------------------------ + * Purpose: libopenmpt plugin settings + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#ifndef LIBOPENMPT_PLUGIN_SETTINGS_HPP +#define LIBOPENMPT_PLUGIN_SETTINGS_HPP + +#include + +#include + + +namespace libopenmpt { +namespace plugin { + + +typedef void (*changed_func)(); + +struct libopenmpt_settings { + bool no_default_format = true; + int samplerate = 48000; + int channels = 2; + int mastergain_millibel = 0; + int stereoseparation = 100; + int use_amiga_resampler = 1; + int amiga_filter_type = 0; + int repeatcount = 0; + int interpolationfilterlength = 8; + int ramping = -1; + int vis_allow_scroll = 1; + changed_func changed = nullptr; +}; + + +class settings : public libopenmpt_settings { +private: + std::basic_string subkey; +protected: + virtual void read_setting( const std::string & /* key */ , const std::basic_string & key, int & val ) { + HKEY regkey = HKEY(); + if ( RegOpenKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, KEY_READ, ®key ) == ERROR_SUCCESS ) { + DWORD v = val; + DWORD type = REG_DWORD; + DWORD typesize = sizeof(v); + if ( RegQueryValueEx( regkey, key.c_str(), NULL, &type, (BYTE *)&v, &typesize ) == ERROR_SUCCESS ) + { + val = v; + } + RegCloseKey( regkey ); + regkey = HKEY(); + } + } + virtual void write_setting( const std::string & /* key */, const std::basic_string & key, int val ) { + HKEY regkey = HKEY(); + if ( RegCreateKeyEx( HKEY_CURRENT_USER, ( TEXT("Software\\libopenmpt\\") + subkey ).c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®key, NULL ) == ERROR_SUCCESS ) { + DWORD v = val; + DWORD type = REG_DWORD; + DWORD typesize = sizeof(v); + if ( RegSetValueEx( regkey, key.c_str(), 0, type, (const BYTE *)&v, typesize ) == ERROR_SUCCESS ) + { + // ok + } + RegCloseKey( regkey ); + regkey = HKEY(); + } + } +public: + settings( const std::basic_string & subkey, bool no_default_format_ ) + : subkey(subkey) + { + no_default_format = no_default_format_; + } + void load() + { + #ifdef UNICODE + #define read_setting(a,b,c) read_setting( b , L ## b , c) + #else + #define read_setting(a,b,c) read_setting( b , b , c) + #endif + read_setting( subkey, "Samplerate_Hz", samplerate ); + read_setting( subkey, "Channels", channels ); + read_setting( subkey, "MasterGain_milliBel", mastergain_millibel ); + read_setting( subkey, "StereoSeparation_Percent", stereoseparation ); + read_setting( subkey, "RepeatCount", repeatcount ); + read_setting( subkey, "InterpolationFilterLength", interpolationfilterlength ); + read_setting( subkey, "UseAmigaResampler", use_amiga_resampler ); + read_setting( subkey, "AmigaFilterType", amiga_filter_type ); + read_setting( subkey, "VolumeRampingStrength", ramping ); + read_setting( subkey, "VisAllowScroll", vis_allow_scroll ); + #undef read_setting + } + void save() + { + #ifdef UNICODE + #define write_setting(a,b,c) write_setting( b , L ## b , c) + #else + #define write_setting(a,b,c) write_setting( b , b , c) + #endif + write_setting( subkey, "Samplerate_Hz", samplerate ); + write_setting( subkey, "Channels", channels ); + write_setting( subkey, "MasterGain_milliBel", mastergain_millibel ); + write_setting( subkey, "StereoSeparation_Percent", stereoseparation ); + write_setting( subkey, "RepeatCount", repeatcount ); + write_setting( subkey, "InterpolationFilterLength", interpolationfilterlength ); + write_setting( subkey, "UseAmigaResampler", use_amiga_resampler ); + write_setting( subkey, "AmigaFilterType", amiga_filter_type ); + write_setting( subkey, "VolumeRampingStrength", ramping ); + write_setting( subkey, "VisAllowScroll", vis_allow_scroll ); + #undef write_setting + } + virtual ~settings() + { + return; + } +}; + + +} // namespace plugin +} // namespace libopenmpt + + +#endif // LIBOPENMPT_PLUGIN_SETTINGS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/resource.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/resource.h new file mode 100644 index 000000000..980115f2a --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/plugin-common/resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libopenmpt_plugin_gui.rc +// +#define IDD_SETTINGS 101 +#define IDD_FILEINFO 102 +#define IDC_COMBO_SAMPLERATE 1001 +#define IDC_COMBO_CHANNELS 1002 +#define IDC_SLIDER_GAIN 1003 +#define IDC_COMBO_INTERPOLATION 1004 +#define IDC_COMBO_REPEAT 1005 +#define IDC_SLIDER_STEREOSEPARATION 1006 +#define IDC_COMBO_RAMPING 1007 +#define IDC_FILEINFO 1008 +#define IDC_COMBO_AMIGA_FILTER 1008 +#define IDC_CHECK_AMIGA_RESAMPLER 1009 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/resource.h b/Frameworks/OpenMPT/OpenMPT/libopenmpt/resource.h index 980115f2a..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/resource.h +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/resource.h @@ -1,27 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by libopenmpt_plugin_gui.rc -// -#define IDD_SETTINGS 101 -#define IDD_FILEINFO 102 -#define IDC_COMBO_SAMPLERATE 1001 -#define IDC_COMBO_CHANNELS 1002 -#define IDC_SLIDER_GAIN 1003 -#define IDC_COMBO_INTERPOLATION 1004 -#define IDC_COMBO_REPEAT 1005 -#define IDC_SLIDER_STEREOSEPARATION 1006 -#define IDC_COMBO_RAMPING 1007 -#define IDC_FILEINFO 1008 -#define IDC_COMBO_AMIGA_FILTER 1008 -#define IDC_CHECK_AMIGA_RESAMPLER 1009 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1010 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp index c6d6fc293..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt.cpp @@ -1,1893 +0,0 @@ -/* - * xmp-openmpt.cpp - * --------------- - * Purpose: libopenmpt xmplay input plugin implementation - * Notes : (currently none) - * Authors: OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - -#ifndef NO_XMPLAY - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#if !defined(WINVER) && !defined(_WIN32_WINDOWS) -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP -#endif -#endif -#if !defined(MPT_BUILD_RETRO) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#else -#if defined(_WIN32_WINNT) -#if (_WIN32_WINNT >= 0x0501) -#if defined(_MSC_VER) -#define MPT_WITH_MFC -#endif -#endif -#endif -#endif -#if defined(MPT_WITH_MFC) -#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls -#endif // MPT_WITH_MFC -#ifndef NOMINMAX -#define NOMINMAX -#endif -#if defined(MPT_WITH_MFC) -#include -#include -#endif // MPT_WITH_MFC -#include -#include - -#ifdef LIBOPENMPT_BUILD_DLL -#undef LIBOPENMPT_BUILD_DLL -#endif - -#ifdef _MSC_VER -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif -#ifndef _SCL_SECURE_NO_WARNINGS -#define _SCL_SECURE_NO_WARNINGS -#endif -#endif // _MSC_VER - -#include -#include - -#include - -#include "libopenmpt.hpp" -#include "libopenmpt_ext.hpp" - -#include "libopenmpt_plugin_settings.hpp" - -#include "libopenmpt_plugin_gui.hpp" - -#include "svn_version.h" -#if defined(OPENMPT_VERSION_REVISION) -static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION) ")"; -#else -static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING ")"; -#endif - -#define USE_XMPLAY_FILE_IO - -#define USE_XMPLAY_ISTREAM - -#include "xmplay/xmpin.h" - -// Shortcut block assigned to the OpenMPT plugin by un4seen. -enum { - openmpt_shortcut_first = 0x21000, - openmpt_shortcut_tempo_decrease = openmpt_shortcut_first, - openmpt_shortcut_tempo_increase, - openmpt_shortcut_pitch_decrease, - openmpt_shortcut_pitch_increase, - openmpt_shortcut_switch_interpolation, - openmpt_shortcut_last = 0x21fff, - - openmpt_shortcut_ex = 0x80000000, // Use extended version of the shortcut callback -}; - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define SHORT_TITLE "xmp-openmpt" -#define SHORTER_TITLE "openmpt" - -static CRITICAL_SECTION xmpopenmpt_mutex; -class xmpopenmpt_lock { -public: - xmpopenmpt_lock() { - EnterCriticalSection( &xmpopenmpt_mutex ); - } - ~xmpopenmpt_lock() { - LeaveCriticalSection( &xmpopenmpt_mutex ); - } -}; - -static XMPFUNC_IN * xmpfin = nullptr; -static XMPFUNC_MISC * xmpfmisc = nullptr; -static XMPFUNC_REGISTRY * xmpfregistry = nullptr; -static XMPFUNC_FILE * xmpffile = nullptr; -static XMPFUNC_TEXT * xmpftext = nullptr; -static XMPFUNC_STATUS * xmpfstatus = nullptr; - -struct self_xmplay_t; - -static self_xmplay_t * self = 0; - -static void save_options(); - -static void apply_and_save_options(); - - -static std::string convert_to_native( const std::string & str ); - -static std::string StringEncode( const std::wstring &src, UINT codepage ); - -static std::wstring StringDecode( const std::string & src, UINT codepage ); - -#if defined(UNICODE) -static std::wstring StringToWINAPI( const std::wstring & src ); -#else -static std::string StringToWINAPI( const std::wstring & src ); -#endif - -class xmp_openmpt_settings - : public libopenmpt::plugin::settings -{ -protected: - void read_setting( const std::string & key, const std::basic_string & keyW, int & val ) override { - libopenmpt::plugin::settings::read_setting( key, keyW, val ); - int storedVal = 0; - if ( xmpfregistry->GetInt( "OpenMPT", key.c_str(), &storedVal ) ) { - val = storedVal; - } - } - void write_setting( const std::string & key, const std::basic_string & /* keyW */ , int val ) override { - if ( !xmpfregistry->SetInt( "OpenMPT", key.c_str(), &val ) ) { - // error - } - // ok - } -public: - xmp_openmpt_settings() - : libopenmpt::plugin::settings(TEXT(SHORT_TITLE), false) - { - return; - } - virtual ~xmp_openmpt_settings() - { - return; - } -}; - -struct self_xmplay_t { - std::vector subsong_lengths; - std::vector subsong_names; - std::size_t samplerate = 48000; - std::size_t num_channels = 2; - xmp_openmpt_settings settings; - openmpt::module_ext * mod = nullptr; - bool set_format_called = false; - openmpt::ext::pattern_vis * pattern_vis = nullptr; - std::int32_t tempo_factor = 0, pitch_factor = 0; - bool single_subsong_mode = false; - self_xmplay_t() { - settings.changed = apply_and_save_options; - } - void on_new_mod() { - set_format_called = false; - self->pattern_vis = static_cast( self->mod->get_interface( openmpt::ext::pattern_vis_id ) ); - } - void delete_mod() { - if ( mod ) { - pattern_vis = 0; - set_format_called = false; - delete mod; - mod = 0; - } - } - ~self_xmplay_t() { - return; - } -}; - -static std::string convert_to_native( const std::string & str ) { - char * native_string = xmpftext->Utf8( str.c_str(), -1 ); - std::string result = native_string ? native_string : ""; - if ( native_string ) { - xmpfmisc->Free( native_string ); - native_string = 0; - } - return result; -} - -static std::string StringEncode( const std::wstring &src, UINT codepage ) -{ - int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, nullptr, 0, nullptr, nullptr); - if(required_size <= 0) - { - return std::string(); - } - std::vector encoded_string( required_size ); - WideCharToMultiByte( codepage, 0, src.c_str(), -1, &encoded_string[0], encoded_string.size(), nullptr, nullptr); - return &encoded_string[0]; -} - -static std::wstring StringDecode( const std::string & src, UINT codepage ) -{ - int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, nullptr, 0 ); - if(required_size <= 0) - { - return std::wstring(); - } - std::vector decoded_string( required_size ); - MultiByteToWideChar( codepage, 0, src.c_str(), -1, &decoded_string[0], decoded_string.size() ); - return &decoded_string[0]; -} - -#if defined(UNICODE) - -static std::wstring StringToWINAPI( const std::wstring & src ) -{ - return src; -} - -#else - -static std::string StringToWINAPI( const std::wstring & src ) -{ - return StringEncode( src, CP_ACP ); -} - -#endif - -template -static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) { - std::size_t pos = 0; - const Tstring oldStr = oldStr_; - const Tstring newStr = newStr_; - while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) { - str.replace( pos, oldStr.length(), newStr ); - pos += newStr.length(); - } - return str; -} - -static std::string StringUpperCase( std::string str ) { - std::transform( str.begin(), str.end(), str.begin(), []( char c ) { return static_cast( std::toupper( c ) ); } ); - return str; -} - -static std::string seconds_to_string( float time ) { - std::int64_t time_ms = static_cast( time * 1000 ); - std::int64_t seconds = ( time_ms / 1000 ) % 60; - std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60; - std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) ); - std::ostringstream str; - if ( hours > 0 ) { - str << hours << ":"; - } - str << std::setfill('0') << std::setw(2) << minutes; - str << ":"; - str << std::setfill('0') << std::setw(2) << seconds; - return str.str(); -} - -static void save_settings_to_map( std::map & result, const libopenmpt::plugin::settings & s ) { - result.clear(); - result[ "Samplerate_Hz" ] = s.samplerate; - result[ "Channels" ] = s.channels; - result[ "MasterGain_milliBel" ] = s.mastergain_millibel; - result[ "StereoSeparation_Percent" ] = s.stereoseparation; - result[ "RepeatCount" ] = s.repeatcount; - result[ "InterpolationFilterLength" ] = s.interpolationfilterlength; - result[ "UseAmigaResampler" ] = s.use_amiga_resampler; - result[ "AmigaFilterType" ] = s.amiga_filter_type; - result[ "VolumeRampingStrength" ] = s.ramping; -} - -static inline void load_map_setting( const std::map & map, const std::string & key, int & val ) { - auto it = map.find( key ); - if ( it != map.end() ) { - val = it->second; - } -} - -static void load_settings_from_map( libopenmpt::plugin::settings & s, const std::map & map ) { - load_map_setting( map, "Samplerate_Hz", s.samplerate ); - load_map_setting( map, "Channels", s.channels ); - load_map_setting( map, "MasterGain_milliBel", s.mastergain_millibel ); - load_map_setting( map, "StereoSeparation_Percent", s.stereoseparation ); - load_map_setting( map, "RepeatCount", s.repeatcount ); - load_map_setting( map, "InterpolationFilterLength", s.interpolationfilterlength ); - load_map_setting( map, "UseAmigaResampler", s.use_amiga_resampler ); - load_map_setting( map, "AmigaFilterType", s.amiga_filter_type ); - load_map_setting( map, "VolumeRampingStrength", s.ramping ); -} - -static void load_settings_from_xml( libopenmpt::plugin::settings & s, const std::string & xml ) { - pugi::xml_document doc; - doc.load_string( xml.c_str() ); - pugi::xml_node settings_node = doc.child( "settings" ); - std::map map; - for ( const auto & attr : settings_node.attributes() ) { - map[ attr.name() ] = attr.as_int(); - } - load_settings_from_map( s, map ); -} - -static void save_settings_to_xml( std::string & xml, const libopenmpt::plugin::settings & s ) { - std::map map; - save_settings_to_map( map, s ); - pugi::xml_document doc; - pugi::xml_node settings_node = doc.append_child( "settings" ); - for ( const auto & setting : map ) { - settings_node.append_attribute( setting.first.c_str() ).set_value( setting.second ); - } - std::ostringstream buf; - doc.save( buf ); - xml = buf.str(); -} - -static void apply_options() { - if ( self->mod ) { - if ( !self->set_format_called ) { - // SetFormat will only be called once after loading a file. - // We cannot apply samplerate or numchannels changes afterwards during playback. - self->samplerate = self->settings.samplerate; - self->num_channels = self->settings.channels; - } - self->mod->set_repeat_count( self->settings.repeatcount ); - self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel ); - self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation ); - self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength ); - self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping ); - self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false ); - switch ( self->settings.amiga_filter_type ) { - case 0: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" ); - break; - case 1: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" ); - break; - case 0xA500: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" ); - break; - case 0xA1200: - self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" ); - break; - } - } -} - -static void save_options() { - self->settings.save(); -} - -static void apply_and_save_options() { - apply_options(); - save_options(); -} - -static void reset_options() { - self->settings = xmp_openmpt_settings(); - self->settings.changed = apply_and_save_options; - self->settings.load(); -} - -// get config (return size of config data) (OPTIONAL) -static DWORD WINAPI openmpt_GetConfig( void * config ) { - std::string xml; - save_settings_to_xml( xml, self->settings ); - if ( config ) { - std::memcpy( config, xml.c_str(), xml.length() + 1 ); - } - return xml.length() + 1; -} - -// apply config (OPTIONAL) -static void WINAPI openmpt_SetConfig( void * config, DWORD size ) { - reset_options(); - if ( config ) { - load_settings_from_xml( self->settings, std::string( (char*)config, (char*)config + size ) ); - apply_options(); - } -} - -static void WINAPI ShortcutHandler( DWORD id ) { - if ( !self->mod ) { - return; - } - - bool tempo_changed = false, pitch_changed = false; - switch ( id ) { - case openmpt_shortcut_tempo_decrease: self->tempo_factor--; tempo_changed = true; break; - case openmpt_shortcut_tempo_increase: self->tempo_factor++; tempo_changed = true; break; - case openmpt_shortcut_pitch_decrease: self->pitch_factor--; pitch_changed = true; break; - case openmpt_shortcut_pitch_increase: self->pitch_factor++; pitch_changed = true; break; - case openmpt_shortcut_switch_interpolation: - self->settings.interpolationfilterlength *= 2; - if ( self->settings.interpolationfilterlength > 8 ) { - self->settings.interpolationfilterlength = 1; - } - apply_and_save_options(); - const char *s = nullptr; - switch ( self->settings.interpolationfilterlength ) - { - case 1: s = "Interpolation: Off"; break; - case 2: s = "Interpolation: Linear"; break; - case 4: s = "Interpolation: Cubic"; break; - case 8: s = "Interpolation: Polyphase"; break; - } - if ( s ) { - xmpfmisc->ShowBubble( s, 0 ); - } - break; - } - - self->tempo_factor = std::min( 48, std::max( -48, self->tempo_factor ) ); - self->pitch_factor = std::min( 48, std::max( -48, self->pitch_factor ) ); - const double tempo_factor = std::pow( 2.0, self->tempo_factor / 24.0 ); - const double pitch_factor = std::pow( 2.0, self->pitch_factor / 24.0 ); - - if ( tempo_changed ) { - std::ostringstream s; - s << "Tempo: " << static_cast( 100.0 * tempo_factor ) << "%"; - xmpfmisc->ShowBubble( s.str().c_str(), 0 ); - } else if ( pitch_changed) { - std::ostringstream s; - s << "Pitch: "; - if ( self->pitch_factor > 0 ) - s << "+"; - else if ( self->pitch_factor == 0 ) - s << "+/-"; - s << (self->pitch_factor * 0.5) << " semitones"; - xmpfmisc->ShowBubble( s.str().c_str(), 0 ); - } - - openmpt::ext::interactive *interactive = static_cast( self->mod->get_interface( openmpt::ext::interactive_id ) ); - interactive->set_tempo_factor( tempo_factor ); - interactive->set_pitch_factor( pitch_factor ); - xmpfin->SetLength( static_cast( self->mod->get_duration_seconds() / tempo_factor ), TRUE ); -} - - -static double timeinfo_position = 0.0; -struct timeinfo { - bool valid; - double seconds; - std::int32_t pattern; - std::int32_t row; -}; -static std::queue timeinfos; -static void reset_timeinfos( double position = 0.0 ) { - while ( !timeinfos.empty() ) { - timeinfos.pop(); - } - timeinfo_position = position; -} -static void update_timeinfos( std::int32_t samplerate, std::int32_t count ) { - timeinfo_position += (double)count / (double)samplerate; - timeinfo info; - info.valid = true; - info.seconds = timeinfo_position; - info.pattern = self->mod->get_current_pattern(); - info.row = self->mod->get_current_row(); - timeinfos.push( info ); -} - -static timeinfo current_timeinfo; - -static timeinfo lookup_timeinfo( double seconds ) { - timeinfo info = current_timeinfo; -#if 0 - info.seconds = timeinfo_position; - info.pattern = self->mod->get_current_pattern(); - info.row = self->mod->get_current_row(); -#endif - while ( timeinfos.size() > 0 && timeinfos.front().seconds <= seconds ) { - info = timeinfos.front(); - timeinfos.pop(); - } - current_timeinfo = info; - return current_timeinfo; -} - -static void clear_current_timeinfo() { - current_timeinfo = timeinfo(); -} - -static void WINAPI openmpt_About( HWND win ) { - std::ostringstream about; - about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; - about << " Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; - about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; - about << std::endl; - about << openmpt::string::get( "contact" ) << std::endl; - about << std::endl; - about << "Show full credits?" << std::endl; - if ( MessageBox( win, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) { - return; - } - std::ostringstream credits; - credits << openmpt::string::get( "credits" ); - credits << "Additional thanks to:" << std::endl; - credits << std::endl; - credits << "Arseny Kapoulkine for pugixml" << std::endl; - credits << "https://pugixml.org/" << std::endl; -#if 1 - libopenmpt::plugin::gui_show_file_info( win, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) ); -#else - MessageBox( win, StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK ); -#endif -} - -static void WINAPI openmpt_Config( HWND win ) { -#if 1 - libopenmpt::plugin::gui_edit_settings( &self->settings, win, TEXT(SHORT_TITLE) ); -#else - static_cast(win); -#endif - apply_and_save_options(); -} - -#ifdef USE_XMPLAY_FILE_IO - -#ifdef USE_XMPLAY_ISTREAM - -class xmplay_streambuf : public std::streambuf { -public: - explicit xmplay_streambuf( XMPFILE & file ); -private: - int_type underflow() override; - xmplay_streambuf( const xmplay_streambuf & ); - xmplay_streambuf & operator = ( const xmplay_streambuf & ); -private: - XMPFILE & file; - static inline constexpr std::size_t put_back = 4096; - static inline constexpr std::size_t buf_size = 65536; - std::vector buffer; -}; // class xmplay_streambuf - -xmplay_streambuf::xmplay_streambuf( XMPFILE & file_ ) : file(file_), buffer(buf_size) { - char * end = &buffer.front() + buffer.size(); - setg( end, end, end ); -} - -std::streambuf::int_type xmplay_streambuf::underflow() { - if ( gptr() < egptr() ) { - return traits_type::to_int_type( *gptr() ); - } - char * base = &buffer.front(); - char * start = base; - if ( eback() == base ) { - std::size_t put_back_count = std::min( put_back, static_cast( egptr() - base ) ); - std::memmove( base, egptr() - put_back_count, put_back_count ); - start += put_back_count; - } - std::size_t n = xmpffile->Read( file, start, buffer.size() - ( start - base ) ); - if ( n == 0 ) { - return traits_type::eof(); - } - setg( base, start, start + n ); - return traits_type::to_int_type( *gptr() ); -} - -class xmplay_istream : public std::istream { -private: - xmplay_streambuf buf; -private: - xmplay_istream( const xmplay_istream & ); - xmplay_istream & operator = ( const xmplay_istream & ); -public: - xmplay_istream( XMPFILE & file ) : std::istream(&buf), buf(file) { - return; - } - ~xmplay_istream() { - return; - } -}; // class xmplay_istream - -// Stream for memory-based files (required for could_open_probability) -struct xmplay_membuf : std::streambuf { - xmplay_membuf( const char * base, size_t size ) { - char* p( const_cast( base ) ); - setg(p, p, p + size); - } -}; - -struct xmplay_imemstream : virtual xmplay_membuf, std::istream { - xmplay_imemstream( const char * base, size_t size ) - : xmplay_membuf( base, size ) - , std::istream( static_cast(this)) { - return; - } -}; - -#else // !USE_XMPLAY_ISTREAM - -static std::vector read_XMPFILE_vector( XMPFILE & file ) { - std::vector data( xmpffile->GetSize( file ) ); - if ( data.size() != xmpffile->Read( file, data.data(), data.size() ) ) { - return std::vector(); - } - return data; -} - -static std::string read_XMPFILE_string( XMPFILE & file ) { - std::vector data = read_XMPFILE_vector( file ); - return std::string( data.begin(), data.end() ); -} - -#endif // USE_XMPLAY_ISTREAM - -#endif // USE_XMPLAY_FILE_IO - -static std::string string_replace( std::string str, const std::string & oldStr, const std::string & newStr ) { - std::size_t pos = 0; - while((pos = str.find(oldStr, pos)) != std::string::npos) - { - str.replace(pos, oldStr.length(), newStr); - pos += newStr.length(); - } - return str; -} - -static void write_xmplay_string( char * dst, std::string src ) { - // xmplay buffers are ~40kB, be conservative and truncate at 32kB-2 - if ( !dst ) { - return; - } - src = src.substr( 0, (1<<15) - 2 ); - std::strcpy( dst, src.c_str() ); -} - -static std::string extract_date( const openmpt::module & mod ) { - std::string result = mod.get_metadata("date"); - if ( result.empty() ) { - // Search the sample, instrument and message texts for possible release years. - // We'll look for things that may vaguely resemble a release year, such as 4-digit numbers - // or 2-digit numbers with a leading apostrophe. Generally, only years between - // 1988 (release of Ultimate SoundTracker) and the current year + 1 (safety margin) will - // be considered. - std::string s = " " + mod.get_metadata("message"); - auto names = mod.get_sample_names(); - for ( const auto & name : names ) { - s += " " + name; - } - names = mod.get_instrument_names(); - for ( const auto & name : names ) { - s += " " + name; - } - s += " "; - - int32_t best_year = 0; - - SYSTEMTIME time; - GetSystemTime( &time ); - const int32_t current_year = time.wYear + 1; - -#define MPT_NUMERIC( x ) ( ( x >= '0' ) && ( x <= '9' ) ) - for ( auto i = s.cbegin(); i != s.cend(); ++i ) { - std::size_t len = s.length(); - std::size_t idx = i - s.begin(); - std::size_t remaining = len - idx; - if ( ( remaining >= 6 ) && !MPT_NUMERIC( i[0] ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && MPT_NUMERIC( i[3] ) && MPT_NUMERIC( i[4] ) && !MPT_NUMERIC( i[5] ) ) { - // Four-digit year - const int32_t year = ( i[1] - '0' ) * 1000 + ( i[2] - '0' ) * 100 + ( i[3] - '0' ) * 10 + ( i[4] - '0' ); - if ( year >= 1988 && year <= current_year ) { - best_year = std::max( year, best_year ); - } - } else if ( ( remaining >= 4 ) && ( i[0] == '\'' ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && !MPT_NUMERIC( i[3] ) ) { - // Apostrophe + two-digit year - const int32_t year = ( i[1] - '0' ) * 10 + ( i[2] - '0' ); - if ( year >= 88 && year <= 99 ) { - best_year = std::max( 1900 + year, best_year ); - } else if ( year >= 00 && ( 2000 + year ) <= current_year ) { - best_year = std::max( 2000 + year, best_year ); - } - } - } -#undef MPT_NUMERIC - - if ( best_year != 0 ) { - std::ostringstream os; - os << best_year; - result = os.str(); - } - } - - return result; -} - -static void append_xmplay_tag( std::string & tags, const std::string & tag, const std::string & val ) { - if ( tag.empty() ) { - return; - } - if ( val.empty() ) { - return; - } - tags.append( tag ); - tags.append( 1, '\0' ); - tags.append( val ); - tags.append( 1, '\0' ); -} - -static char * build_xmplay_tags( const openmpt::module & mod, int32_t subsong = -1 ) { - std::string tags; - const std::string title = mod.get_metadata("title"); - - const auto subsong_names = mod.get_subsong_names(); - auto first_subsong = subsong_names.cbegin(), last_subsong = subsong_names.cend(); - if ( subsong >= 0 && static_cast( subsong ) < subsong_names.size() ) { - first_subsong += subsong; - last_subsong = first_subsong + 1; - } else - { - last_subsong = first_subsong + 1; - } - - for ( auto subsong_name = first_subsong; subsong_name != last_subsong; subsong_name++ ) { - append_xmplay_tag( tags, "filetype", convert_to_native( StringUpperCase( mod.get_metadata( "type" ) ) ) ); - append_xmplay_tag( tags, "title", convert_to_native( ( subsong_name->empty() || subsong == -1 ) ? title : *subsong_name ) ); - append_xmplay_tag( tags, "artist", convert_to_native( mod.get_metadata( "artist" ) ) ); - append_xmplay_tag( tags, "album", convert_to_native( mod.get_metadata( "xmplay-album" ) ) ); // todo, libopenmpt does not support that - append_xmplay_tag( tags, "date", convert_to_native( extract_date( mod ) ) ); - append_xmplay_tag( tags, "track", convert_to_native( mod.get_metadata( "xmplay-tracknumber" ) ) ); // todo, libopenmpt does not support that - append_xmplay_tag( tags, "genre", convert_to_native( mod.get_metadata( "xmplay-genre" ) ) ); // todo, libopenmpt does not support that - append_xmplay_tag( tags, "comment", convert_to_native( mod.get_metadata( "message" ) ) ); - tags.append( 1, '\0' ); - } - char * result = static_cast( xmpfmisc->Alloc( tags.size() ) ); - if ( !result ) { - return nullptr; - } - std::copy( tags.data(), tags.data() + tags.size(), result ); - return result; -} - -static float * build_xmplay_length( const openmpt::module & /* mod */ ) { - float * result = static_cast( xmpfmisc->Alloc( sizeof( float ) * self->subsong_lengths.size() ) ); - if ( !result ) { - return nullptr; - } - for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { - result[i] = self->subsong_lengths[i]; - } - return result; -} - -static void clear_xmplay_string( char * str ) { - if ( !str ) { - return; - } - str[0] = '\0'; -} - -static std::string sanitize_xmplay_info_string( const std::string & str ) { - std::string result; - result.reserve(str.size()); - for ( auto c : str ) { - switch ( c ) { - case '\0': - case '\t': - case '\r': - case '\n': - break; - default: - result.push_back( c ); - break; - } - } - return result; -} - -static std::string sanitize_xmplay_multiline_info_string( const std::string & str ) { - std::string result; - result.reserve(str.size()); - for ( auto c : str ) { - switch ( c ) { - case '\0': - case '\t': - case '\r': - break; - case '\n': - result.push_back( '\r' ); - result.push_back( '\t' ); - break; - default: - result.push_back( c ); - break; - } - } - return result; -} - -static std::string sanitize_xmplay_multiline_string( const std::string & str ) { - std::string result; - result.reserve(str.size()); - for ( auto c : str ) { - switch ( c ) { - case '\0': - case '\t': - break; - default: - result.push_back( c ); - break; - } - } - return result; -} - -// check if a file is playable by this plugin -// more thorough checks can be saved for the GetFileInfo and Open functions -static BOOL WINAPI openmpt_CheckFile( const char * filename, XMPFILE file ) { - static_cast( filename ); - try { - #ifdef USE_XMPLAY_FILE_IO - #ifdef USE_XMPLAY_ISTREAM - switch ( xmpffile->GetType( file ) ) { - case XMPFILE_TYPE_MEMORY: - { - xmplay_imemstream s( reinterpret_cast( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) ); - return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; - } - break; - case XMPFILE_TYPE_FILE: - case XMPFILE_TYPE_NETFILE: - case XMPFILE_TYPE_NETSTREAM: - default: - { - xmplay_istream s( file ); - return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; - } - break; - } - #else - if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { - std::string data( reinterpret_cast( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) ); - std::istringstream s( data ); - return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; - } else { - std::string data = read_XMPFILE_string( file ); - std::istringstream s(data); - return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; - } - #endif - #else - std::ifstream s( filename, std::ios_base::binary ); - return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; - #endif - } catch ( ... ) { - return FALSE; - } - return FALSE; -} - -static DWORD WINAPI openmpt_GetFileInfo( const char * filename, XMPFILE file, float * * length, char * * tags ) { - static_cast( filename ); - try { - std::map< std::string, std::string > ctls - { - { "load.skip_plugins", "1" }, - { "load.skip_samples", "1" }, - }; - #ifdef USE_XMPLAY_FILE_IO - #ifdef USE_XMPLAY_ISTREAM - switch ( xmpffile->GetType( file ) ) { - case XMPFILE_TYPE_MEMORY: - { - openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); - if ( length ) { - *length = build_xmplay_length( mod ); - } - if ( tags ) { - *tags = build_xmplay_tags( mod ); - } - } - break; - case XMPFILE_TYPE_FILE: - case XMPFILE_TYPE_NETFILE: - case XMPFILE_TYPE_NETSTREAM: - default: - { - xmplay_istream s( file ); - openmpt::module mod( s, std::clog, ctls ); - if ( length ) { - *length = build_xmplay_length( mod ); - } - if ( tags ) { - *tags = build_xmplay_tags( mod ); - } - } - break; - } - #else - if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { - openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); - if ( length ) { - *length = build_xmplay_length( mod ); - } - if ( tags ) { - *tags = build_xmplay_tags( mod ); - } - } else { - openmpt::module mod( read_XMPFILE_vector( file ), std::clog, ctls ); - if ( length ) { - *length = build_xmplay_length( mod ); - } - if ( tags ) { - *tags = build_xmplay_tags( mod ); - } - } - #endif - #else - std::ifstream s( filename, std::ios_base::binary ); - openmpt::module mod( s, std::clog, ctls ); - if ( length ) { - *length = build_xmplay_length( mod ); - } - if ( tags ) { - *tags = build_xmplay_tags( mod ); - } - #endif - } catch ( ... ) { - if ( length ) *length = nullptr; - if ( tags ) *tags = nullptr; - return 0; - } - return self->subsong_lengths.size() + XMPIN_INFO_NOSUBTAGS; -} - -// open a file for playback -// return: 0=failed, 1=success, 2=success and XMPlay can close the file -static DWORD WINAPI openmpt_Open( const char * filename, XMPFILE file ) { - static_cast( filename ); - xmpopenmpt_lock guard; - reset_options(); - try { - std::map< std::string, std::string > ctls - { - { "seek.sync_samples", "1" }, - { "play.at_end", "continue" }, - }; - self->delete_mod(); - #ifdef USE_XMPLAY_FILE_IO - #ifdef USE_XMPLAY_ISTREAM - switch ( xmpffile->GetType( file ) ) { - case XMPFILE_TYPE_MEMORY: - self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); - break; - case XMPFILE_TYPE_FILE: - case XMPFILE_TYPE_NETFILE: - case XMPFILE_TYPE_NETSTREAM: - default: - { - xmplay_istream s( file ); - self->mod = new openmpt::module_ext( s, std::clog, ctls ); - } - break; - } - #else - if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { - self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); - } else { - self->mod = new openmpt::module_ext( read_XMPFILE_vector( file ), std::clog, ctls ); - } - #endif - #else - self->mod = new openmpt::module_ext( std::ifstream( filename, std::ios_base::binary ), std::clog, ctls ); - #endif - self->on_new_mod(); - clear_current_timeinfo(); - reset_timeinfos(); - apply_options(); - - std::int32_t num_subsongs = self->mod->get_num_subsongs(); - self->subsong_lengths.resize( num_subsongs ); - for ( std::int32_t i = 0; i < num_subsongs; ++i ) { - self->mod->select_subsong( i ); - self->subsong_lengths[i] = static_cast( self->mod->get_duration_seconds() ); - } - self->subsong_names = self->mod->get_subsong_names(); - self->mod->select_subsong( 0 ); - self->tempo_factor = 0; - self->pitch_factor = 0; - - xmpfin->SetLength( self->subsong_lengths[0], TRUE ); - return 2; - } catch ( ... ) { - self->delete_mod(); - return 0; - } - return 0; -} - -// close the file -static void WINAPI openmpt_Close() { - xmpopenmpt_lock guard; - self->delete_mod(); -} - -// set the sample format (in=user chosen format, out=file format if different) -static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) { - if ( !form ) { - return; - } - // SetFormat will only be called once after loading a file. - // We cannot apply samplerate or numchannels changes afterwards during playback. - self->set_format_called = true; - if ( !self->mod ) { - form->rate = 0; - form->chan = 0; - form->res = 0; - return; - } - if ( self->settings.samplerate != 0 ) { - form->rate = self->samplerate; - } else { - if ( form->rate > 0 ) { - self->samplerate = form->rate; - } else { - form->rate = 48000; - self->samplerate = 48000; - } - } - if ( self->settings.channels != 0 ) { - form->chan = self->num_channels; - } else { - if ( form->chan > 0 ) { - if ( form->chan > 2 ) { - form->chan = 4; - self->num_channels = 4; - } else { - self->num_channels = form->chan; - } - } else { - form->chan = 2; - self->num_channels = 2; - } - } - form->res = 4; // float -} - -// get the tags -static char * WINAPI openmpt_GetTags() { - if ( !self->mod ) { - char * tags = static_cast( xmpfmisc->Alloc( 1 ) ); - tags[0] = '\0'; - return tags; - } - return build_xmplay_tags( *self->mod, std::max( 0, self->mod->get_selected_subsong() ) ); -} - -// get the main panel info text -static void WINAPI openmpt_GetInfoText( char * format, char * length ) { - if ( !self->mod ) { - clear_xmplay_string( format ); - clear_xmplay_string( length ); - return; - } - if ( format ) { - std::ostringstream str; - str - << StringUpperCase( self->mod->get_metadata("type") ) - << " - " - << self->mod->get_num_channels() << " ch" - << " - " - << "(via " << SHORTER_TITLE << ")" - ; - write_xmplay_string( format, sanitize_xmplay_info_string( str.str() ) ); - } - if ( length ) { - std::ostringstream str; - str - << length - << " - " - << self->mod->get_num_orders() << " orders" - ; - write_xmplay_string( length, sanitize_xmplay_info_string( str.str() ) ); - } -} - -// get text for "General" info window -// separate headings and values with a tab (\t), end each line with a carriage-return (\r) -static void WINAPI openmpt_GetGeneralInfo( char * buf ) { - if ( !self->mod ) { - clear_xmplay_string( buf ); - return; - } - std::ostringstream str; - str << "\r"; - bool metadatainfo = false; - if ( !self->mod->get_metadata("artist").empty() ) { - metadatainfo = true; - str << "Artist" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("artist") ) << "\r"; - } - const std::string date = extract_date( *self->mod ); - if ( !date.empty() ) { - metadatainfo = true; - str << "Date" << "\t" << sanitize_xmplay_info_string( date ) << "\r"; - } - if ( metadatainfo ) { - str << "\r"; - } - str << "Format" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("type") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("type_long") ) << ")" << "\r"; - if ( !self->mod->get_metadata("originaltype").empty() ) { - str << "Original Type" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype_long") ) << ")" << "\r"; - } - if ( !self->mod->get_metadata("container").empty() ) { - str << "Container" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("container") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("container_long") ) << ")" << "\r"; - } - str - << "Channels" << "\t" << self->mod->get_num_channels() << "\r" - << "Orders" << "\t" << self->mod->get_num_orders() << "\r" - << "Patterns" << "\t" << self->mod->get_num_patterns() << "\r"; - if ( self->mod->get_num_instruments() != 0 ) { - str << "Instruments" << "\t" << self->mod->get_num_instruments() << "\r"; - } - str << "Samples" << "\t" << self->mod->get_num_samples() << "\r"; - - if( !self->single_subsong_mode && self->subsong_lengths.size() > 1 ) { - for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { - str << ( i == 0 ? "Subsongs\t" : "\t" ) << (i + 1) << ". " << seconds_to_string( self->subsong_lengths[i]) << " " << self->subsong_names[i] << "\r"; - } - } - - str - << "\r" - << "Tracker" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("tracker") ) << "\r" - << "Player" << "\t" << "xmp-openmpt" << " version " << openmpt::string::get( "library_version" ) << "\r" - ; - std::string warnings = self->mod->get_metadata("warnings"); - if ( !warnings.empty() ) { - str << "Warnings" << "\t" << sanitize_xmplay_multiline_info_string( warnings ) << "\r"; - } - str << "\r"; - write_xmplay_string( buf, str.str() ); -} - -// get text for "Message" info window -// separate tag names and values with a tab (\t), and end each line with a carriage-return (\r) -static void WINAPI openmpt_GetMessage( char * buf ) { - if ( !self->mod ) { - clear_xmplay_string( buf ); - return; - } - write_xmplay_string( buf, convert_to_native( sanitize_xmplay_multiline_string( string_replace( self->mod->get_metadata("message"), "\n", "\r" ) ) ) ); -} - -// Seek to a position (in granularity units) -// return the new position in seconds (-1 = failed) -static double WINAPI openmpt_SetPosition( DWORD pos ) { - if ( !self->mod ) { - return -1.0; - } - if ( pos == static_cast(static_cast(XMPIN_POS_LOOP)) ) { - // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on. - // There is currently no way to easily figure out at which time the loop restarts. - return -2; - } else if ( pos == static_cast(static_cast(XMPIN_POS_AUTOLOOP)) ) { - // In the auto-looping case, the function should only loop when a loop has been detected, and otherwise return -1 - // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on. - // There is currently no way to easily figure out at which time the loop restarts. - return -2; - } - if ( pos & XMPIN_POS_SUBSONG ) { - self->single_subsong_mode = ( pos & XMPIN_POS_SUBSONG1 ) != 0; - const int32_t subsong = pos & 0xffff; - try { - self->mod->select_subsong( subsong ); - } catch ( ... ) { - return 0.0; - } - openmpt::ext::interactive *interactive = static_cast( self->mod->get_interface( openmpt::ext::interactive_id ) ); - xmpfin->SetLength( static_cast( self->subsong_lengths[ subsong ] / interactive->get_tempo_factor() ), TRUE ); - xmpfin->UpdateTitle( nullptr ); - reset_timeinfos( 0 ); - return 0.0; - } - double new_position = self->mod->set_position_seconds( static_cast( pos ) * 0.001 ); - reset_timeinfos( new_position ); - return new_position; -} - -// Get the seeking granularity in seconds -static double WINAPI openmpt_GetGranularity() { - return 0.001; -} - -// get some sample data, always floating-point -// count=number of floats to write (not bytes or samples) -// return number of floats written. if it's less than requested, playback is ended... -// so wait for more if there is more to come (use CheckCancel function to check if user wants to cancel) -static DWORD WINAPI openmpt_Process( float * dstbuf, DWORD count ) { - xmpopenmpt_lock guard; - if ( !self->mod || self->num_channels == 0 ) { - return 0; - } - update_timeinfos( self->samplerate, 0 ); - std::size_t frames = count / self->num_channels; - std::size_t frames_to_render = frames; - std::size_t frames_rendered = 0; - while ( frames_to_render > 0 ) { - std::size_t frames_chunk = std::min( frames_to_render, static_cast( ( self->samplerate + 99 ) / 100 ) ); // 100 Hz timing info update interval - switch ( self->num_channels ) { - case 1: - { - frames_chunk = self->mod->read( self->samplerate, frames_chunk, dstbuf ); - } - break; - case 2: - { - frames_chunk = self->mod->read_interleaved_stereo( self->samplerate, frames_chunk, dstbuf ); - } - break; - case 4: - { - frames_chunk = self->mod->read_interleaved_quad( self->samplerate, frames_chunk, dstbuf ); - } - break; - } - dstbuf += frames_chunk * self->num_channels; - if ( frames_chunk == 0 ) { - break; - } - update_timeinfos( self->samplerate, frames_chunk ); - frames_to_render -= frames_chunk; - frames_rendered += frames_chunk; - } - if ( frames_rendered == 0 ) { - return 0; - } - return frames_rendered * self->num_channels; -} - -static void add_names( std::ostream & str, const std::string & title, const std::vector & names, int display_offset ) { - if ( names.size() > 0 ) { - bool valid = false; - for ( std::size_t i = 0; i < names.size(); i++ ) { - if ( names[i] != "" ) { - valid = true; - } - } - if ( !valid ) { - return; - } - str << title << " Names:" << "\r"; - for ( std::size_t i = 0; i < names.size(); i++ ) { - str << std::setfill('0') << std::setw(2) << (display_offset + i) << std::setw(0) << "\t" << convert_to_native( names[i] ) << "\r"; - } - str << "\r"; - } -} - -static void WINAPI openmpt_GetSamples( char * buf ) { - if ( !self->mod ) { - clear_xmplay_string( buf ); - return; - } - std::ostringstream str; - add_names( str, "Instrument", self->mod->get_instrument_names(), 1 ); - add_names( str, "Sample", self->mod->get_sample_names(), 1 ); - add_names( str, "Channel", self->mod->get_channel_names(), 1 ); - add_names( str, "Order", self->mod->get_order_names(), 0 ); - add_names( str, "Pattern", self->mod->get_pattern_names(), 0 ); - write_xmplay_string( buf, str.str() ); -} - -static DWORD WINAPI openmpt_GetSubSongs( float * length ) { - *length = 0.0f; - for ( auto sub_length : self->subsong_lengths ) { - *length += sub_length; - } - - return static_cast( self->subsong_lengths.size() ); -} - -enum ColorIndex -{ - col_background = 0, - col_unknown, - col_text, - col_empty, - col_instr, - col_vol, - col_pitch, - col_global, - - col_max -}; - -static ColorIndex effect_type_to_color_index( openmpt::ext::pattern_vis::effect_type effect_type ) { - switch ( effect_type ) { - case openmpt::ext::pattern_vis::effect_unknown: return col_unknown; break; - case openmpt::ext::pattern_vis::effect_general: return col_text ; break; - case openmpt::ext::pattern_vis::effect_global : return col_global ; break; - case openmpt::ext::pattern_vis::effect_volume : return col_vol ; break; - case openmpt::ext::pattern_vis::effect_panning: return col_instr ; break; - case openmpt::ext::pattern_vis::effect_pitch : return col_pitch ; break; - default: return col_unknown; break; - } -} - -const struct Columns -{ - int num_chars; - int color; -} pattern_columns[] = { - { 3, col_text }, // C-5 - { 2, col_instr }, // 01 - { 3, col_vol }, // v64 - { 3, col_pitch }, // EFF -}; - -static const int max_cols = 4; - -static void assure_width( std::string & str, std::size_t width ) { - if ( str.length() == width ) { - return; - } else if ( str.length() < width ) { - str += std::string( width - str.length(), ' ' ); - } else if ( str.length() > width ) { - str = str.substr( 0, width ); - } -} - -struct ColorRGBA -{ - uint8_t r, g, b, a; -}; - -union Color -{ - ColorRGBA rgba; - COLORREF dw; -}; - -static_assert(sizeof(Color) == 4); - -HDC visDC; -HGDIOBJ visbitmap; - -Color viscolors[col_max]; -HPEN vispens[col_max]; -HBRUSH visbrushs[col_max]; -HFONT visfont; -static int last_pattern = -1; - -static Color invert_color( Color c ) { - Color res; - res.rgba.a = c.rgba.a; - res.rgba.r = 255 - c.rgba.r; - res.rgba.g = 255 - c.rgba.g; - res.rgba.b = 255 - c.rgba.b; - return res; -} - -static BOOL WINAPI VisOpen(DWORD colors[3]) { - xmpopenmpt_lock guard; - visDC = 0; - visbitmap = 0; - visfont = 0; - - viscolors[col_background].dw = colors[0]; - viscolors[col_unknown].dw = colors[1]; - viscolors[col_text].dw = colors[2]; - - viscolors[col_global] = invert_color( viscolors[col_background] ); - - const int r = viscolors[col_text].rgba.r, g = viscolors[col_text].rgba.g, b = viscolors[col_text].rgba.b; - viscolors[col_empty].rgba.r = static_cast( (r + viscolors[col_background].rgba.r) / 2 ); - viscolors[col_empty].rgba.g = static_cast( (g + viscolors[col_background].rgba.g) / 2 ); - viscolors[col_empty].rgba.b = static_cast( (b + viscolors[col_background].rgba.b) / 2 ); - viscolors[col_empty].rgba.a = 0; - -#define MIXCOLOR(col, c1, c2, c3) { \ - viscolors[col] = viscolors[col_text]; \ - int mix = viscolors[col].rgba.c1 + 0xA0; \ - viscolors[col].rgba.c1 = static_cast( mix ); \ - if ( mix > 0xFF ) { \ - viscolors[col].rgba.c2 = std::max( static_cast( c2 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \ - viscolors[col].rgba.c3 = std::max( static_cast( c3 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \ - viscolors[col].rgba.c1 = 0xFF; \ - } } - - MIXCOLOR(col_instr, g, r, b); - MIXCOLOR(col_vol, b, r, g); - MIXCOLOR(col_pitch, r, g, b); -#undef MIXCOLOR - - for( int i = 0; i < col_max; ++i ) { - vispens[i] = CreatePen( PS_SOLID, 1, viscolors[i].dw ); - visbrushs[i] = CreateSolidBrush( viscolors[i].dw ); - } - - clear_current_timeinfo(); - - if ( !self->mod ) { - return FALSE; - } - return TRUE; -} -static void WINAPI VisClose() { - xmpopenmpt_lock guard; - - for( int i = 0; i < col_max; ++i ) { - DeletePen( vispens[i] ); - DeleteBrush( visbrushs[i] ); - } - - DeleteFont( visfont ); - DeleteBitmap( visbitmap ); - if ( visDC ) { - DeleteDC( visDC ); - } -} -static void WINAPI VisSize( HDC /* dc */ , SIZE * /* size */ ) { - xmpopenmpt_lock guard; - last_pattern = -1; // Force redraw -} - -#if 0 -static BOOL WINAPI VisRender( DWORD * /* buf */ , SIZE /* size */ , DWORD /* flags */ ) { - xmpopenmpt_lock guard; - return FALSE; -} -#endif - -static int get_pattern_width( int chars_per_channel, int spaces_per_channel, int num_cols, int text_size, int channels ) -{ - int pattern_width = ((chars_per_channel * channels + 4) * text_size) + (spaces_per_channel * channels + channels - (num_cols == 1 ? 1 : 2)) * (text_size / 2); - return pattern_width; -} - -static BOOL WINAPI VisRenderDC( HDC dc, SIZE size, DWORD flags ) { - xmpopenmpt_lock guard; - RECT rect; - - if ( !visfont ) { - // Force usage of a nice monospace font - LOGFONT logfont; - GetObject ( GetCurrentObject( dc, OBJ_FONT ), sizeof(logfont), &logfont ); - _tcscpy( logfont.lfFaceName, TEXT("Lucida Console") ); - visfont = CreateFontIndirect( &logfont ); - } - SIZE text_size; - SelectFont( dc, visfont ); - if ( GetTextExtentPoint32( dc, TEXT("W"), 1, &text_size ) == FALSE ) { - return FALSE; - } - - if ( flags & XMPIN_VIS_INIT ) { - last_pattern = -1; - } - - timeinfo info = lookup_timeinfo( xmpfstatus->GetTime() ); - - if ( !info.valid ) { - RECT bgrect; - bgrect.top = 0; - bgrect.left = 0; - bgrect.right = size.cx; - bgrect.bottom = size.cy; - FillRect(dc, &bgrect, visbrushs[col_background]); - return TRUE; - } - - int pattern = info.pattern; - int current_row = info.row; - - const std::size_t channels = self->mod->get_num_channels(); - const std::size_t rows = self->mod->get_pattern_num_rows( pattern ); - - const std::size_t num_half_chars = std::max( static_cast( 2 * size.cx / text_size.cx ), std::size_t(8) ) - 8; - //const std::size_t num_rows = size.cy / text_size.cy; - - // Spaces between pattern components are half width, full space at channel end - const std::size_t half_chars_per_channel = num_half_chars / channels; - std::size_t chars_per_channel, spaces_per_channel; - std::size_t num_cols; - std::size_t col0_width = pattern_columns[0].num_chars; - for ( num_cols = sizeof ( pattern_columns ) / sizeof ( pattern_columns[0] ); num_cols >= 1; num_cols-- ) { - chars_per_channel = 0; - spaces_per_channel = num_cols > 1 ? num_cols : 0; // No extra space if we only display notes - for ( std::size_t i = 0; i < num_cols; i++ ) { - chars_per_channel += pattern_columns[i].num_chars; - } - - if ( half_chars_per_channel >= chars_per_channel * 2 + spaces_per_channel + 1 || num_cols == 1 ) { - break; - } - } - - if ( !self->settings.vis_allow_scroll ) { - if ( num_cols == 1 ) { - spaces_per_channel = 0; - while ( get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels ) > size.cx && chars_per_channel > 1 ) { - chars_per_channel -= 1; - } - col0_width = chars_per_channel; - chars_per_channel = col0_width; - } - } - - int pattern_width = get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels ); - int pattern_height = rows * text_size.cy; - - if ( !visDC || last_pattern != pattern ) { - DeleteBitmap( visbitmap ); - if ( visDC ) { - DeleteDC( visDC ); - } - - visDC = CreateCompatibleDC( dc ); - visbitmap = CreateCompatibleBitmap( dc, pattern_width, pattern_height ); - SelectBitmap( visDC, visbitmap ); - - SelectBrush( visDC, vispens[col_unknown] ); - SelectBrush( visDC, visbrushs[col_background] ); - - SelectFont( visDC, visfont ); - - rect.top = 0; - rect.left = 0; - rect.right = pattern_width; - rect.bottom = pattern_height; - FillRect( visDC, &rect, visbrushs[col_background] ); - - SetBkColor( visDC, viscolors[col_background].dw ); - - POINT pos; - pos.y = 0; - - for ( std::size_t row = 0; row < rows; row++ ) { - pos.x = 0; - - std::ostringstream s; - s.imbue(std::locale::classic()); - s << std::setfill('0') << std::setw(3) << row; - const std::string rowstr = s.str(); - - SetTextColor( visDC, viscolors[1].dw ); - TextOutA( visDC, pos.x, pos.y, rowstr.c_str(), rowstr.length() ); - pos.x += 4 * text_size.cx; - - for ( std::size_t channel = 0; channel < channels; ++channel ) { - - struct coldata { - std::string text; - bool is_empty; - ColorIndex color; - coldata() - : is_empty(false) - , color(col_unknown) - { - return; - } - }; - - coldata cols[max_cols]; - - for ( std::size_t col = 0; col < max_cols; ++col ) { - switch ( col ) { - case 0: - cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_note ); - break; - case 1: - cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_instrument ); - break; - case 2: - cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volumeffect ) - + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volume ); - break; - case 3: - cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_effect ) - + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_parameter ); - break; - } - int color = pattern_columns[col].color; - if ( self->pattern_vis && ( col == 2 || col == 3 ) ) { - if ( col == 2 ) { - color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_volume_effect_type( pattern, row, channel ) ); - } - if ( col == 3 ) { - color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_effect_type( pattern, row, channel ) ); - } - } - switch ( cols[col].text[0] ) { - case ' ': - [[fallthrough]]; - case '.': - cols[col].is_empty = true; - [[fallthrough]]; - case '^': - [[fallthrough]]; - case '=': - [[fallthrough]]; - case '~': - color = col_empty; - break; - } - cols[col].color = (ColorIndex)color; - - } - - if ( num_cols <= 3 && !cols[3].is_empty ) { - if ( cols[2].is_empty ) { - cols[2] = cols[3]; - } else if ( cols[0].is_empty ) { - cols[0] = cols[3]; - } - } - - if ( num_cols <= 2 && !cols[2].is_empty ) { - if ( cols[0].is_empty ) { - cols[0] = cols[2]; - } - } - - for ( std::size_t col = 0; col < num_cols; ++col ) { - - std::size_t col_width = ( num_cols > 1 ) ? pattern_columns[col].num_chars : col0_width; - - assure_width( cols[col].text, col_width ); - - SetTextColor( visDC, viscolors[cols[col].color].dw ); - TextOutA( visDC, pos.x, pos.y, cols[col].text.c_str(), cols[col].text.length() ); - pos.x += col_width * text_size.cx + text_size.cx / 2; - } - // Extra padding - if ( num_cols > 1 ) { - pos.x += text_size.cx / 2; - } - } - - pos.y += text_size.cy; - } - } - - rect.top = 0; - rect.left = 0; - rect.right = size.cx; - rect.bottom = size.cy; - FillRect( dc, &rect, visbrushs[col_background] ); - - int offset_x = (size.cx - pattern_width) / 2; - int offset_y = (size.cy - text_size.cy) / 2 - current_row * text_size.cy; - int src_offset_x = 0; - int src_offset_y = 0; - - if ( offset_x < 0 ) { - src_offset_x -= offset_x; - pattern_width = std::min( static_cast( pattern_width + offset_x ), static_cast( size.cx ) ); - offset_x = 0; - } - - if ( offset_y < 0 ) { - src_offset_y -= offset_y; - pattern_height = std::min( static_cast( pattern_height + offset_y ), static_cast( size.cy ) ); - offset_y = 0; - } - - BitBlt( dc, offset_x, offset_y, pattern_width, pattern_height, visDC, src_offset_x, src_offset_y , SRCCOPY ); - - // Highlight current row - rect.left = offset_x; - rect.top = (size.cy - text_size.cy) / 2; - rect.right = rect.left + pattern_width; - rect.bottom = rect.top + text_size.cy; - InvertRect( dc, &rect ); - - last_pattern = pattern; - - return TRUE; -} - -#if 0 -static void WINAPI VisButton( DWORD /* x */ , DWORD /* y */ ) { - //xmpopenmpt_lock guard; -} -#endif - -static XMPIN xmpin = { -#ifdef USE_XMPLAY_FILE_IO - 0 | -#else - XMPIN_FLAG_NOXMPFILE | -#endif - XMPIN_FLAG_CONFIG | XMPIN_FLAG_LOOP, - xmp_openmpt_string, - nullptr, // "libopenmpt\0mptm/mptmz", - openmpt_About, - openmpt_Config, - openmpt_CheckFile, - openmpt_GetFileInfo, - openmpt_Open, - openmpt_Close, - nullptr, // reserved - openmpt_SetFormat, - openmpt_GetTags, - openmpt_GetInfoText, - openmpt_GetGeneralInfo, - openmpt_GetMessage, - openmpt_SetPosition, - openmpt_GetGranularity, - nullptr, // GetBuffering - openmpt_Process, - nullptr, // WriteFile - openmpt_GetSamples, - openmpt_GetSubSongs, // GetSubSongs - nullptr, // GetCues - nullptr, // GetDownloaded - - "OpenMPT Pattern Display", - VisOpen, - VisClose, - VisSize, - /*VisRender,*/nullptr, - VisRenderDC, - /*VisButton,*/nullptr, - - nullptr, // reserved2 - openmpt_GetConfig, - openmpt_SetConfig -}; - -static const char * xmp_openmpt_default_exts = "OpenMPT\0mptm/mptmz"; - -static char * file_formats; - -static void xmp_openmpt_on_dll_load() { - ZeroMemory( &xmpopenmpt_mutex, sizeof( xmpopenmpt_mutex ) ); - #if defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable:28125) // The function 'InitializeCriticalSection' must be called from within a try/except block: The requirement might be conditional. - #endif // _MSC_VER - InitializeCriticalSection( &xmpopenmpt_mutex ); - #if defined(_MSC_VER) - #pragma warning(pop) - #endif // _MSC_VER - std::vector extensions = openmpt::get_supported_extensions(); - std::string filetypes_string = "OpenMPT"; - filetypes_string.push_back('\0'); - bool first = true; - for ( const auto & ext : extensions ) { - if ( first ) { - first = false; - } else { - filetypes_string.push_back('/'); - } - filetypes_string += ext; - } - filetypes_string.push_back('\0'); - file_formats = (char*)HeapAlloc( GetProcessHeap(), 0, filetypes_string.size() ); - if ( file_formats ) { - std::copy( filetypes_string.begin(), filetypes_string.end(), file_formats ); - xmpin.exts = file_formats; - } else { - xmpin.exts = xmp_openmpt_default_exts; - } - self = new self_xmplay_t(); -} - -static void xmp_openmpt_on_dll_unload() { - delete self; - self = nullptr; - if ( xmpin.exts != xmp_openmpt_default_exts ) { - HeapFree(GetProcessHeap(), 0, (LPVOID)const_cast(xmpin.exts)); - } - xmpin.exts = nullptr; - DeleteCriticalSection( &xmpopenmpt_mutex ); -} - -static XMPIN * XMPIN_GetInterface_cxx( DWORD face, InterfaceProc faceproc ) { - if ( face != XMPIN_FACE ) return nullptr; - xmpfin=(XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE); - xmpfmisc=(XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE); - xmpfregistry=(XMPFUNC_REGISTRY*)faceproc(XMPFUNC_REGISTRY_FACE); - xmpffile=(XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE); - xmpftext=(XMPFUNC_TEXT*)faceproc(XMPFUNC_TEXT_FACE); - xmpfstatus=(XMPFUNC_STATUS*)faceproc(XMPFUNC_STATUS_FACE); - - // Register keyboard shortcuts - static constexpr std::pair shortcuts[] = { - { openmpt_shortcut_ex | openmpt_shortcut_tempo_decrease, "OpenMPT - Decrease Tempo" }, - { openmpt_shortcut_ex | openmpt_shortcut_tempo_increase, "OpenMPT - Increase Tempo" }, - { openmpt_shortcut_ex | openmpt_shortcut_pitch_decrease, "OpenMPT - Decrease Pitch" }, - { openmpt_shortcut_ex | openmpt_shortcut_pitch_increase, "OpenMPT - Increase Pitch" }, - { openmpt_shortcut_ex | openmpt_shortcut_switch_interpolation, "OpenMPT - Switch Interpolation" }, - }; - XMPSHORTCUT cut; - cut.procex = &ShortcutHandler; - for ( const auto & shortcut : shortcuts ) { - cut.id = shortcut.first; - cut.text = shortcut.second; - xmpfmisc->RegisterShortcut( &cut ); - } - - self->settings.load(); - - return &xmpin; -} - -extern "C" { - -// XMPLAY expects a WINAPI (which is __stdcall) function using an undecorated symbol name. -#if defined(__GNUC__) -XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc ); -XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc ) { - return XMPIN_GetInterface_cxx( face, faceproc ); -} -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattribute-alias" -// clang-format off -__declspec(dllexport) void XMPIN_GetInterface() __attribute__((alias("XMPIN_GetInterface_@8"))); -// clang-format on -#pragma GCC diagnostic pop -#else -XMPIN * WINAPI XMPIN_GetInterface( DWORD face, InterfaceProc faceproc ) { - return XMPIN_GetInterface_cxx( face, faceproc ); -} -#pragma comment(linker, "/EXPORT:XMPIN_GetInterface=_XMPIN_GetInterface@8") -#endif - -} // extern "C" - - -#if defined(MPT_WITH_MFC) && defined(_MFC_VER) - -namespace libopenmpt { -namespace plugin { - -void DllMainAttach() { - xmp_openmpt_on_dll_load(); -} - -void DllMainDetach() { - xmp_openmpt_on_dll_unload(); -} - -} // namespace plugin -} // namespace libopenmpt - -#else - -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ); -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { - static_cast(hinstDLL); - static_cast(lpvReserved); - switch ( fdwReason ) { - case DLL_PROCESS_ATTACH: - xmp_openmpt_on_dll_load(); - break; - case DLL_PROCESS_DETACH: - xmp_openmpt_on_dll_unload(); - break; - } - return TRUE; -} - -#endif - - -#endif // NO_XMPLAY diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp new file mode 100644 index 000000000..ca0aa695c --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.cpp @@ -0,0 +1,1859 @@ +/* + * xmp-openmpt.cpp + * --------------- + * Purpose: libopenmpt xmplay input plugin implementation + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + +#if defined(MPT_WITH_MFC) +#include +#include +#endif // MPT_WITH_MFC +#include +#include + +#include +#include + +#include + +#include "../libopenmpt.hpp" +#include "../libopenmpt_ext.hpp" + +#include "../plugin-common/libopenmpt_plugin_settings.hpp" + +#include "../plugin-common/libopenmpt_plugin_gui.hpp" + +#if __has_include("svn_version.h") +#include "svn_version.h" +#else +#include "../../build/svn_version/svn_version.h" +#endif +#if defined(OPENMPT_VERSION_REVISION) +static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION) ")"; +#else +static const char * xmp_openmpt_string = "OpenMPT (" OPENMPT_API_VERSION_STRING ")"; +#endif + +#define USE_XMPLAY_FILE_IO + +#define USE_XMPLAY_ISTREAM + +#include "xmplay/xmpin.h" + +// Shortcut block assigned to the OpenMPT plugin by un4seen. +enum { + openmpt_shortcut_first = 0x21000, + openmpt_shortcut_tempo_decrease = openmpt_shortcut_first, + openmpt_shortcut_tempo_increase, + openmpt_shortcut_pitch_decrease, + openmpt_shortcut_pitch_increase, + openmpt_shortcut_switch_interpolation, + openmpt_shortcut_last = 0x21fff, + + openmpt_shortcut_ex = 0x80000000, // Use extended version of the shortcut callback +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define SHORT_TITLE "xmp-openmpt" +#define SHORTER_TITLE "openmpt" + +static CRITICAL_SECTION xmpopenmpt_mutex; +class xmpopenmpt_lock { +public: + xmpopenmpt_lock() { + EnterCriticalSection( &xmpopenmpt_mutex ); + } + ~xmpopenmpt_lock() { + LeaveCriticalSection( &xmpopenmpt_mutex ); + } +}; + +static XMPFUNC_IN * xmpfin = nullptr; +static XMPFUNC_MISC * xmpfmisc = nullptr; +static XMPFUNC_REGISTRY * xmpfregistry = nullptr; +static XMPFUNC_FILE * xmpffile = nullptr; +static XMPFUNC_TEXT * xmpftext = nullptr; +static XMPFUNC_STATUS * xmpfstatus = nullptr; + +struct self_xmplay_t; + +static self_xmplay_t * self = 0; + +static void save_options(); + +static void apply_and_save_options(); + + +static std::string convert_to_native( const std::string & str ); + +static std::string StringEncode( const std::wstring &src, UINT codepage ); + +static std::wstring StringDecode( const std::string & src, UINT codepage ); + +#if defined(UNICODE) +static std::wstring StringToWINAPI( const std::wstring & src ); +#else +static std::string StringToWINAPI( const std::wstring & src ); +#endif + +class xmp_openmpt_settings + : public libopenmpt::plugin::settings +{ +protected: + void read_setting( const std::string & key, const std::basic_string & keyW, int & val ) override { + libopenmpt::plugin::settings::read_setting( key, keyW, val ); + int storedVal = 0; + if ( xmpfregistry->GetInt( "OpenMPT", key.c_str(), &storedVal ) ) { + val = storedVal; + } + } + void write_setting( const std::string & key, const std::basic_string & /* keyW */ , int val ) override { + if ( !xmpfregistry->SetInt( "OpenMPT", key.c_str(), &val ) ) { + // error + } + // ok + } +public: + xmp_openmpt_settings() + : libopenmpt::plugin::settings(TEXT(SHORT_TITLE), false) + { + return; + } + virtual ~xmp_openmpt_settings() + { + return; + } +}; + +struct self_xmplay_t { + std::vector subsong_lengths; + std::vector subsong_names; + std::size_t samplerate = 48000; + std::size_t num_channels = 2; + xmp_openmpt_settings settings; + openmpt::module_ext * mod = nullptr; + bool set_format_called = false; + openmpt::ext::pattern_vis * pattern_vis = nullptr; + std::int32_t tempo_factor = 0, pitch_factor = 0; + bool single_subsong_mode = false; + self_xmplay_t() { + settings.changed = apply_and_save_options; + } + void on_new_mod() { + set_format_called = false; + self->pattern_vis = static_cast( self->mod->get_interface( openmpt::ext::pattern_vis_id ) ); + } + void delete_mod() { + if ( mod ) { + pattern_vis = 0; + set_format_called = false; + delete mod; + mod = 0; + } + } + ~self_xmplay_t() { + return; + } +}; + +static std::string convert_to_native( const std::string & str ) { + char * native_string = xmpftext->Utf8( str.c_str(), -1 ); + std::string result = native_string ? native_string : ""; + if ( native_string ) { + xmpfmisc->Free( native_string ); + native_string = 0; + } + return result; +} + +static std::string StringEncode( const std::wstring &src, UINT codepage ) +{ + int required_size = WideCharToMultiByte( codepage, 0, src.c_str(), -1, nullptr, 0, nullptr, nullptr); + if(required_size <= 0) + { + return std::string(); + } + std::vector encoded_string( required_size ); + WideCharToMultiByte( codepage, 0, src.c_str(), -1, encoded_string.data(), encoded_string.size(), nullptr, nullptr); + return encoded_string.data(); +} + +static std::wstring StringDecode( const std::string & src, UINT codepage ) +{ + int required_size = MultiByteToWideChar( codepage, 0, src.c_str(), -1, nullptr, 0 ); + if(required_size <= 0) + { + return std::wstring(); + } + std::vector decoded_string( required_size ); + MultiByteToWideChar( codepage, 0, src.c_str(), -1, decoded_string.data(), decoded_string.size() ); + return decoded_string.data(); +} + +#if defined(UNICODE) + +static std::wstring StringToWINAPI( const std::wstring & src ) +{ + return src; +} + +#else + +static std::string StringToWINAPI( const std::wstring & src ) +{ + return StringEncode( src, CP_ACP ); +} + +#endif + +template +static inline Tstring StringReplace( Tstring str, const Tstring2 & oldStr_, const Tstring3 & newStr_ ) { + std::size_t pos = 0; + const Tstring oldStr = oldStr_; + const Tstring newStr = newStr_; + while ( ( pos = str.find( oldStr, pos ) ) != Tstring::npos ) { + str.replace( pos, oldStr.length(), newStr ); + pos += newStr.length(); + } + return str; +} + +static std::string StringUpperCase( std::string str ) { + std::transform( str.begin(), str.end(), str.begin(), []( char c ) { return static_cast( std::toupper( c ) ); } ); + return str; +} + +static std::string seconds_to_string( double time ) { + std::int64_t time_ms = static_cast( time * 1000 ); + std::int64_t seconds = ( time_ms / 1000 ) % 60; + std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60; + std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) ); + std::ostringstream str; + if ( hours > 0 ) { + str << hours << ":"; + } + str << std::setfill('0') << std::setw(2) << minutes; + str << ":"; + str << std::setfill('0') << std::setw(2) << seconds; + return str.str(); +} + +static void save_settings_to_map( std::map & result, const libopenmpt::plugin::settings & s ) { + result.clear(); + result[ "Samplerate_Hz" ] = s.samplerate; + result[ "Channels" ] = s.channels; + result[ "MasterGain_milliBel" ] = s.mastergain_millibel; + result[ "StereoSeparation_Percent" ] = s.stereoseparation; + result[ "RepeatCount" ] = s.repeatcount; + result[ "InterpolationFilterLength" ] = s.interpolationfilterlength; + result[ "UseAmigaResampler" ] = s.use_amiga_resampler; + result[ "AmigaFilterType" ] = s.amiga_filter_type; + result[ "VolumeRampingStrength" ] = s.ramping; +} + +static inline void load_map_setting( const std::map & map, const std::string & key, int & val ) { + auto it = map.find( key ); + if ( it != map.end() ) { + val = it->second; + } +} + +static void load_settings_from_map( libopenmpt::plugin::settings & s, const std::map & map ) { + load_map_setting( map, "Samplerate_Hz", s.samplerate ); + load_map_setting( map, "Channels", s.channels ); + load_map_setting( map, "MasterGain_milliBel", s.mastergain_millibel ); + load_map_setting( map, "StereoSeparation_Percent", s.stereoseparation ); + load_map_setting( map, "RepeatCount", s.repeatcount ); + load_map_setting( map, "InterpolationFilterLength", s.interpolationfilterlength ); + load_map_setting( map, "UseAmigaResampler", s.use_amiga_resampler ); + load_map_setting( map, "AmigaFilterType", s.amiga_filter_type ); + load_map_setting( map, "VolumeRampingStrength", s.ramping ); +} + +static void load_settings_from_xml( libopenmpt::plugin::settings & s, const std::string & xml ) { + pugi::xml_document doc; + doc.load_string( xml.c_str() ); + pugi::xml_node settings_node = doc.child( "settings" ); + std::map map; + for ( const auto & attr : settings_node.attributes() ) { + map[ attr.name() ] = attr.as_int(); + } + load_settings_from_map( s, map ); +} + +static void save_settings_to_xml( std::string & xml, const libopenmpt::plugin::settings & s ) { + std::map map; + save_settings_to_map( map, s ); + pugi::xml_document doc; + pugi::xml_node settings_node = doc.append_child( "settings" ); + for ( const auto & setting : map ) { + settings_node.append_attribute( setting.first.c_str() ).set_value( setting.second ); + } + std::ostringstream buf; + doc.save( buf ); + xml = buf.str(); +} + +static void apply_options() { + if ( self->mod ) { + if ( !self->set_format_called ) { + // SetFormat will only be called once after loading a file. + // We cannot apply samplerate or numchannels changes afterwards during playback. + self->samplerate = self->settings.samplerate; + self->num_channels = self->settings.channels; + } + self->mod->set_repeat_count( self->settings.repeatcount ); + self->mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, self->settings.mastergain_millibel ); + self->mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, self->settings.stereoseparation ); + self->mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, self->settings.interpolationfilterlength ); + self->mod->set_render_param( openmpt::module::RENDER_VOLUMERAMPING_STRENGTH, self->settings.ramping ); + self->mod->ctl_set_boolean( "render.resampler.emulate_amiga", self->settings.use_amiga_resampler ? true : false ); + switch ( self->settings.amiga_filter_type ) { + case 0: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "auto" ); + break; + case 1: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "unfiltered" ); + break; + case 0xA500: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a500" ); + break; + case 0xA1200: + self->mod->ctl_set_text( "render.resampler.emulate_amiga_type", "a1200" ); + break; + } + } +} + +static void save_options() { + self->settings.save(); +} + +static void apply_and_save_options() { + apply_options(); + save_options(); +} + +static void reset_options() { + self->settings = xmp_openmpt_settings(); + self->settings.changed = apply_and_save_options; + self->settings.load(); +} + +// get config (return size of config data) (OPTIONAL) +static DWORD WINAPI openmpt_GetConfig( void * config ) { + std::string xml; + save_settings_to_xml( xml, self->settings ); + if ( config ) { + std::memcpy( config, xml.c_str(), xml.length() + 1 ); + } + return xml.length() + 1; +} + +// apply config (OPTIONAL) +static void WINAPI openmpt_SetConfig( void * config, DWORD size ) { + reset_options(); + if ( config ) { + load_settings_from_xml( self->settings, std::string( (char*)config, (char*)config + size ) ); + apply_options(); + } +} + +static void WINAPI ShortcutHandler( DWORD id ) { + if ( !self->mod ) { + return; + } + + bool tempo_changed = false, pitch_changed = false; + switch ( id ) { + case openmpt_shortcut_tempo_decrease: self->tempo_factor--; tempo_changed = true; break; + case openmpt_shortcut_tempo_increase: self->tempo_factor++; tempo_changed = true; break; + case openmpt_shortcut_pitch_decrease: self->pitch_factor--; pitch_changed = true; break; + case openmpt_shortcut_pitch_increase: self->pitch_factor++; pitch_changed = true; break; + case openmpt_shortcut_switch_interpolation: + self->settings.interpolationfilterlength *= 2; + if ( self->settings.interpolationfilterlength > 8 ) { + self->settings.interpolationfilterlength = 1; + } + apply_and_save_options(); + const char *s = nullptr; + switch ( self->settings.interpolationfilterlength ) + { + case 1: s = "Interpolation: Off"; break; + case 2: s = "Interpolation: Linear"; break; + case 4: s = "Interpolation: Cubic"; break; + case 8: s = "Interpolation: Polyphase"; break; + } + if ( s ) { + xmpfmisc->ShowBubble( s, 0 ); + } + break; + } + + self->tempo_factor = std::min( 48, std::max( -48, self->tempo_factor ) ); + self->pitch_factor = std::min( 48, std::max( -48, self->pitch_factor ) ); + const double tempo_factor = std::pow( 2.0, self->tempo_factor / 24.0 ); + const double pitch_factor = std::pow( 2.0, self->pitch_factor / 24.0 ); + + if ( tempo_changed ) { + std::ostringstream s; + s << "Tempo: " << static_cast( 100.0 * tempo_factor ) << "%"; + xmpfmisc->ShowBubble( s.str().c_str(), 0 ); + } else if ( pitch_changed) { + std::ostringstream s; + s << "Pitch: "; + if ( self->pitch_factor > 0 ) + s << "+"; + else if ( self->pitch_factor == 0 ) + s << "+/-"; + s << (self->pitch_factor * 0.5) << " semitones"; + xmpfmisc->ShowBubble( s.str().c_str(), 0 ); + } + + openmpt::ext::interactive *interactive = static_cast( self->mod->get_interface( openmpt::ext::interactive_id ) ); + interactive->set_tempo_factor( tempo_factor ); + interactive->set_pitch_factor( pitch_factor ); + xmpfin->SetLength( static_cast( self->mod->get_duration_seconds() / tempo_factor ), TRUE ); +} + + +static double timeinfo_position = 0.0; +struct timeinfo { + bool valid; + double seconds; + std::int32_t pattern; + std::int32_t row; +}; +static std::queue timeinfos; +static void reset_timeinfos( double position = 0.0 ) { + while ( !timeinfos.empty() ) { + timeinfos.pop(); + } + timeinfo_position = position; +} +static void update_timeinfos( std::int32_t samplerate, std::int32_t count ) { + timeinfo_position += (double)count / (double)samplerate; + timeinfo info; + info.valid = true; + info.seconds = timeinfo_position; + info.pattern = self->mod->get_current_pattern(); + info.row = self->mod->get_current_row(); + timeinfos.push( info ); +} + +static timeinfo current_timeinfo; + +static timeinfo lookup_timeinfo( double seconds ) { + timeinfo info = current_timeinfo; +#if 0 + info.seconds = timeinfo_position; + info.pattern = self->mod->get_current_pattern(); + info.row = self->mod->get_current_row(); +#endif + while ( timeinfos.size() > 0 && timeinfos.front().seconds <= seconds ) { + info = timeinfos.front(); + timeinfos.pop(); + } + current_timeinfo = info; + return current_timeinfo; +} + +static void clear_current_timeinfo() { + current_timeinfo = timeinfo(); +} + +static void WINAPI openmpt_About( HWND win ) { + std::ostringstream about; + about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl; + about << " Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors (https://lib.openmpt.org/)" << std::endl; + about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl; + about << std::endl; + about << openmpt::string::get( "contact" ) << std::endl; + about << std::endl; + about << "Show full credits?" << std::endl; + if ( MessageBox( win, StringToWINAPI( StringDecode( about.str(), CP_UTF8 ) ).c_str(), TEXT(SHORT_TITLE), MB_ICONINFORMATION | MB_YESNOCANCEL | MB_DEFBUTTON1 ) != IDYES ) { + return; + } + std::ostringstream credits; + credits << openmpt::string::get( "credits" ); + credits << "Additional thanks to:" << std::endl; + credits << std::endl; + credits << "Arseny Kapoulkine for pugixml" << std::endl; + credits << "https://pugixml.org/" << std::endl; +#if 1 + libopenmpt::plugin::gui_show_file_info( win, TEXT(SHORT_TITLE), StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ) ); +#else + MessageBox( win, StringToWINAPI( StringReplace( StringDecode( credits.str(), CP_UTF8 ), L"\n", L"\r\n" ) ).c_str(), TEXT(SHORT_TITLE), MB_OK ); +#endif +} + +static void WINAPI openmpt_Config( HWND win ) { +#if 1 + libopenmpt::plugin::gui_edit_settings( &self->settings, win, TEXT(SHORT_TITLE) ); +#else + static_cast(win); +#endif + apply_and_save_options(); +} + +#ifdef USE_XMPLAY_FILE_IO + +#ifdef USE_XMPLAY_ISTREAM + +class xmplay_streambuf : public std::streambuf { +public: + explicit xmplay_streambuf( XMPFILE & file ); +private: + int_type underflow() override; + xmplay_streambuf( const xmplay_streambuf & ); + xmplay_streambuf & operator = ( const xmplay_streambuf & ); +private: + XMPFILE & file; + static inline constexpr std::size_t put_back = 4096; + static inline constexpr std::size_t buf_size = 65536; + std::vector buffer; +}; // class xmplay_streambuf + +xmplay_streambuf::xmplay_streambuf( XMPFILE & file_ ) : file(file_), buffer(buf_size) { + char * end = &buffer.front() + buffer.size(); + setg( end, end, end ); +} + +std::streambuf::int_type xmplay_streambuf::underflow() { + if ( gptr() < egptr() ) { + return traits_type::to_int_type( *gptr() ); + } + char * base = &buffer.front(); + char * start = base; + if ( eback() == base ) { + std::size_t put_back_count = std::min( put_back, static_cast( egptr() - base ) ); + std::memmove( base, egptr() - put_back_count, put_back_count ); + start += put_back_count; + } + std::size_t n = xmpffile->Read( file, start, buffer.size() - ( start - base ) ); + if ( n == 0 ) { + return traits_type::eof(); + } + setg( base, start, start + n ); + return traits_type::to_int_type( *gptr() ); +} + +class xmplay_istream : public std::istream { +private: + xmplay_streambuf buf; +private: + xmplay_istream( const xmplay_istream & ); + xmplay_istream & operator = ( const xmplay_istream & ); +public: + xmplay_istream( XMPFILE & file ) : std::istream(&buf), buf(file) { + return; + } + ~xmplay_istream() { + return; + } +}; // class xmplay_istream + +// Stream for memory-based files (required for could_open_probability) +struct xmplay_membuf : std::streambuf { + xmplay_membuf( const char * base, size_t size ) { + char* p( const_cast( base ) ); + setg(p, p, p + size); + } +}; + +struct xmplay_imemstream : virtual xmplay_membuf, std::istream { + xmplay_imemstream( const char * base, size_t size ) + : xmplay_membuf( base, size ) + , std::istream( static_cast(this)) { + return; + } +}; + +#else // !USE_XMPLAY_ISTREAM + +static std::vector read_XMPFILE_vector( XMPFILE & file ) { + std::vector data( xmpffile->GetSize( file ) ); + if ( data.size() != xmpffile->Read( file, data.data(), data.size() ) ) { + return std::vector(); + } + return data; +} + +static std::string read_XMPFILE_string( XMPFILE & file ) { + std::vector data = read_XMPFILE_vector( file ); + return std::string( data.begin(), data.end() ); +} + +#endif // USE_XMPLAY_ISTREAM + +#endif // USE_XMPLAY_FILE_IO + +static std::string string_replace( std::string str, const std::string & oldStr, const std::string & newStr ) { + std::size_t pos = 0; + while((pos = str.find(oldStr, pos)) != std::string::npos) + { + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } + return str; +} + +static void write_xmplay_string( char * dst, std::string src ) { + // xmplay buffers are ~40kB, be conservative and truncate at 32kB-2 + if ( !dst ) { + return; + } + src = src.substr( 0, (1<<15) - 2 ); + std::strcpy( dst, src.c_str() ); +} + +static std::string extract_date( const openmpt::module & mod ) { + std::string result = mod.get_metadata("date"); + if ( result.empty() ) { + // Search the sample, instrument and message texts for possible release years. + // We'll look for things that may vaguely resemble a release year, such as 4-digit numbers + // or 2-digit numbers with a leading apostrophe. Generally, only years between + // 1988 (release of Ultimate SoundTracker) and the current year + 1 (safety margin) will + // be considered. + std::string s = " " + mod.get_metadata("message"); + auto names = mod.get_sample_names(); + for ( const auto & name : names ) { + s += " " + name; + } + names = mod.get_instrument_names(); + for ( const auto & name : names ) { + s += " " + name; + } + s += " "; + + int32_t best_year = 0; + + SYSTEMTIME time; + GetSystemTime( &time ); + const int32_t current_year = time.wYear + 1; + +#define MPT_NUMERIC( x ) ( ( x >= '0' ) && ( x <= '9' ) ) + for ( auto i = s.cbegin(); i != s.cend(); ++i ) { + std::size_t len = s.length(); + std::size_t idx = i - s.begin(); + std::size_t remaining = len - idx; + if ( ( remaining >= 6 ) && !MPT_NUMERIC( i[0] ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && MPT_NUMERIC( i[3] ) && MPT_NUMERIC( i[4] ) && !MPT_NUMERIC( i[5] ) ) { + // Four-digit year + const int32_t year = ( i[1] - '0' ) * 1000 + ( i[2] - '0' ) * 100 + ( i[3] - '0' ) * 10 + ( i[4] - '0' ); + if ( year >= 1988 && year <= current_year ) { + best_year = std::max( year, best_year ); + } + } else if ( ( remaining >= 4 ) && ( i[0] == '\'' ) && MPT_NUMERIC( i[1] ) && MPT_NUMERIC( i[2] ) && !MPT_NUMERIC( i[3] ) ) { + // Apostrophe + two-digit year + const int32_t year = ( i[1] - '0' ) * 10 + ( i[2] - '0' ); + if ( year >= 88 && year <= 99 ) { + best_year = std::max( 1900 + year, best_year ); + } else if ( year >= 00 && ( 2000 + year ) <= current_year ) { + best_year = std::max( 2000 + year, best_year ); + } + } + } +#undef MPT_NUMERIC + + if ( best_year != 0 ) { + std::ostringstream os; + os << best_year; + result = os.str(); + } + } + + return result; +} + +static void append_xmplay_tag( std::string & tags, const std::string & tag, const std::string & val ) { + if ( tag.empty() ) { + return; + } + if ( val.empty() ) { + return; + } + tags.append( tag ); + tags.append( 1, '\0' ); + tags.append( val ); + tags.append( 1, '\0' ); +} + +static char * build_xmplay_tags( const openmpt::module & mod, int32_t subsong = -1 ) { + std::string tags; + const std::string title = mod.get_metadata("title"); + + const auto subsong_names = mod.get_subsong_names(); + auto first_subsong = subsong_names.cbegin(), last_subsong = subsong_names.cend(); + if ( subsong >= 0 && static_cast( subsong ) < subsong_names.size() ) { + first_subsong += subsong; + last_subsong = first_subsong + 1; + } else + { + last_subsong = first_subsong + 1; + } + + for ( auto subsong_name = first_subsong; subsong_name != last_subsong; subsong_name++ ) { + append_xmplay_tag( tags, "filetype", convert_to_native( StringUpperCase( mod.get_metadata( "type" ) ) ) ); + append_xmplay_tag( tags, "title", convert_to_native( ( subsong_name->empty() || subsong == -1 ) ? title : *subsong_name ) ); + append_xmplay_tag( tags, "artist", convert_to_native( mod.get_metadata( "artist" ) ) ); + append_xmplay_tag( tags, "album", convert_to_native( mod.get_metadata( "xmplay-album" ) ) ); // todo, libopenmpt does not support that + append_xmplay_tag( tags, "date", convert_to_native( extract_date( mod ) ) ); + append_xmplay_tag( tags, "track", convert_to_native( mod.get_metadata( "xmplay-tracknumber" ) ) ); // todo, libopenmpt does not support that + append_xmplay_tag( tags, "genre", convert_to_native( mod.get_metadata( "xmplay-genre" ) ) ); // todo, libopenmpt does not support that + append_xmplay_tag( tags, "comment", convert_to_native( mod.get_metadata( "message" ) ) ); + tags.append( 1, '\0' ); + } + char * result = static_cast( xmpfmisc->Alloc( tags.size() ) ); + if ( !result ) { + return nullptr; + } + std::copy( tags.data(), tags.data() + tags.size(), result ); + return result; +} + +static float * build_xmplay_length( const openmpt::module & /* mod */ ) { + float * result = static_cast( xmpfmisc->Alloc( sizeof( float ) * self->subsong_lengths.size() ) ); + if ( !result ) { + return nullptr; + } + for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { + result[i] = static_cast( self->subsong_lengths[i] ); + } + return result; +} + +static void clear_xmplay_string( char * str ) { + if ( !str ) { + return; + } + str[0] = '\0'; +} + +static std::string sanitize_xmplay_info_string( const std::string & str ) { + std::string result; + result.reserve(str.size()); + for ( auto c : str ) { + switch ( c ) { + case '\0': + case '\t': + case '\r': + case '\n': + break; + default: + result.push_back( c ); + break; + } + } + return result; +} + +static std::string sanitize_xmplay_multiline_info_string( const std::string & str ) { + std::string result; + result.reserve(str.size()); + for ( auto c : str ) { + switch ( c ) { + case '\0': + case '\t': + case '\r': + break; + case '\n': + result.push_back( '\r' ); + result.push_back( '\t' ); + break; + default: + result.push_back( c ); + break; + } + } + return result; +} + +static std::string sanitize_xmplay_multiline_string( const std::string & str ) { + std::string result; + result.reserve(str.size()); + for ( auto c : str ) { + switch ( c ) { + case '\0': + case '\t': + break; + default: + result.push_back( c ); + break; + } + } + return result; +} + +// check if a file is playable by this plugin +// more thorough checks can be saved for the GetFileInfo and Open functions +static BOOL WINAPI openmpt_CheckFile( const char * filename, XMPFILE file ) { + static_cast( filename ); + try { + #ifdef USE_XMPLAY_FILE_IO + #ifdef USE_XMPLAY_ISTREAM + switch ( xmpffile->GetType( file ) ) { + case XMPFILE_TYPE_MEMORY: + { + xmplay_imemstream s( reinterpret_cast( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) ); + return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; + } + break; + case XMPFILE_TYPE_FILE: + case XMPFILE_TYPE_NETFILE: + case XMPFILE_TYPE_NETSTREAM: + default: + { + xmplay_istream s( file ); + return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; + } + break; + } + #else + if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { + std::string data( reinterpret_cast( xmpffile->GetMemory( file ) ), xmpffile->GetSize( file ) ); + std::istringstream s( data ); + return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; + } else { + std::string data = read_XMPFILE_string( file ); + std::istringstream s(data); + return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; + } + #endif + #else + std::ifstream s( filename, std::ios_base::binary ); + return ( openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, s ) == openmpt::probe_file_header_result_success ) ? TRUE : FALSE; + #endif + } catch ( ... ) { + return FALSE; + } + return FALSE; +} + +static DWORD WINAPI openmpt_GetFileInfo( const char * filename, XMPFILE file, float * * length, char * * tags ) { + static_cast( filename ); + try { + std::map< std::string, std::string > ctls + { + { "load.skip_plugins", "1" }, + { "load.skip_samples", "1" }, + }; + #ifdef USE_XMPLAY_FILE_IO + #ifdef USE_XMPLAY_ISTREAM + switch ( xmpffile->GetType( file ) ) { + case XMPFILE_TYPE_MEMORY: + { + openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); + if ( length ) { + *length = build_xmplay_length( mod ); + } + if ( tags ) { + *tags = build_xmplay_tags( mod ); + } + } + break; + case XMPFILE_TYPE_FILE: + case XMPFILE_TYPE_NETFILE: + case XMPFILE_TYPE_NETSTREAM: + default: + { + xmplay_istream s( file ); + openmpt::module mod( s, std::clog, ctls ); + if ( length ) { + *length = build_xmplay_length( mod ); + } + if ( tags ) { + *tags = build_xmplay_tags( mod ); + } + } + break; + } + #else + if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { + openmpt::module mod( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); + if ( length ) { + *length = build_xmplay_length( mod ); + } + if ( tags ) { + *tags = build_xmplay_tags( mod ); + } + } else { + openmpt::module mod( read_XMPFILE_vector( file ), std::clog, ctls ); + if ( length ) { + *length = build_xmplay_length( mod ); + } + if ( tags ) { + *tags = build_xmplay_tags( mod ); + } + } + #endif + #else + std::ifstream s( filename, std::ios_base::binary ); + openmpt::module mod( s, std::clog, ctls ); + if ( length ) { + *length = build_xmplay_length( mod ); + } + if ( tags ) { + *tags = build_xmplay_tags( mod ); + } + #endif + } catch ( ... ) { + if ( length ) *length = nullptr; + if ( tags ) *tags = nullptr; + return 0; + } + return self->subsong_lengths.size() + XMPIN_INFO_NOSUBTAGS; +} + +// open a file for playback +// return: 0=failed, 1=success, 2=success and XMPlay can close the file +static DWORD WINAPI openmpt_Open( const char * filename, XMPFILE file ) { + static_cast( filename ); + xmpopenmpt_lock guard; + reset_options(); + try { + std::map< std::string, std::string > ctls + { + { "play.at_end", "continue" }, + }; + self->delete_mod(); + #ifdef USE_XMPLAY_FILE_IO + #ifdef USE_XMPLAY_ISTREAM + switch ( xmpffile->GetType( file ) ) { + case XMPFILE_TYPE_MEMORY: + self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); + break; + case XMPFILE_TYPE_FILE: + case XMPFILE_TYPE_NETFILE: + case XMPFILE_TYPE_NETSTREAM: + default: + { + xmplay_istream s( file ); + self->mod = new openmpt::module_ext( s, std::clog, ctls ); + } + break; + } + #else + if ( xmpffile->GetType( file ) == XMPFILE_TYPE_MEMORY ) { + self->mod = new openmpt::module_ext( xmpffile->GetMemory( file ), xmpffile->GetSize( file ), std::clog, ctls ); + } else { + self->mod = new openmpt::module_ext( read_XMPFILE_vector( file ), std::clog, ctls ); + } + #endif + #else + self->mod = new openmpt::module_ext( std::ifstream( filename, std::ios_base::binary ), std::clog, ctls ); + #endif + self->on_new_mod(); + clear_current_timeinfo(); + reset_timeinfos(); + apply_options(); + + std::int32_t num_subsongs = self->mod->get_num_subsongs(); + self->subsong_lengths.resize( num_subsongs ); + for ( std::int32_t i = 0; i < num_subsongs; ++i ) { + self->mod->select_subsong( i ); + self->subsong_lengths[i] = self->mod->get_duration_seconds(); + } + self->subsong_names = self->mod->get_subsong_names(); + self->mod->select_subsong( 0 ); + self->tempo_factor = 0; + self->pitch_factor = 0; + + xmpfin->SetLength( static_cast( self->subsong_lengths[0] ), TRUE ); + return 2; + } catch ( ... ) { + self->delete_mod(); + return 0; + } + return 0; +} + +// close the file +static void WINAPI openmpt_Close() { + xmpopenmpt_lock guard; + self->delete_mod(); +} + +// set the sample format (in=user chosen format, out=file format if different) +static void WINAPI openmpt_SetFormat( XMPFORMAT * form ) { + if ( !form ) { + return; + } + // SetFormat will only be called once after loading a file. + // We cannot apply samplerate or numchannels changes afterwards during playback. + self->set_format_called = true; + if ( !self->mod ) { + form->rate = 0; + form->chan = 0; + form->res = 0; + return; + } + if ( self->settings.samplerate != 0 ) { + form->rate = self->samplerate; + } else { + if ( form->rate > 0 ) { + self->samplerate = form->rate; + } else { + form->rate = 48000; + self->samplerate = 48000; + } + } + if ( self->settings.channels != 0 ) { + form->chan = self->num_channels; + } else { + if ( form->chan > 0 ) { + if ( form->chan > 2 ) { + form->chan = 4; + self->num_channels = 4; + } else { + self->num_channels = form->chan; + } + } else { + form->chan = 2; + self->num_channels = 2; + } + } + form->res = 4; // float +} + +// get the tags +static char * WINAPI openmpt_GetTags() { + if ( !self->mod ) { + char * tags = static_cast( xmpfmisc->Alloc( 1 ) ); + tags[0] = '\0'; + return tags; + } + return build_xmplay_tags( *self->mod, std::max( 0, self->mod->get_selected_subsong() ) ); +} + +// get the main panel info text +static void WINAPI openmpt_GetInfoText( char * format, char * length ) { + if ( !self->mod ) { + clear_xmplay_string( format ); + clear_xmplay_string( length ); + return; + } + if ( format ) { + std::ostringstream str; + str + << StringUpperCase( self->mod->get_metadata("type") ) + << " - " + << self->mod->get_num_channels() << " ch" + << " - " + << "(via " << SHORTER_TITLE << ")" + ; + write_xmplay_string( format, sanitize_xmplay_info_string( str.str() ) ); + } + if ( length ) { + std::ostringstream str; + str + << length + << " - " + << self->mod->get_num_orders() << " orders" + ; + write_xmplay_string( length, sanitize_xmplay_info_string( str.str() ) ); + } +} + +// get text for "General" info window +// separate headings and values with a tab (\t), end each line with a carriage-return (\r) +static void WINAPI openmpt_GetGeneralInfo( char * buf ) { + if ( !self->mod ) { + clear_xmplay_string( buf ); + return; + } + std::ostringstream str; + str << "\r"; + bool metadatainfo = false; + if ( !self->mod->get_metadata("artist").empty() ) { + metadatainfo = true; + str << "Artist" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("artist") ) << "\r"; + } + const std::string date = extract_date( *self->mod ); + if ( !date.empty() ) { + metadatainfo = true; + str << "Date" << "\t" << sanitize_xmplay_info_string( date ) << "\r"; + } + if ( metadatainfo ) { + str << "\r"; + } + str << "Format" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("type") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("type_long") ) << ")" << "\r"; + if ( !self->mod->get_metadata("originaltype").empty() ) { + str << "Original Type" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("originaltype_long") ) << ")" << "\r"; + } + if ( !self->mod->get_metadata("container").empty() ) { + str << "Container" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("container") ) << " (" << sanitize_xmplay_info_string( self->mod->get_metadata("container_long") ) << ")" << "\r"; + } + str + << "Channels" << "\t" << self->mod->get_num_channels() << "\r" + << "Orders" << "\t" << self->mod->get_num_orders() << "\r" + << "Patterns" << "\t" << self->mod->get_num_patterns() << "\r"; + if ( self->mod->get_num_instruments() != 0 ) { + str << "Instruments" << "\t" << self->mod->get_num_instruments() << "\r"; + } + str << "Samples" << "\t" << self->mod->get_num_samples() << "\r"; + + if( !self->single_subsong_mode && self->subsong_lengths.size() > 1 ) { + for ( std::size_t i = 0; i < self->subsong_lengths.size(); ++i ) { + str << ( i == 0 ? "Subsongs\t" : "\t" ) << (i + 1) << ". " << seconds_to_string( self->subsong_lengths[i] ) << " " << self->subsong_names[i] << "\r"; + } + } + + str + << "\r" + << "Tracker" << "\t" << sanitize_xmplay_info_string( self->mod->get_metadata("tracker") ) << "\r" + << "Player" << "\t" << "xmp-openmpt" << " version " << openmpt::string::get( "library_version" ) << "\r" + ; + std::string warnings = self->mod->get_metadata("warnings"); + if ( !warnings.empty() ) { + str << "Warnings" << "\t" << sanitize_xmplay_multiline_info_string( warnings ) << "\r"; + } + str << "\r"; + write_xmplay_string( buf, str.str() ); +} + +// get text for "Message" info window +// separate tag names and values with a tab (\t), and end each line with a carriage-return (\r) +static void WINAPI openmpt_GetMessage( char * buf ) { + if ( !self->mod ) { + clear_xmplay_string( buf ); + return; + } + write_xmplay_string( buf, convert_to_native( sanitize_xmplay_multiline_string( string_replace( self->mod->get_metadata("message"), "\n", "\r" ) ) ) ); +} + +// Seek to a position (in granularity units) +// return the new position in seconds (-1 = failed) +static double WINAPI openmpt_SetPosition( DWORD pos ) { + if ( !self->mod ) { + return -1.0; + } + if ( pos == static_cast(static_cast(XMPIN_POS_LOOP)) ) { + // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on. + // There is currently no way to easily figure out at which time the loop restarts. + return -2; + } else if ( pos == static_cast(static_cast(XMPIN_POS_AUTOLOOP)) ) { + // In the auto-looping case, the function should only loop when a loop has been detected, and otherwise return -1 + // If the time of the loop start position is known, that should be returned, otherwise -2 can be returned to let the time run on. + // There is currently no way to easily figure out at which time the loop restarts. + return -2; + } + if ( pos & XMPIN_POS_SUBSONG ) { + self->single_subsong_mode = ( pos & XMPIN_POS_SUBSONG1 ) != 0; + const int32_t subsong = pos & 0xffff; + try { + self->mod->select_subsong( subsong ); + } catch ( ... ) { + return 0.0; + } + openmpt::ext::interactive *interactive = static_cast( self->mod->get_interface( openmpt::ext::interactive_id ) ); + xmpfin->SetLength( static_cast( self->subsong_lengths[ subsong ] / interactive->get_tempo_factor() ), TRUE ); + xmpfin->UpdateTitle( nullptr ); + reset_timeinfos( 0 ); + return 0.0; + } + double new_position = self->mod->set_position_seconds( static_cast( pos ) * 0.001 ); + reset_timeinfos( new_position ); + return new_position; +} + +// Get the seeking granularity in seconds +static double WINAPI openmpt_GetGranularity() { + return 0.001; +} + +// get some sample data, always floating-point +// count=number of floats to write (not bytes or samples) +// return number of floats written. if it's less than requested, playback is ended... +// so wait for more if there is more to come (use CheckCancel function to check if user wants to cancel) +static DWORD WINAPI openmpt_Process( float * dstbuf, DWORD count ) { + xmpopenmpt_lock guard; + if ( !self->mod || self->num_channels == 0 ) { + return 0; + } + update_timeinfos( self->samplerate, 0 ); + std::size_t frames = count / self->num_channels; + std::size_t frames_to_render = frames; + std::size_t frames_rendered = 0; + while ( frames_to_render > 0 ) { + std::size_t frames_chunk = std::min( frames_to_render, static_cast( ( self->samplerate + 99 ) / 100 ) ); // 100 Hz timing info update interval + switch ( self->num_channels ) { + case 1: + { + frames_chunk = self->mod->read( self->samplerate, frames_chunk, dstbuf ); + } + break; + case 2: + { + frames_chunk = self->mod->read_interleaved_stereo( self->samplerate, frames_chunk, dstbuf ); + } + break; + case 4: + { + frames_chunk = self->mod->read_interleaved_quad( self->samplerate, frames_chunk, dstbuf ); + } + break; + } + dstbuf += frames_chunk * self->num_channels; + if ( frames_chunk == 0 ) { + break; + } + update_timeinfos( self->samplerate, frames_chunk ); + frames_to_render -= frames_chunk; + frames_rendered += frames_chunk; + } + if ( frames_rendered == 0 ) { + return 0; + } + return frames_rendered * self->num_channels; +} + +static void add_names( std::ostream & str, const std::string & title, const std::vector & names, int display_offset ) { + if ( names.size() > 0 ) { + bool valid = false; + for ( std::size_t i = 0; i < names.size(); i++ ) { + if ( names[i] != "" ) { + valid = true; + } + } + if ( !valid ) { + return; + } + str << title << " Names:" << "\r"; + for ( std::size_t i = 0; i < names.size(); i++ ) { + str << std::setfill('0') << std::setw(2) << (display_offset + i) << std::setw(0) << "\t" << convert_to_native( names[i] ) << "\r"; + } + str << "\r"; + } +} + +static void WINAPI openmpt_GetSamples( char * buf ) { + if ( !self->mod ) { + clear_xmplay_string( buf ); + return; + } + std::ostringstream str; + add_names( str, "Instrument", self->mod->get_instrument_names(), 1 ); + add_names( str, "Sample", self->mod->get_sample_names(), 1 ); + add_names( str, "Channel", self->mod->get_channel_names(), 1 ); + add_names( str, "Order", self->mod->get_order_names(), 0 ); + add_names( str, "Pattern", self->mod->get_pattern_names(), 0 ); + write_xmplay_string( buf, str.str() ); +} + +static DWORD WINAPI openmpt_GetSubSongs( float * length ) { + double tmp = 0.0; + for ( auto sub_length : self->subsong_lengths ) { + tmp += sub_length; + } + *length = static_cast( tmp ); + return static_cast( self->subsong_lengths.size() ); +} + +enum ColorIndex +{ + col_background = 0, + col_unknown, + col_text, + col_empty, + col_instr, + col_vol, + col_pitch, + col_global, + + col_max +}; + +static ColorIndex effect_type_to_color_index( openmpt::ext::pattern_vis::effect_type effect_type ) { + switch ( effect_type ) { + case openmpt::ext::pattern_vis::effect_unknown: return col_unknown; break; + case openmpt::ext::pattern_vis::effect_general: return col_text ; break; + case openmpt::ext::pattern_vis::effect_global : return col_global ; break; + case openmpt::ext::pattern_vis::effect_volume : return col_vol ; break; + case openmpt::ext::pattern_vis::effect_panning: return col_instr ; break; + case openmpt::ext::pattern_vis::effect_pitch : return col_pitch ; break; + default: return col_unknown; break; + } +} + +const struct Columns +{ + int num_chars; + int color; +} pattern_columns[] = { + { 3, col_text }, // C-5 + { 2, col_instr }, // 01 + { 3, col_vol }, // v64 + { 3, col_pitch }, // EFF +}; + +static const int max_cols = 4; + +static void assure_width( std::string & str, std::size_t width ) { + if ( str.length() == width ) { + return; + } else if ( str.length() < width ) { + str += std::string( width - str.length(), ' ' ); + } else if ( str.length() > width ) { + str = str.substr( 0, width ); + } +} + +struct ColorRGBA +{ + uint8_t r, g, b, a; +}; + +union Color +{ + ColorRGBA rgba; + COLORREF dw; +}; + +static_assert(sizeof(Color) == 4); + +HDC visDC; +HGDIOBJ visbitmap; + +Color viscolors[col_max]; +HPEN vispens[col_max]; +HBRUSH visbrushs[col_max]; +HFONT visfont; +static int last_pattern = -1; + +static Color invert_color( Color c ) { + Color res; + res.rgba.a = c.rgba.a; + res.rgba.r = 255 - c.rgba.r; + res.rgba.g = 255 - c.rgba.g; + res.rgba.b = 255 - c.rgba.b; + return res; +} + +static BOOL WINAPI VisOpen(DWORD colors[3]) { + xmpopenmpt_lock guard; + visDC = 0; + visbitmap = 0; + visfont = 0; + + viscolors[col_background].dw = colors[0]; + viscolors[col_unknown].dw = colors[1]; + viscolors[col_text].dw = colors[2]; + + viscolors[col_global] = invert_color( viscolors[col_background] ); + + const int r = viscolors[col_text].rgba.r, g = viscolors[col_text].rgba.g, b = viscolors[col_text].rgba.b; + viscolors[col_empty].rgba.r = static_cast( (r + viscolors[col_background].rgba.r) / 2 ); + viscolors[col_empty].rgba.g = static_cast( (g + viscolors[col_background].rgba.g) / 2 ); + viscolors[col_empty].rgba.b = static_cast( (b + viscolors[col_background].rgba.b) / 2 ); + viscolors[col_empty].rgba.a = 0; + +#define MIXCOLOR(col, c1, c2, c3) { \ + viscolors[col] = viscolors[col_text]; \ + int mix = viscolors[col].rgba.c1 + 0xA0; \ + viscolors[col].rgba.c1 = static_cast( mix ); \ + if ( mix > 0xFF ) { \ + viscolors[col].rgba.c2 = std::max( static_cast( c2 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \ + viscolors[col].rgba.c3 = std::max( static_cast( c3 - viscolors[col].rgba.c1 / 2 ), std::uint8_t(0) ); \ + viscolors[col].rgba.c1 = 0xFF; \ + } } + + MIXCOLOR(col_instr, g, r, b); + MIXCOLOR(col_vol, b, r, g); + MIXCOLOR(col_pitch, r, g, b); +#undef MIXCOLOR + + for( int i = 0; i < col_max; ++i ) { + vispens[i] = CreatePen( PS_SOLID, 1, viscolors[i].dw ); + visbrushs[i] = CreateSolidBrush( viscolors[i].dw ); + } + + clear_current_timeinfo(); + + if ( !self->mod ) { + return FALSE; + } + return TRUE; +} +static void WINAPI VisClose() { + xmpopenmpt_lock guard; + + for( int i = 0; i < col_max; ++i ) { + DeletePen( vispens[i] ); + DeleteBrush( visbrushs[i] ); + } + + DeleteFont( visfont ); + DeleteBitmap( visbitmap ); + if ( visDC ) { + DeleteDC( visDC ); + } +} +static void WINAPI VisSize( HDC /* dc */ , SIZE * /* size */ ) { + xmpopenmpt_lock guard; + last_pattern = -1; // Force redraw +} + +#if 0 +static BOOL WINAPI VisRender( DWORD * /* buf */ , SIZE /* size */ , DWORD /* flags */ ) { + xmpopenmpt_lock guard; + return FALSE; +} +#endif + +static int get_pattern_width( int chars_per_channel, int spaces_per_channel, int num_cols, int text_size, int channels ) +{ + int pattern_width = ((chars_per_channel * channels + 4) * text_size) + (spaces_per_channel * channels + channels - (num_cols == 1 ? 1 : 2)) * (text_size / 2); + return pattern_width; +} + +static BOOL WINAPI VisRenderDC( HDC dc, SIZE size, DWORD flags ) { + xmpopenmpt_lock guard; + RECT rect; + + if ( !visfont ) { + // Force usage of a nice monospace font + LOGFONT logfont; + GetObject ( GetCurrentObject( dc, OBJ_FONT ), sizeof(logfont), &logfont ); + _tcscpy( logfont.lfFaceName, TEXT("Lucida Console") ); + visfont = CreateFontIndirect( &logfont ); + } + SIZE text_size; + SelectFont( dc, visfont ); + if ( GetTextExtentPoint32( dc, TEXT("W"), 1, &text_size ) == FALSE ) { + return FALSE; + } + + if ( flags & XMPIN_VIS_INIT ) { + last_pattern = -1; + } + + timeinfo info = lookup_timeinfo( xmpfstatus->GetTime() ); + + if ( !info.valid ) { + RECT bgrect; + bgrect.top = 0; + bgrect.left = 0; + bgrect.right = size.cx; + bgrect.bottom = size.cy; + FillRect(dc, &bgrect, visbrushs[col_background]); + return TRUE; + } + + int pattern = info.pattern; + int current_row = info.row; + + const std::size_t channels = self->mod->get_num_channels(); + const std::size_t rows = self->mod->get_pattern_num_rows( pattern ); + + const std::size_t num_half_chars = std::max( static_cast( 2 * size.cx / text_size.cx ), std::size_t(8) ) - 8; + //const std::size_t num_rows = size.cy / text_size.cy; + + // Spaces between pattern components are half width, full space at channel end + const std::size_t half_chars_per_channel = num_half_chars / channels; + std::size_t chars_per_channel, spaces_per_channel; + std::size_t num_cols; + std::size_t col0_width = pattern_columns[0].num_chars; + for ( num_cols = sizeof ( pattern_columns ) / sizeof ( pattern_columns[0] ); num_cols >= 1; num_cols-- ) { + chars_per_channel = 0; + spaces_per_channel = num_cols > 1 ? num_cols : 0; // No extra space if we only display notes + for ( std::size_t i = 0; i < num_cols; i++ ) { + chars_per_channel += pattern_columns[i].num_chars; + } + + if ( half_chars_per_channel >= chars_per_channel * 2 + spaces_per_channel + 1 || num_cols == 1 ) { + break; + } + } + + if ( !self->settings.vis_allow_scroll ) { + if ( num_cols == 1 ) { + spaces_per_channel = 0; + while ( get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels ) > size.cx && chars_per_channel > 1 ) { + chars_per_channel -= 1; + } + col0_width = chars_per_channel; + chars_per_channel = col0_width; + } + } + + int pattern_width = get_pattern_width( chars_per_channel, spaces_per_channel, num_cols, text_size.cx, channels ); + int pattern_height = rows * text_size.cy; + + if ( !visDC || last_pattern != pattern ) { + DeleteBitmap( visbitmap ); + if ( visDC ) { + DeleteDC( visDC ); + } + + visDC = CreateCompatibleDC( dc ); + visbitmap = CreateCompatibleBitmap( dc, pattern_width, pattern_height ); + SelectBitmap( visDC, visbitmap ); + + SelectBrush( visDC, vispens[col_unknown] ); + SelectBrush( visDC, visbrushs[col_background] ); + + SelectFont( visDC, visfont ); + + rect.top = 0; + rect.left = 0; + rect.right = pattern_width; + rect.bottom = pattern_height; + FillRect( visDC, &rect, visbrushs[col_background] ); + + SetBkColor( visDC, viscolors[col_background].dw ); + + POINT pos; + pos.y = 0; + + for ( std::size_t row = 0; row < rows; row++ ) { + pos.x = 0; + + std::ostringstream s; + s.imbue(std::locale::classic()); + s << std::setfill('0') << std::setw(3) << row; + const std::string rowstr = s.str(); + + SetTextColor( visDC, viscolors[1].dw ); + TextOutA( visDC, pos.x, pos.y, rowstr.c_str(), rowstr.length() ); + pos.x += 4 * text_size.cx; + + for ( std::size_t channel = 0; channel < channels; ++channel ) { + + struct coldata { + std::string text; + bool is_empty; + ColorIndex color; + coldata() + : is_empty(false) + , color(col_unknown) + { + return; + } + }; + + coldata cols[max_cols]; + + for ( std::size_t col = 0; col < max_cols; ++col ) { + switch ( col ) { + case 0: + cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_note ); + break; + case 1: + cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_instrument ); + break; + case 2: + cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volumeffect ) + + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_volume ); + break; + case 3: + cols[col].text = self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_effect ) + + self->mod->format_pattern_row_channel_command( pattern, row, channel, openmpt::module::command_parameter ); + break; + } + int color = pattern_columns[col].color; + if ( self->pattern_vis && ( col == 2 || col == 3 ) ) { + if ( col == 2 ) { + color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_volume_effect_type( pattern, row, channel ) ); + } + if ( col == 3 ) { + color = effect_type_to_color_index( self->pattern_vis->get_pattern_row_channel_effect_type( pattern, row, channel ) ); + } + } + switch ( cols[col].text[0] ) { + case ' ': + [[fallthrough]]; + case '.': + cols[col].is_empty = true; + [[fallthrough]]; + case '^': + [[fallthrough]]; + case '=': + [[fallthrough]]; + case '~': + color = col_empty; + break; + } + cols[col].color = (ColorIndex)color; + + } + + if ( num_cols <= 3 && !cols[3].is_empty ) { + if ( cols[2].is_empty ) { + cols[2] = cols[3]; + } else if ( cols[0].is_empty ) { + cols[0] = cols[3]; + } + } + + if ( num_cols <= 2 && !cols[2].is_empty ) { + if ( cols[0].is_empty ) { + cols[0] = cols[2]; + } + } + + for ( std::size_t col = 0; col < num_cols; ++col ) { + + std::size_t col_width = ( num_cols > 1 ) ? pattern_columns[col].num_chars : col0_width; + + assure_width( cols[col].text, col_width ); + + SetTextColor( visDC, viscolors[cols[col].color].dw ); + TextOutA( visDC, pos.x, pos.y, cols[col].text.c_str(), cols[col].text.length() ); + pos.x += col_width * text_size.cx + text_size.cx / 2; + } + // Extra padding + if ( num_cols > 1 ) { + pos.x += text_size.cx / 2; + } + } + + pos.y += text_size.cy; + } + } + + rect.top = 0; + rect.left = 0; + rect.right = size.cx; + rect.bottom = size.cy; + FillRect( dc, &rect, visbrushs[col_background] ); + + int offset_x = (size.cx - pattern_width) / 2; + int offset_y = (size.cy - text_size.cy) / 2 - current_row * text_size.cy; + int src_offset_x = 0; + int src_offset_y = 0; + + if ( offset_x < 0 ) { + src_offset_x -= offset_x; + pattern_width = std::min( static_cast( pattern_width + offset_x ), static_cast( size.cx ) ); + offset_x = 0; + } + + if ( offset_y < 0 ) { + src_offset_y -= offset_y; + pattern_height = std::min( static_cast( pattern_height + offset_y ), static_cast( size.cy ) ); + offset_y = 0; + } + + BitBlt( dc, offset_x, offset_y, pattern_width, pattern_height, visDC, src_offset_x, src_offset_y , SRCCOPY ); + + // Highlight current row + rect.left = offset_x; + rect.top = (size.cy - text_size.cy) / 2; + rect.right = rect.left + pattern_width; + rect.bottom = rect.top + text_size.cy; + InvertRect( dc, &rect ); + + last_pattern = pattern; + + return TRUE; +} + +#if 0 +static void WINAPI VisButton( DWORD /* x */ , DWORD /* y */ ) { + //xmpopenmpt_lock guard; +} +#endif + +static XMPIN xmpin = { +#ifdef USE_XMPLAY_FILE_IO + 0 | +#else + XMPIN_FLAG_NOXMPFILE | +#endif + XMPIN_FLAG_CONFIG | XMPIN_FLAG_LOOP, + xmp_openmpt_string, + nullptr, // "libopenmpt\0mptm/mptmz", + openmpt_About, + openmpt_Config, + openmpt_CheckFile, + openmpt_GetFileInfo, + openmpt_Open, + openmpt_Close, + nullptr, // reserved + openmpt_SetFormat, + openmpt_GetTags, + openmpt_GetInfoText, + openmpt_GetGeneralInfo, + openmpt_GetMessage, + openmpt_SetPosition, + openmpt_GetGranularity, + nullptr, // GetBuffering + openmpt_Process, + nullptr, // WriteFile + openmpt_GetSamples, + openmpt_GetSubSongs, // GetSubSongs + nullptr, // GetCues + nullptr, // GetDownloaded + + "OpenMPT Pattern Display", + VisOpen, + VisClose, + VisSize, + /*VisRender,*/nullptr, + VisRenderDC, + /*VisButton,*/nullptr, + + nullptr, // reserved2 + openmpt_GetConfig, + openmpt_SetConfig +}; + +static const char * xmp_openmpt_default_exts = "OpenMPT\0mptm/mptmz"; + +static char * file_formats; + +static void xmp_openmpt_on_dll_load() { + ZeroMemory( &xmpopenmpt_mutex, sizeof( xmpopenmpt_mutex ) ); + #if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable:28125) // The function 'InitializeCriticalSection' must be called from within a try/except block: The requirement might be conditional. + #endif // _MSC_VER + InitializeCriticalSection( &xmpopenmpt_mutex ); + #if defined(_MSC_VER) + #pragma warning(pop) + #endif // _MSC_VER + std::vector extensions = openmpt::get_supported_extensions(); + std::string filetypes_string = "OpenMPT"; + filetypes_string.push_back('\0'); + bool first = true; + for ( const auto & ext : extensions ) { + if ( first ) { + first = false; + } else { + filetypes_string.push_back('/'); + } + filetypes_string += ext; + } + filetypes_string.push_back('\0'); + file_formats = (char*)HeapAlloc( GetProcessHeap(), 0, filetypes_string.size() ); + if ( file_formats ) { + std::copy( filetypes_string.begin(), filetypes_string.end(), file_formats ); + xmpin.exts = file_formats; + } else { + xmpin.exts = xmp_openmpt_default_exts; + } + self = new self_xmplay_t(); +} + +static void xmp_openmpt_on_dll_unload() { + delete self; + self = nullptr; + if ( xmpin.exts != xmp_openmpt_default_exts ) { + HeapFree(GetProcessHeap(), 0, (LPVOID)const_cast(xmpin.exts)); + } + xmpin.exts = nullptr; + DeleteCriticalSection( &xmpopenmpt_mutex ); +} + +static XMPIN * XMPIN_GetInterface_cxx( DWORD face, InterfaceProc faceproc ) { + if ( face != XMPIN_FACE ) return nullptr; + xmpfin=(XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE); + xmpfmisc=(XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE); + xmpfregistry=(XMPFUNC_REGISTRY*)faceproc(XMPFUNC_REGISTRY_FACE); + xmpffile=(XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE); + xmpftext=(XMPFUNC_TEXT*)faceproc(XMPFUNC_TEXT_FACE); + xmpfstatus=(XMPFUNC_STATUS*)faceproc(XMPFUNC_STATUS_FACE); + + // Register keyboard shortcuts + static constexpr std::pair shortcuts[] = { + { openmpt_shortcut_ex | openmpt_shortcut_tempo_decrease, "OpenMPT - Decrease Tempo" }, + { openmpt_shortcut_ex | openmpt_shortcut_tempo_increase, "OpenMPT - Increase Tempo" }, + { openmpt_shortcut_ex | openmpt_shortcut_pitch_decrease, "OpenMPT - Decrease Pitch" }, + { openmpt_shortcut_ex | openmpt_shortcut_pitch_increase, "OpenMPT - Increase Pitch" }, + { openmpt_shortcut_ex | openmpt_shortcut_switch_interpolation, "OpenMPT - Switch Interpolation" }, + }; + XMPSHORTCUT cut; + cut.procex = &ShortcutHandler; + for ( const auto & shortcut : shortcuts ) { + cut.id = shortcut.first; + cut.text = shortcut.second; + xmpfmisc->RegisterShortcut( &cut ); + } + + self->settings.load(); + + return &xmpin; +} + +extern "C" { + +// XMPLAY expects a WINAPI (which is __stdcall) function using an undecorated symbol name. +#if defined(__GNUC__) +XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc ); +XMPIN * WINAPI XMPIN_GetInterface_( DWORD face, InterfaceProc faceproc ) { + return XMPIN_GetInterface_cxx( face, faceproc ); +} +#if (__GNUC__ >= 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattribute-alias" +#endif +// clang-format off +__declspec(dllexport) void XMPIN_GetInterface() __attribute__((alias("XMPIN_GetInterface_@8"))); +// clang-format on +#if (__GNUC__ >= 8) +#pragma GCC diagnostic pop +#endif +#else +XMPIN * WINAPI XMPIN_GetInterface( DWORD face, InterfaceProc faceproc ) { + return XMPIN_GetInterface_cxx( face, faceproc ); +} +#pragma comment(linker, "/EXPORT:XMPIN_GetInterface=_XMPIN_GetInterface@8") +#endif + +} // extern "C" + + +#if defined(MPT_WITH_MFC) && defined(_MFC_VER) + +namespace libopenmpt { +namespace plugin { + +void DllMainAttach() { + xmp_openmpt_on_dll_load(); +} + +void DllMainDetach() { + xmp_openmpt_on_dll_unload(); +} + +} // namespace plugin +} // namespace libopenmpt + +#else + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ); +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { + static_cast(hinstDLL); + static_cast(lpvReserved); + switch ( fdwReason ) { + case DLL_PROCESS_ATTACH: + xmp_openmpt_on_dll_load(); + break; + case DLL_PROCESS_DETACH: + xmp_openmpt_on_dll_unload(); + break; + } + return TRUE; +} + +#endif diff --git a/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.txt b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.txt new file mode 100644 index 000000000..6720bee2d --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/libopenmpt/xmp-openmpt/xmp-openmpt.txt @@ -0,0 +1,16 @@ + +xmp-openmpt +=========== + +xmp-openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input +plugin for XMPlay >= 3.8.0.0. xmp-openmpt is based on libopenmpt. + + +Installation +------------ + +"xmp-openmpt.dll" and "openmpt-mpg123.dll" must both be placed into the XMPlay +plugins directory. + + +See https://lib.openmpt.org/ for documentation, FAQ and other details. diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp index 7abae4798..a217fe985 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.cpp @@ -37,16 +37,23 @@ static const char * const license = #include "openmpt123_config.hpp" +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + +#include "mpt/base/check_platform.hpp" +#include "mpt/base/detect.hpp" + #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -62,8 +69,9 @@ static const char * const license = #include #include -#if defined(__DJGPP__) +#if MPT_OS_DJGPP #include +#include #include #include #include @@ -71,7 +79,7 @@ static const char * const license = #include #include #include -#elif defined(WIN32) +#elif MPT_OS_WINDOWS #include #include #include @@ -134,7 +142,9 @@ struct show_version_number_exception : public std::exception { struct show_long_version_number_exception : public std::exception { }; -#if defined( WIN32 ) +constexpr auto libopenmpt_encoding = mpt::common_encoding::utf8; + +#if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) bool IsConsole( DWORD stdHandle ) { HANDLE hStd = GetStdHandle( stdHandle ); if ( ( hStd != NULL ) && ( hStd != INVALID_HANDLE_VALUE ) ) { @@ -145,10 +155,10 @@ bool IsConsole( DWORD stdHandle ) { } return false; } -#endif +#endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) bool IsTerminal( int fd ) { -#if defined( WIN32 ) +#if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) if ( !_isatty( fd ) ) { return false; } @@ -166,7 +176,7 @@ bool IsTerminal( int fd ) { #endif } -#if !defined( WIN32 ) +#if !MPT_OS_WINDOWS static termios saved_attributes; @@ -194,25 +204,25 @@ class file_audio_stream_raii : public file_audio_stream_base { private: std::unique_ptr impl; public: - file_audio_stream_raii( const commandlineflags & flags, const std::string & filename, std::ostream & log ) + file_audio_stream_raii( const commandlineflags & flags, const mpt::native_path & filename, concat_stream & log ) : impl(nullptr) { if ( !flags.force_overwrite ) { - std::ifstream testfile( filename, std::ios::binary ); + mpt::IO::ifstream testfile( filename, std::ios::binary ); if ( testfile ) { - throw exception( "file already exists" ); + throw exception( MPT_USTRING("file already exists") ); } } if ( false ) { // nothing - } else if ( flags.output_extension == "raw" ) { + } else if ( flags.output_extension == MPT_NATIVE_PATH("raw") ) { impl = std::make_unique( filename, flags, log ); -#ifdef MPT_WITH_MMIO - } else if ( flags.output_extension == "wav" ) { +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT + } else if ( flags.output_extension == MPT_NATIVE_PATH("wav") ) { impl = std::make_unique( filename, flags, log ); #endif #ifdef MPT_WITH_FLAC - } else if ( flags.output_extension == "flac" ) { + } else if ( flags.output_extension == MPT_NATIVE_PATH("flac") ) { impl = std::make_unique( filename, flags, log ); #endif #ifdef MPT_WITH_SNDFILE @@ -221,16 +231,16 @@ public: #endif } if ( !impl ) { - throw exception( "file format handler '" + flags.output_extension + "' not found" ); + throw exception( MPT_USTRING("file format handler '") + mpt::transcode( flags.output_extension ) + MPT_USTRING("' not found") ); } } virtual ~file_audio_stream_raii() { return; } - void write_metadata( std::map metadata ) override { + void write_metadata( std::map metadata ) override { impl->write_metadata( metadata ); } - void write_updated_metadata( std::map metadata ) override { + void write_updated_metadata( std::map metadata ) override { impl->write_updated_metadata( metadata ); } void write( const std::vector buffers, std::size_t frames ) override { @@ -241,13 +251,13 @@ public: } }; -static std::string ctls_to_string( const std::map & ctls ) { - std::string result; +static mpt::ustring ctls_to_string( const std::map & ctls ) { + mpt::ustring result; for ( const auto & ctl : ctls ) { if ( !result.empty() ) { - result += "; "; + result += MPT_USTRING("; "); } - result += ctl.first + "=" + ctl.second; + result += mpt::transcode( libopenmpt_encoding, ctl.first ) + MPT_USTRING("=") + mpt::transcode( libopenmpt_encoding, ctl.second ); } return result; } @@ -260,177 +270,82 @@ static double pitch_flag_to_double( std::int32_t pitch ) { return std::pow( 2.0, pitch / 24.0 ); } -static double my_round( double val ) { - if ( val >= 0.0 ) { - return std::floor( val + 0.5 ); - } else { - return std::ceil( val - 0.5 ); - } -} - static std::int32_t double_to_tempo_flag( double factor ) { - return static_cast( my_round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); + return static_cast( mpt::round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); } static std::int32_t double_to_pitch_flag( double factor ) { - return static_cast( my_round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); + return static_cast( mpt::round( std::log( factor ) / std::log( 2.0 ) * 24.0 ) ); } -static std::ostream & operator << ( std::ostream & s, const commandlineflags & flags ) { - s << "Quiet: " << flags.quiet << std::endl; - s << "Verbose: " << flags.verbose << std::endl; - s << "Mode : " << mode_to_string( flags.mode ) << std::endl; - s << "Show progress: " << flags.show_progress << std::endl; - s << "Show peak meters: " << flags.show_meters << std::endl; - s << "Show channel peak meters: " << flags.show_channel_meters << std::endl; - s << "Show details: " << flags.show_details << std::endl; - s << "Show message: " << flags.show_message << std::endl; - s << "Update: " << flags.ui_redraw_interval << "ms" << std::endl; - s << "Device: " << flags.device << std::endl; - s << "Buffer: " << flags.buffer << "ms" << std::endl; - s << "Period: " << flags.period << "ms" << std::endl; - s << "Samplerate: " << flags.samplerate << std::endl; - s << "Channels: " << flags.channels << std::endl; - s << "Float: " << flags.use_float << std::endl; - s << "Gain: " << flags.gain / 100.0 << std::endl; - s << "Stereo separation: " << flags.separation << std::endl; - s << "Interpolation filter taps: " << flags.filtertaps << std::endl; - s << "Volume ramping strength: " << flags.ramping << std::endl; - s << "Tempo: " << tempo_flag_to_double( flags.tempo ) << std::endl; - s << "Pitch: " << pitch_flag_to_double( flags.pitch ) << std::endl; - s << "Output dithering: " << flags.dither << std::endl; - s << "Repeat count: " << flags.repeatcount << std::endl; - s << "Seek target: " << flags.seek_target << std::endl; - s << "End time: " << flags.end_time << std::endl; - s << "Standard output: " << flags.use_stdout << std::endl; - s << "Output filename: " << flags.output_filename << std::endl; - s << "Force overwrite output file: " << flags.force_overwrite << std::endl; - s << "Ctls: " << ctls_to_string( flags.ctls ) << std::endl; - s << std::endl; - s << "Files: " << std::endl; +static concat_stream & operator << ( concat_stream & s, const commandlineflags & flags ) { + s << MPT_USTRING("Quiet: ") << flags.quiet << lf; + s << MPT_USTRING("Banner: ") << flags.banner << lf; + s << MPT_USTRING("Verbose: ") << flags.verbose << lf; + s << MPT_USTRING("Mode : ") << mode_to_string( flags.mode ) << lf; + s << MPT_USTRING("Show progress: ") << flags.show_progress << lf; + s << MPT_USTRING("Show peak meters: ") << flags.show_meters << lf; + s << MPT_USTRING("Show channel peak meters: ") << flags.show_channel_meters << lf; + s << MPT_USTRING("Show details: ") << flags.show_details << lf; + s << MPT_USTRING("Show message: ") << flags.show_message << lf; + s << MPT_USTRING("Update: ") << flags.ui_redraw_interval << MPT_USTRING("ms") << lf; + s << MPT_USTRING("Device: ") << flags.device << lf; + s << MPT_USTRING("Buffer: ") << flags.buffer << MPT_USTRING("ms") << lf; + s << MPT_USTRING("Period: ") << flags.period << MPT_USTRING("ms") << lf; + s << MPT_USTRING("Samplerate: ") << flags.samplerate << lf; + s << MPT_USTRING("Channels: ") << flags.channels << lf; + s << MPT_USTRING("Float: ") << flags.use_float << lf; + s << MPT_USTRING("Gain: ") << flags.gain / 100.0 << lf; + s << MPT_USTRING("Stereo separation: ") << flags.separation << lf; + s << MPT_USTRING("Interpolation filter taps: ") << flags.filtertaps << lf; + s << MPT_USTRING("Volume ramping strength: ") << flags.ramping << lf; + s << MPT_USTRING("Tempo: ") << tempo_flag_to_double( flags.tempo ) << lf; + s << MPT_USTRING("Pitch: ") << pitch_flag_to_double( flags.pitch ) << lf; + s << MPT_USTRING("Output dithering: ") << flags.dither << lf; + s << MPT_USTRING("Repeat count: ") << flags.repeatcount << lf; + s << MPT_USTRING("Seek target: ") << flags.seek_target << lf; + s << MPT_USTRING("End time: ") << flags.end_time << lf; + s << MPT_USTRING("Standard output: ") << flags.use_stdout << lf; + s << MPT_USTRING("Output filename: ") << mpt::transcode( flags.output_filename ) << lf; + s << MPT_USTRING("Force overwrite output file: ") << flags.force_overwrite << lf; + s << MPT_USTRING("Ctls: ") << ctls_to_string( flags.ctls ) << lf; + s << lf; + s << MPT_USTRING("Files: ") << lf; for ( const auto & filename : flags.filenames ) { - s << " " << filename << std::endl; + s << MPT_USTRING(" ") << mpt::transcode( filename ) << lf; } - s << std::endl; + s << lf; return s; } -static std::string replace( std::string str, const std::string & oldstr, const std::string & newstr ) { - std::size_t pos = 0; - while ( ( pos = str.find( oldstr, pos ) ) != std::string::npos ) { - str.replace( pos, oldstr.length(), newstr ); - pos += newstr.length(); - } - return str; -} - -static bool begins_with( const std::string & str, const std::string & match ) { - return ( str.find( match ) == 0 ); -} - -static bool ends_with( const std::string & str, const std::string & match ) { - return ( str.rfind( match ) == ( str.length() - match.length() ) ); -} - -static std::string trim_left(std::string str, const std::string &whitespace = std::string()) { - std::string::size_type pos = str.find_first_not_of(whitespace); - if(pos != std::string::npos) { - str.erase(str.begin(), str.begin() + pos); - } else if(pos == std::string::npos && str.length() > 0 && str.find_last_of(whitespace) == str.length() - 1) { - return std::string(); - } - return str; -} - -static std::string trim_right(std::string str, const std::string &whitespace = std::string()) { - std::string::size_type pos = str.find_last_not_of(whitespace); - if(pos != std::string::npos) { - str.erase(str.begin() + pos + 1, str.end()); - } else if(pos == std::string::npos && str.length() > 0 && str.find_first_of(whitespace) == 0) { - return std::string(); - } - return str; -} - -static std::string trim(std::string str, const std::string &whitespace = std::string()) { - return trim_right(trim_left(str, whitespace), whitespace); -} - static std::string trim_eol( const std::string & str ) { - return trim( str, "\r\n" ); + return mpt::trim( str, std::string("\r\n") ); } -static std::string default_path_separator() { -#if defined(WIN32) - return "\\"; -#else - return "/"; -#endif +static mpt::native_path get_basepath( mpt::native_path filename ) { + return (filename.GetPrefix() + filename.GetDirectoryWithDrive()).WithTrailingSlash(); } -static std::string path_separators() { -#if defined(WIN32) - return "\\/"; -#else - return "/"; -#endif +static bool is_absolute( mpt::native_path filename ) { + return filename.IsAbsolute(); } -static bool is_path_separator( char c ) { -#if defined(WIN32) - return ( c == '\\' ) || ( c == '/' ); -#else - return c == '/'; -#endif +static mpt::native_path get_filename( const mpt::native_path & filepath ) { + return filepath.GetFilename(); } -static std::string get_basepath( std::string filename ) { - std::string::size_type pos = filename.find_last_of( path_separators() ); - if ( pos == std::string::npos ) { - return std::string(); - } - return filename.substr( 0, pos ) + default_path_separator(); -} - -static bool is_absolute( std::string filename ) { -#if defined(WIN32) - if ( begins_with( filename, "\\\\?\\UNC\\" ) ) { - return true; - } - if ( begins_with( filename, "\\\\?\\" ) ) { - return true; - } - if ( begins_with( filename, "\\\\" ) ) { - return true; // UNC - } - if ( begins_with( filename, "//" ) ) { - return true; // UNC - } - return ( filename.length() ) >= 3 && ( filename[1] == ':' ) && is_path_separator( filename[2] ); -#else - return ( filename.length() >= 1 ) && is_path_separator( filename[0] ); -#endif -} - -static std::string get_filename( const std::string & filepath ) { - if ( filepath.find_last_of( path_separators() ) == std::string::npos ) { - return filepath; - } - return filepath.substr( filepath.find_last_of( path_separators() ) + 1 ); -} - -static std::string prepend_lines( std::string str, const std::string & prefix ) { +static mpt::ustring prepend_lines( mpt::ustring str, const mpt::ustring & prefix ) { if ( str.empty() ) { return str; } - if ( str.substr( str.length() - 1, 1 ) == std::string("\n") ) { + if ( str.substr( str.length() - 1, 1 ) == MPT_USTRING("\n") ) { str = str.substr( 0, str.length() - 1 ); } - return replace( str, std::string("\n"), std::string("\n") + prefix ); + return mpt::replace( str, MPT_USTRING("\n"), MPT_USTRING("\n") + prefix ); } -static std::string bytes_to_string( std::uint64_t bytes ) { - static const char * const suffixes[] = { "B", "kB", "MB", "GB", "TB", "PB" }; +static mpt::ustring bytes_to_string( std::uint64_t bytes ) { + static const mpt::uchar * const suffixes[] = { MPT_ULITERAL("B"), MPT_ULITERAL("kB"), MPT_ULITERAL("MB"), MPT_ULITERAL("GB"), MPT_ULITERAL("TB"), MPT_ULITERAL("PB") }; int offset = 0; while ( bytes > 9999 ) { bytes /= 1000; @@ -439,54 +354,59 @@ static std::string bytes_to_string( std::uint64_t bytes ) { break; } } - std::ostringstream result; - result << bytes << suffixes[offset]; - return result.str(); + return mpt::format::val( bytes ) + suffixes[offset]; } -static std::string seconds_to_string( double time ) { +static mpt::ustring seconds_to_string( double time ) { std::int64_t time_ms = static_cast( time * 1000 ); std::int64_t milliseconds = time_ms % 1000; std::int64_t seconds = ( time_ms / 1000 ) % 60; std::int64_t minutes = ( time_ms / ( 1000 * 60 ) ) % 60; std::int64_t hours = ( time_ms / ( 1000 * 60 * 60 ) ); - std::ostringstream str; + mpt::ustring str; if ( hours > 0 ) { - str << hours << ":"; + str += mpt::format::val( hours ) + MPT_USTRING(":"); } - str << std::setfill('0') << std::setw(2) << minutes; - str << ":"; - str << std::setfill('0') << std::setw(2) << seconds; - str << "."; - str << std::setfill('0') << std::setw(3) << milliseconds; - return str.str(); + str += mpt::format::dec0<2>( minutes ); + str += MPT_USTRING(":"); + str += mpt::format::dec0<2>( seconds ); + str += MPT_USTRING("."); + str += mpt::format::dec0<3>( milliseconds ); + return str; } -static void show_info( std::ostream & log, bool verbose ) { - log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << ", libopenmpt " << openmpt::string::get( "library_version" ) << " (" << "OpenMPT " << openmpt::string::get( "core_version" ) << ")" << std::endl; - log << "Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors " << std::endl; - if ( !verbose ) { - log << std::endl; +static void show_banner( concat_stream & log, verbosity banner ) { + if ( banner == verbosity_hidden ) { return; } - log << " libopenmpt source..: " << openmpt::string::get( "source_url" ) << std::endl; - log << " libopenmpt date....: " << openmpt::string::get( "source_date" ) << std::endl; - log << " libopenmpt srcinfo.: "; + if ( banner == verbosity_shortversion ) { + log << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(" / ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" / ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << lf; + return; + } + log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << MPT_USTRING(", libopenmpt ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_version" ) ) << MPT_USTRING(" (") << MPT_USTRING("OpenMPT ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "core_version" ) ) << MPT_USTRING(")") << lf; + log << MPT_USTRING("Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors ") << lf; + if ( banner == verbosity_normal ) { + log << lf; + return; + } + log << MPT_USTRING(" libopenmpt source..: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_url" ) ) << lf; + log << MPT_USTRING(" libopenmpt date....: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_date" ) ) << lf; + log << MPT_USTRING(" libopenmpt srcinfo.: "); { - std::vector fields; + std::vector fields; if ( openmpt::string::get( "source_is_package" ) == "1" ) { - fields.push_back( "package" ); + fields.push_back( MPT_USTRING("package") ); } if ( openmpt::string::get( "source_is_release" ) == "1" ) { - fields.push_back( "release" ); + fields.push_back( MPT_USTRING("release") ); } if ( ( !openmpt::string::get( "source_revision" ).empty() ) && ( openmpt::string::get( "source_revision" ) != "0" ) ) { - std::string field = "rev" + openmpt::string::get( "source_revision" ); + mpt::ustring field = MPT_USTRING("rev") + mpt::transcode( libopenmpt_encoding, openmpt::string::get( "source_revision" ) ); if ( openmpt::string::get( "source_has_mixed_revisions" ) == "1" ) { - field += "+mixed"; + field += MPT_USTRING("+mixed"); } if ( openmpt::string::get( "source_is_modified" ) == "1" ) { - field += "+modified"; + field += MPT_USTRING("+modified"); } fields.push_back( field ); } @@ -495,235 +415,232 @@ static void show_info( std::ostream & log, bool verbose ) { if ( first ) { first = false; } else { - log << ", "; + log << MPT_USTRING(", "); } log << field; } } - log << std::endl; - log << " libopenmpt compiler: " << openmpt::string::get( "build_compiler" ) << std::endl; - log << " libopenmpt features: " << openmpt::string::get( "library_features" ) << std::endl; + log << lf; + log << MPT_USTRING(" libopenmpt compiler: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "build_compiler" ) ) << lf; + log << MPT_USTRING(" libopenmpt features: ") << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "library_features" ) ) << lf; #ifdef MPT_WITH_SDL2 - log << " libSDL2 "; + log << MPT_USTRING(" libSDL2 "); SDL_version sdlver; std::memset( &sdlver, 0, sizeof( SDL_version ) ); SDL_GetVersion( &sdlver ); - log << static_cast( sdlver.major ) << "." << static_cast( sdlver.minor ) << "." << static_cast( sdlver.patch ); + log << static_cast( sdlver.major ) << MPT_USTRING(".") << static_cast( sdlver.minor ) << MPT_USTRING(".") << static_cast( sdlver.patch ); const char * revision = SDL_GetRevision(); if ( revision ) { - log << " (" << revision << ")"; + log << MPT_USTRING(" (") << mpt::transcode( sdl2_encoding, revision ) << MPT_USTRING(")"); } - log << ", "; + log << MPT_USTRING(", "); std::memset( &sdlver, 0, sizeof( SDL_version ) ); SDL_VERSION( &sdlver ); - log << "API: " << static_cast( sdlver.major ) << "." << static_cast( sdlver.minor ) << "." << static_cast( sdlver.patch ) << ""; - log << " " << std::endl; + log << MPT_USTRING("API: ") << static_cast( sdlver.major ) << MPT_USTRING(".") << static_cast( sdlver.minor ) << MPT_USTRING(".") << static_cast( sdlver.patch ); + log << MPT_USTRING(" ") << lf; #endif #ifdef MPT_WITH_PULSEAUDIO - log << " " << "libpulse, libpulse-simple" << " (headers " << pa_get_headers_version() << ", API " << PA_API_VERSION << ", PROTOCOL " << PA_PROTOCOL_VERSION << ", library " << ( pa_get_library_version() ? pa_get_library_version() : "unknown" ) << ") " << std::endl; + log << MPT_USTRING(" ") << MPT_USTRING("libpulse, libpulse-simple") << MPT_USTRING(" (headers ") << mpt::transcode( pulseaudio_encoding, pa_get_headers_version() ) << MPT_USTRING(", API ") << PA_API_VERSION << MPT_USTRING(", PROTOCOL ") << PA_PROTOCOL_VERSION << MPT_USTRING(", library ") << mpt::transcode( pulseaudio_encoding, ( pa_get_library_version() ? pa_get_library_version() : "unknown" ) ) << MPT_USTRING(") ") << lf; #endif #ifdef MPT_WITH_PORTAUDIO - log << " " << Pa_GetVersionText() << " (" << Pa_GetVersion() << ") " << std::endl; + log << MPT_USTRING(" ") << mpt::transcode( portaudio_encoding, Pa_GetVersionText() ) << MPT_USTRING(" (") << Pa_GetVersion() << MPT_USTRING(") ") << lf; #endif #ifdef MPT_WITH_FLAC - log << " FLAC " << FLAC__VERSION_STRING << ", " << FLAC__VENDOR_STRING << ", API " << FLAC_API_VERSION_CURRENT << "." << FLAC_API_VERSION_REVISION << "." << FLAC_API_VERSION_AGE << " " << std::endl; + log << MPT_USTRING(" FLAC ") << mpt::transcode( mpt::source_encoding, FLAC__VERSION_STRING ) << MPT_USTRING(", ") << mpt::transcode( mpt::source_encoding, FLAC__VENDOR_STRING ) << MPT_USTRING(", API ") << FLAC_API_VERSION_CURRENT << MPT_USTRING(".") << FLAC_API_VERSION_REVISION << MPT_USTRING(".") << FLAC_API_VERSION_AGE << MPT_USTRING(" ") << lf; #endif #ifdef MPT_WITH_SNDFILE char sndfile_info[128]; std::memset( sndfile_info, 0, sizeof( sndfile_info ) ); sf_command( 0, SFC_GET_LIB_VERSION, sndfile_info, sizeof( sndfile_info ) ); sndfile_info[127] = '\0'; - log << " libsndfile " << sndfile_info << " " << std::endl; + log << MPT_USTRING(" libsndfile ") << mpt::transcode( sndfile_encoding, sndfile_info ) << MPT_USTRING(" ") << lf; #endif - log << std::endl; + log << lf; } static void show_man_version( textout & log ) { - log << "openmpt123" << " v" << OPENMPT123_VERSION_STRING << std::endl; - log << std::endl; - log << "Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors " << std::endl; + log << MPT_USTRING("openmpt123") << MPT_USTRING(" v") << mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) << lf; + log << lf; + log << MPT_USTRING("Copyright (c) 2013-2023 OpenMPT Project Developers and Contributors ") << lf; } static void show_short_version( textout & log ) { - log << OPENMPT123_VERSION_STRING << " / " << openmpt::string::get( "library_version" ) << " / " << openmpt::string::get( "core_version" ) << std::endl; + show_banner( log, verbosity_shortversion ); log.writeout(); } static void show_version( textout & log ) { - show_info( log, false ); + show_banner( log, verbosity_normal ); log.writeout(); } static void show_long_version( textout & log ) { - show_info( log, true ); + show_banner( log, verbosity_verbose ); log.writeout(); } -static void show_credits( textout & log ) { - show_info( log, false ); - log << openmpt::string::get( "contact" ) << std::endl; - log << std::endl; - log << openmpt::string::get( "credits" ) << std::endl; +static void show_credits( textout & log, verbosity banner ) { + show_banner( log, banner ); + log << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "contact" ) ) << lf; + log << lf; + log << mpt::transcode( libopenmpt_encoding, openmpt::string::get( "credits" ) ) << lf; log.writeout(); } -static void show_license( textout & log ) { - show_info( log, false ); - log << license << std::endl; +static void show_license( textout & log, verbosity banner ) { + show_banner( log, banner ); + log << mpt::transcode( mpt::source_encoding, license ) << lf; log.writeout(); } -static std::string get_driver_string( const std::string & driver ) { +static mpt::ustring get_driver_string( const mpt::ustring & driver ) { if ( driver.empty() ) { - return "default"; + return MPT_USTRING("default"); } return driver; } -static std::string get_device_string( const std::string & device ) { +static mpt::ustring get_device_string( const mpt::ustring & device ) { if ( device.empty() ) { - return "default"; + return MPT_USTRING("default"); } return device; } static void show_help_keyboard( textout & log, bool man_version = false ) { - if ( !man_version ) { - show_info( log, false ); - } - log << "Keyboard hotkeys (use 'openmpt123 --ui'):" << std::endl; - log << std::endl; - log << " [q] quit" << std::endl; - log << " [ ] pause / unpause" << std::endl; - log << " [N] skip 10 files backward" << std::endl; - log << " [n] prev file" << std::endl; - log << " [m] next file" << std::endl; - log << " [M] skip 10 files forward" << std::endl; - log << " [h] seek 10 seconds backward" << std::endl; - log << " [j] seek 1 seconds backward" << std::endl; - log << " [k] seek 1 seconds forward" << std::endl; - log << " [l] seek 10 seconds forward" << std::endl; - log << " [u]|[i] +/- tempo" << std::endl; - log << " [o]|[p] +/- pitch" << std::endl; - log << " [3]|[4] +/- gain" << std::endl; - log << " [5]|[6] +/- stereo separation" << std::endl; - log << " [7]|[8] +/- filter taps" << std::endl; - log << " [9]|[0] +/- volume ramping" << std::endl; - log << std::endl; + log << MPT_USTRING("Keyboard hotkeys (use 'openmpt123 --ui'):") << lf; + log << lf; + log << MPT_USTRING(" [q] quit") << lf; + log << MPT_USTRING(" [ ] pause / unpause") << lf; + log << MPT_USTRING(" [N] skip 10 files backward") << lf; + log << MPT_USTRING(" [n] prev file") << lf; + log << MPT_USTRING(" [m] next file") << lf; + log << MPT_USTRING(" [M] skip 10 files forward") << lf; + log << MPT_USTRING(" [h] seek 10 seconds backward") << lf; + log << MPT_USTRING(" [j] seek 1 seconds backward") << lf; + log << MPT_USTRING(" [k] seek 1 seconds forward") << lf; + log << MPT_USTRING(" [l] seek 10 seconds forward") << lf; + log << MPT_USTRING(" [u]|[i] +/- tempo") << lf; + log << MPT_USTRING(" [o]|[p] +/- pitch") << lf; + log << MPT_USTRING(" [3]|[4] +/- gain") << lf; + log << MPT_USTRING(" [5]|[6] +/- stereo separation") << lf; + log << MPT_USTRING(" [7]|[8] +/- filter taps") << lf; + log << MPT_USTRING(" [9]|[0] +/- volume ramping") << lf; + log << lf; if ( !man_version ) { log.writeout(); } } -static void show_help( textout & log, bool with_info = true, bool longhelp = false, bool man_version = false, const std::string & message = std::string() ) { - if ( with_info ) { - show_info( log, false ); - } +static void show_help( textout & log, bool longhelp = false, bool man_version = false, const mpt::ustring & message = mpt::ustring() ) { { - log << "Usage: openmpt123 [options] [--] file1 [file2] ..." << std::endl; - log << std::endl; + log << MPT_USTRING("Usage: openmpt123 [options] [--] file1 [file2] ...") << lf; + log << lf; if ( man_version ) { - log << "openmpt123 plays module music files." << std::endl; - log << std::endl; + log << MPT_USTRING("openmpt123 plays module music files.") << lf; + log << lf; } if ( man_version ) { - log << "Options:" << std::endl; - log << std::endl; + log << MPT_USTRING("Options:") << lf; + log << lf; } - log << " -h, --help Show help" << std::endl; - log << " --help-keyboard Show keyboard hotkeys in ui mode" << std::endl; - log << " -q, --quiet Suppress non-error screen output" << std::endl; - log << " -v, --verbose Show more screen output" << std::endl; - log << " --version Show version information and exit" << std::endl; - log << " --short-version Show version number and nothing else" << std::endl; - log << " --long-version Show long version information and exit" << std::endl; - log << " --credits Show elaborate contributors list" << std::endl; - log << " --license Show license" << std::endl; - log << std::endl; - log << " --probe Probe each file whether it is a supported file format" << std::endl; - log << " --info Display information about each file" << std::endl; - log << " --ui Interactively play each file" << std::endl; - log << " --batch Play each file" << std::endl; - log << " --render Render each file to individual PCM data files" << std::endl; + log << MPT_USTRING(" -h, --help Show help") << lf; + log << MPT_USTRING(" --help-keyboard Show keyboard hotkeys in ui mode") << lf; + log << MPT_USTRING(" -q, --quiet Suppress non-error screen output") << lf; + log << MPT_USTRING(" -v, --verbose Show more screen output") << lf; + log << MPT_USTRING(" --version Show version information and exit") << lf; + log << MPT_USTRING(" --short-version Show version number and nothing else") << lf; + log << MPT_USTRING(" --long-version Show long version information and exit") << lf; + log << MPT_USTRING(" --credits Show elaborate contributors list") << lf; + log << MPT_USTRING(" --license Show license") << lf; + log << lf; + log << MPT_USTRING(" --probe Probe each file whether it is a supported file format") << lf; + log << MPT_USTRING(" --info Display information about each file") << lf; + log << MPT_USTRING(" --ui Interactively play each file") << lf; + log << MPT_USTRING(" --batch Play each file") << lf; + log << MPT_USTRING(" --render Render each file to individual PCM data files") << lf; if ( !longhelp ) { - log << std::endl; + log << lf; log.writeout(); return; } - log << std::endl; - log << " --terminal-width n Assume terminal is n characters wide [default: " << commandlineflags().terminal_width << "]" << std::endl; - log << " --terminal-height n Assume terminal is n characters high [default: " << commandlineflags().terminal_height << "]" << std::endl; - log << std::endl; - log << " --[no-]progress Show playback progress [default: " << commandlineflags().show_progress << "]" << std::endl; - log << " --[no-]meters Show peak meters [default: " << commandlineflags().show_meters << "]" << std::endl; - log << " --[no-]channel-meters Show channel peak meters (EXPERIMENTAL) [default: " << commandlineflags().show_channel_meters << "]" << std::endl; - log << " --[no-]pattern Show pattern (EXPERIMENTAL) [default: " << commandlineflags().show_pattern << "]" << std::endl; - log << std::endl; - log << " --[no-]details Show song details [default: " << commandlineflags().show_details << "]" << std::endl; - log << " --[no-]message Show song message [default: " << commandlineflags().show_message << "]" << std::endl; - log << std::endl; - log << " --update n Set output update interval to n ms [default: " << commandlineflags().ui_redraw_interval << "]" << std::endl; - log << std::endl; - log << " --samplerate n Set samplerate to n Hz [default: " << commandlineflags().samplerate << "]" << std::endl; - log << " --channels n use n [1,2,4] output channels [default: " << commandlineflags().channels << "]" << std::endl; - log << " --[no-]float Output 32bit floating point instead of 16bit integer [default: " << commandlineflags().use_float << "]" << std::endl; - log << std::endl; - log << " --gain n Set output gain to n dB [default: " << commandlineflags().gain / 100.0 << "]" << std::endl; - log << " --stereo n Set stereo separation to n % [default: " << commandlineflags().separation << "]" << std::endl; - log << " --filter n Set interpolation filter taps to n [1,2,4,8] [default: " << commandlineflags().filtertaps << "]" << std::endl; - log << " --ramping n Set volume ramping strength n [0..5] [default: " << commandlineflags().ramping << "]" << std::endl; - log << " --tempo f Set tempo factor f [default: " << tempo_flag_to_double( commandlineflags().tempo ) << "]" << std::endl; - log << " --pitch f Set pitch factor f [default: " << pitch_flag_to_double( commandlineflags().pitch ) << "]" << std::endl; - log << " --dither n Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: " << commandlineflags().dither << "]" << std::endl; - log << std::endl; - log << " --playlist file Load playlist from file" << std::endl; - log << " --[no-]randomize Randomize playlist [default: " << commandlineflags().randomize << "]" << std::endl; - log << " --[no-]shuffle Shuffle through playlist [default: " << commandlineflags().shuffle << "]" << std::endl; - log << " --[no-]restart Restart playlist when finished [default: " << commandlineflags().restart << "]" << std::endl; - log << std::endl; - log << " --subsong n Select subsong n (-1 means play all subsongs consecutively) [default: " << commandlineflags().subsong << "]" << std::endl; - log << " --repeat n Repeat song n times (-1 means forever) [default: " << commandlineflags().repeatcount << "]" << std::endl; - log << " --seek n Seek to n seconds on start [default: " << commandlineflags().seek_target << "]" << std::endl; - log << " --end-time n Play until position is n seconds (0 means until the end) [default: " << commandlineflags().end_time << "]" << std::endl; - log << std::endl; - log << " --ctl c=v Set libopenmpt ctl c to value v" << std::endl; - log << std::endl; - log << " --driver n Set output driver [default: " << get_driver_string( commandlineflags().driver ) << "]," << std::endl; - log << " --device n Set output device [default: " << get_device_string( commandlineflags().device ) << "]," << std::endl; - log << " use --device help to show available devices" << std::endl; - log << " --buffer n Set output buffer size to n ms [default: " << commandlineflags().buffer << "]" << std::endl; - log << " --period n Set output period size to n ms [default: " << commandlineflags().period << "]" << std::endl; - log << " --stdout Write raw audio data to stdout [default: " << commandlineflags().use_stdout << "]" << std::endl; - log << " --output-type t Use output format t when writing to a individual PCM files (only applies to --render mode) [default: " << commandlineflags().output_extension << "]" << std::endl; - log << " -o, --output f Write PCM output to file f instead of streaming to audio device (only applies to --ui and --batch modes) [default: " << commandlineflags().output_filename << "]" << std::endl; - log << " --force Force overwriting of output file [default: " << commandlineflags().force_overwrite << "]" << std::endl; - log << std::endl; - log << " -- Interpret further arguments as filenames" << std::endl; - log << std::endl; + log << lf; + log << MPT_USTRING(" --banner n openmpt123 banner style [0=hide,1=show,2=verbose] [default: ") << commandlineflags().banner << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --assume-terminal Skip checking whether stdin/stderr are a terminal, and always allow UI [default: ") << commandlineflags().assume_terminal << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --terminal-width n Assume terminal is n characters wide [default: ") << commandlineflags().terminal_width << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --terminal-height n Assume terminal is n characters high [default: ") << commandlineflags().terminal_height << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --[no-]progress Show playback progress [default: ") << commandlineflags().show_progress << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]meters Show peak meters [default: ") << commandlineflags().show_meters << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]channel-meters Show channel peak meters (EXPERIMENTAL) [default: ") << commandlineflags().show_channel_meters << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]pattern Show pattern (EXPERIMENTAL) [default: ") << commandlineflags().show_pattern << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --[no-]details Show song details [default: ") << commandlineflags().show_details << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]message Show song message [default: ") << commandlineflags().show_message << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --update n Set output update interval to n ms [default: ") << commandlineflags().ui_redraw_interval << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --samplerate n Set samplerate to n Hz [default: ") << commandlineflags().samplerate << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --channels n use n [1,2,4] output channels [default: ") << commandlineflags().channels << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]float Output 32bit floating point instead of 16bit integer [default: ") << commandlineflags().use_float << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --gain n Set output gain to n dB [default: ") << commandlineflags().gain / 100.0 << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --stereo n Set stereo separation to n % [default: ") << commandlineflags().separation << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --filter n Set interpolation filter taps to n [1,2,4,8] [default: ") << commandlineflags().filtertaps << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --ramping n Set volume ramping strength n [0..5] [default: ") << commandlineflags().ramping << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --tempo f Set tempo factor f [default: ") << tempo_flag_to_double( commandlineflags().tempo ) << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --pitch f Set pitch factor f [default: ") << pitch_flag_to_double( commandlineflags().pitch ) << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --dither n Dither type to use (if applicable for selected output format): [0=off,1=auto,2=0.5bit,3=1bit] [default: ") << commandlineflags().dither << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --playlist file Load playlist from file") << lf; + log << MPT_USTRING(" --[no-]randomize Randomize playlist [default: ") << commandlineflags().randomize << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]shuffle Shuffle through playlist [default: ") << commandlineflags().shuffle << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --[no-]restart Restart playlist when finished [default: ") << commandlineflags().restart << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --subsong n Select subsong n (-1 means play all subsongs consecutively) [default: ") << commandlineflags().subsong << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --repeat n Repeat song n times (-1 means forever) [default: ") << commandlineflags().repeatcount << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --seek n Seek to n seconds on start [default: ") << commandlineflags().seek_target << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --end-time n Play until position is n seconds (0 means until the end) [default: ") << commandlineflags().end_time << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" --ctl c=v Set libopenmpt ctl c to value v") << lf; + log << lf; + log << MPT_USTRING(" --driver n Set output driver [default: ") << get_driver_string( commandlineflags().driver ) << MPT_USTRING("],") << lf; + log << MPT_USTRING(" --device n Set output device [default: ") << get_device_string( commandlineflags().device ) << MPT_USTRING("],") << lf; + log << MPT_USTRING(" use --device help to show available devices") << lf; + log << MPT_USTRING(" --buffer n Set output buffer size to n ms [default: ") << commandlineflags().buffer << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --period n Set output period size to n ms [default: ") << commandlineflags().period << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --stdout Write raw audio data to stdout [default: ") << commandlineflags().use_stdout << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --output-type t Use output format t when writing to a individual PCM files (only applies to --render mode) [default: ") << mpt::transcode( commandlineflags().output_extension ) << MPT_USTRING("]") << lf; + log << MPT_USTRING(" -o, --output f Write PCM output to file f instead of streaming to audio device (only applies to --ui and --batch modes) [default: ") << mpt::transcode( commandlineflags().output_filename ) << MPT_USTRING("]") << lf; + log << MPT_USTRING(" --force Force overwriting of output file [default: ") << commandlineflags().force_overwrite << MPT_USTRING("]") << lf; + log << lf; + log << MPT_USTRING(" -- Interpret further arguments as filenames") << lf; + log << lf; if ( !man_version ) { - log << " Supported file formats: " << std::endl; - log << " "; + log << MPT_USTRING(" Supported file formats: ") << lf; + log << MPT_USTRING(" "); std::vector extensions = openmpt::get_supported_extensions(); bool first = true; for ( const auto & extension : extensions ) { if ( first ) { first = false; } else { - log << ", "; + log << MPT_USTRING(", "); } - log << extension; + log << mpt::transcode( libopenmpt_encoding, extension ); } - log << std::endl; + log << lf; } else { show_help_keyboard( log, true ); } } - log << std::endl; + log << lf; if ( message.size() > 0 ) { log << message; - log << std::endl; + log << lf; } log.writeout(); } @@ -815,7 +732,7 @@ struct meter_type { static const float falloff_rate = 20.0f / 1.7f; static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const std::int16_t * const * buffers ) { - float falloff_factor = std::pow( 10.0f, -falloff_rate / flags.samplerate / 20.0f ); + float falloff_factor = std::pow( 10.0f, -falloff_rate / static_cast( flags.samplerate ) / 20.0f ); for ( int channel = 0; channel < flags.channels; ++channel ) { meter.channels[channel].peak = 0.0f; for ( std::size_t frame = 0; frame < count; ++frame ) { @@ -844,7 +761,7 @@ static void update_meter( meter_type & meter, const commandlineflags & flags, st } static void update_meter( meter_type & meter, const commandlineflags & flags, std::size_t count, const float * const * buffers ) { - float falloff_factor = std::pow( 10.0f, -falloff_rate / flags.samplerate / 20.0f ); + float falloff_factor = std::pow( 10.0f, -falloff_rate / static_cast( flags.samplerate ) / 20.0f ); for ( int channel = 0; channel < flags.channels; ++channel ) { if ( !count ) { meter = meter_type(); @@ -875,14 +792,14 @@ static void update_meter( meter_type & meter, const commandlineflags & flags, st } } -static const char * const channel_tags[4][4] = { - { " C", " ", " ", " " }, - { " L", " R", " ", " " }, - { "FL", "FR", "RC", " " }, - { "FL", "FR", "RL", "RR" }, +static const mpt::uchar * const channel_tags[4][4] = { + { MPT_ULITERAL(" C"), MPT_ULITERAL(" "), MPT_ULITERAL(" "), MPT_ULITERAL(" ") }, + { MPT_ULITERAL(" L"), MPT_ULITERAL(" R"), MPT_ULITERAL(" "), MPT_ULITERAL(" ") }, + { MPT_ULITERAL("FL"), MPT_ULITERAL("FR"), MPT_ULITERAL("RC"), MPT_ULITERAL(" ") }, + { MPT_ULITERAL("FL"), MPT_ULITERAL("FR"), MPT_ULITERAL("RL"), MPT_ULITERAL("RR") }, }; -static std::string channel_to_string( int channels, int channel, const meter_channel & meter, bool tiny = false ) { +static mpt::ustring channel_to_string( int channels, int channel, const meter_channel & meter, bool tiny = false ) { int val = std::numeric_limits::min(); int hold_pos = std::numeric_limits::min(); if ( meter.peak > 0.0f ) { @@ -913,85 +830,81 @@ static std::string channel_to_string( int channels, int channel, const meter_cha } if ( tiny ) { if ( meter.clip != 0.0f || meter.peak >= 1.0f ) { - return "#"; + return MPT_USTRING("#"); } else if ( meter.peak > std::pow( 10.0f, -6.0f / 20.0f ) ) { - return "O"; + return MPT_USTRING("O"); } else if ( meter.peak > std::pow( 10.0f, -12.0f / 20.0f ) ) { - return "o"; + return MPT_USTRING("o"); } else if ( meter.peak > std::pow( 10.0f, -18.0f / 20.0f ) ) { - return "."; + return MPT_USTRING("."); } else { - return " "; + return MPT_USTRING(" "); } } else { - std::ostringstream res1; - std::ostringstream res2; - res1 - << " " - << channel_tags[channels-1][channel] - << " : " - ; - res2 - << std::string(val,'>') << std::string(std::size_t{48}-val,' ') - << ( ( meter.clip != 0.0f ) ? "#" : ":" ) - << std::string(headroom,'>') << std::string(std::size_t{12}-headroom,' ') - ; - std::string tmp = res2.str(); + mpt::ustring res1; + mpt::ustring res2; + res1 += MPT_USTRING(" "); + res1 += channel_tags[channels-1][channel]; + res1 += MPT_USTRING(" : "); + res2 += mpt::ustring( val, MPT_UCHAR('>') ) + mpt::ustring( std::size_t{48} - val, MPT_UCHAR(' ') ); + res2 += ( ( meter.clip != 0.0f ) ? MPT_USTRING("#") : MPT_USTRING(":") ); + res2 += mpt::ustring( headroom, MPT_UCHAR('>') ) + mpt::ustring( std::size_t{12} - headroom, MPT_UCHAR(' ') ); + mpt::ustring tmp = res2; if ( 0 <= hold_pos && hold_pos <= 60 ) { if ( hold_pos == 48 ) { - tmp[hold_pos] = '#'; + tmp[hold_pos] = MPT_UCHAR('#'); } else { - tmp[hold_pos] = ':'; + tmp[hold_pos] = MPT_UCHAR(':'); } } - return res1.str() + tmp; + return res1 + tmp; } } -static char peak_to_char( float peak ) { +static mpt::ustring peak_to_string( float peak ) { if ( peak >= 1.0f ) { - return '#'; + return MPT_USTRING("#"); } else if ( peak >= 0.5f ) { - return 'O'; + return MPT_USTRING("O"); } else if ( peak >= 0.25f ) { - return 'o'; + return MPT_USTRING("o"); } else if ( peak >= 0.125f ) { - return '.'; + return MPT_USTRING("."); } else { - return ' '; + return MPT_USTRING(" "); } } -static std::string peak_to_string_left( float peak, int width ) { - std::string result; +static mpt::ustring peak_to_string_left( float peak, int width ) { + mpt::ustring result; float thresh = 1.0f; while ( width-- ) { if ( peak >= thresh ) { if ( thresh == 1.0f ) { - result.push_back( '#' ); + result.push_back( MPT_UCHAR('#') ); } else { - result.push_back( '<' ); + result.push_back( MPT_UCHAR('<') ); } } else { - result.push_back( ' ' ); + result.push_back( MPT_UCHAR(' ') ); } thresh *= 0.5f; } return result; } -static std::string peak_to_string_right( float peak, int width ) { - std::string result; +static mpt::ustring peak_to_string_right( float peak, int width ) { + mpt::ustring result; float thresh = 1.0f; while ( width-- ) { if ( peak >= thresh ) { if ( thresh == 1.0f ) { - result.push_back( '#' ); + result.push_back( MPT_UCHAR('#') ); } else { - result.push_back( '>' ); + result.push_back( MPT_UCHAR('>') ); } } else { - result.push_back( ' ' ); + result.push_back( MPT_UCHAR(' ') ); } thresh *= 0.5f; } @@ -999,31 +912,31 @@ static std::string peak_to_string_right( float peak, int width ) { return result; } -static void draw_meters( std::ostream & log, const meter_type & meter, const commandlineflags & flags ) { +static void draw_meters( concat_stream & log, const meter_type & meter, const commandlineflags & flags ) { for ( int channel = 0; channel < flags.channels; ++channel ) { - log << channel_to_string( flags.channels, channel, meter.channels[channel] ) << std::endl; + log << channel_to_string( flags.channels, channel, meter.channels[channel] ) << lf; } } -static void draw_meters_tiny( std::ostream & log, const meter_type & meter, const commandlineflags & flags ) { +static void draw_meters_tiny( concat_stream & log, const meter_type & meter, const commandlineflags & flags ) { for ( int channel = 0; channel < flags.channels; ++channel ) { log << channel_to_string( flags.channels, channel, meter.channels[channel], true ); } } -static void draw_channel_meters_tiny( std::ostream & log, float peak ) { - log << peak_to_char( peak ); +static void draw_channel_meters_tiny( concat_stream & log, float peak ) { + log << peak_to_string( peak ); } -static void draw_channel_meters_tiny( std::ostream & log, float peak_left, float peak_right ) { - log << peak_to_char( peak_left ) << peak_to_char( peak_right ); +static void draw_channel_meters_tiny( concat_stream & log, float peak_left, float peak_right ) { + log << peak_to_string( peak_left ) << peak_to_string( peak_right ); } -static void draw_channel_meters( std::ostream & log, float peak_left, float peak_right, int width ) { +static void draw_channel_meters( concat_stream & log, float peak_left, float peak_right, int width ) { if ( width >= 8 + 1 + 8 ) { width = 8 + 1 + 8; } - log << peak_to_string_left( peak_left, width / 2 ) << ( width % 2 == 1 ? ":" : "" ) << peak_to_string_right( peak_right, width / 2 ); + log << peak_to_string_left( peak_left, width / 2 ) << ( width % 2 == 1 ? MPT_USTRING(":") : MPT_USTRING("") ) << peak_to_string_right( peak_right, width / 2 ); } template < typename Tsample, typename Tmod > @@ -1090,10 +1003,10 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto lines = flags.terminal_height - 1; } } else if ( flags.show_ui || flags.show_details || flags.show_progress ) { - log << std::endl; + log << lf; } for ( int line = 0; line < lines; ++line ) { - log << std::endl; + log << lf; } log.writeout(); @@ -1104,7 +1017,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto if ( flags.mode == Mode::UI ) { -#if defined( __DJGPP__ ) +#if MPT_OS_DJGPP while ( kbhit() ) { int c = getch(); @@ -1113,7 +1026,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto } } -#elif defined( WIN32 ) && defined( UNICODE ) +#elif MPT_OS_WINDOWS && defined( UNICODE ) && !MPT_OS_WINDOWS_WINRT while ( _kbhit() ) { wint_t c = _getwch(); @@ -1122,7 +1035,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto } } -#elif defined( WIN32 ) +#elif MPT_OS_WINDOWS while ( _kbhit() ) { int c = _getch(); @@ -1173,7 +1086,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto case 4: count = mod.read( flags.samplerate, bufsize, left.data(), right.data(), rear_left.data(), rear_right.data() ); break; } - char cpu_str[64] = ""; + mpt::ustring cpu_str; if ( flags.show_details ) { cpu_end = std::clock(); if ( count > 0 ) { @@ -1182,7 +1095,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto cpu /= ( static_cast( count ) ) / static_cast( flags.samplerate ); double mix = ( static_cast( count ) ) / static_cast( flags.samplerate ); cpu_smooth = ( 1.0 - mix ) * cpu_smooth + mix * cpu; - std::snprintf( cpu_str, 64, "%.2f%%", cpu_smooth * 100.0 ); + cpu_str = mpt::format::fix( cpu_smooth * 100.0, 2 ) + MPT_USTRING("%"); } } @@ -1205,7 +1118,7 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto if ( multiline ) { log.cursor_up( lines ); - log << std::endl; + log << lf; if ( flags.show_meters ) { draw_meters( log, meter, flags ); } @@ -1214,10 +1127,10 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto if ( width > 11 ) { width = 11; } - log << " "; + log << MPT_USTRING(" "); for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } if ( width == 1 ) { draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) ); @@ -1228,9 +1141,9 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto } } if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } - log << std::endl; + log << lf; } if ( flags.show_pattern ) { int width = ( flags.terminal_width - 3 ) / mod.get_num_channels(); @@ -1240,75 +1153,75 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto for ( std::int32_t line = 0; line < pattern_lines; ++line ) { std::int32_t row = mod.get_current_row() - ( pattern_lines / 2 ) + line; if ( row == mod.get_current_row() ) { - log << ">"; + log << MPT_USTRING(">"); } else { - log << " "; + log << MPT_USTRING(" "); } if ( row < 0 || row >= mod.get_pattern_num_rows( mod.get_current_pattern() ) ) { for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } - log << std::string( width >= 3 ? width - 1 : width, ' ' ); + log << mpt::ustring( width >= 3 ? width - 1 : width, MPT_UCHAR(' ') ); } } else { for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { if ( row == mod.get_current_row() ) { - log << "+"; + log << MPT_USTRING("+"); } else { - log << ":"; + log << MPT_USTRING(":"); } } - log << mod.format_pattern_row_channel( mod.get_current_pattern(), row, channel, width >= 3 ? width - 1 : width ); + log << mpt::transcode( libopenmpt_encoding, mod.format_pattern_row_channel( mod.get_current_pattern(), row, channel, width >= 3 ? width - 1 : width ) ); } } if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } - log << std::endl; + log << lf; } } if ( flags.show_ui ) { - log << "Settings...: "; - log << "Gain: " << flags.gain * 0.01f << " dB" << " "; - log << "Stereo: " << flags.separation << " %" << " "; - log << "Filter: " << flags.filtertaps << " taps" << " "; - log << "Ramping: " << flags.ramping << " "; - log << std::endl; + log << MPT_USTRING("Settings...: "); + log << MPT_USTRING("Gain: ") << static_cast( flags.gain ) * 0.01f << MPT_USTRING(" dB") << MPT_USTRING(" "); + log << MPT_USTRING("Stereo: ") << flags.separation << MPT_USTRING(" %") << MPT_USTRING(" "); + log << MPT_USTRING("Filter: ") << flags.filtertaps << MPT_USTRING(" taps") << MPT_USTRING(" "); + log << MPT_USTRING("Ramping: ") << flags.ramping << MPT_USTRING(" "); + log << lf; } if ( flags.show_details ) { - log << "Mixer......: "; - log << "CPU:" << std::setw(6) << std::setfill(':') << cpu_str; - log << " "; - log << "Chn:" << std::setw(3) << std::setfill(':') << mod.get_current_playing_channels(); - log << " "; - log << std::endl; + log << MPT_USTRING("Mixer......: "); + log << MPT_USTRING("CPU:") << align_right( MPT_UCHAR(':'), 6, cpu_str ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Chn:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_playing_channels() ); + log << MPT_USTRING(" "); + log << lf; if ( flags.show_progress ) { - log << "Player.....: "; - log << "Ord:" << std::setw(3) << std::setfill(':') << mod.get_current_order() << "/" << std::setw(3) << std::setfill(':') << mod.get_num_orders(); - log << " "; - log << "Pat:" << std::setw(3) << std::setfill(':') << mod.get_current_pattern(); - log << " "; - log << "Row:" << std::setw(3) << std::setfill(':') << mod.get_current_row(); - log << " "; - log << "Spd:" << std::setw(2) << std::setfill(':') << mod.get_current_speed(); - log << " "; - log << "Tmp:" << std::setw(3) << std::setfill(':') << mod.get_current_tempo(); - log << " "; - log << std::endl; + log << MPT_USTRING("Player.....: "); + log << MPT_USTRING("Ord:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_order() ) << MPT_USTRING("/") << align_right( MPT_UCHAR(':'), 3, mod.get_num_orders() ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Pat:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_pattern() ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Row:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_row() ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Spd:") << align_right( MPT_UCHAR(':'), 2, mod.get_current_speed() ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Tmp:") << align_right( MPT_UCHAR(':'), 6, mpt::format::fix( mod.get_current_tempo2(), 2 ) ); + log << MPT_USTRING(" "); + log << lf; } } if ( flags.show_progress ) { - log << "Position...: " << seconds_to_string( mod.get_position_seconds() ) << " / " << seconds_to_string( duration ) << " " << std::endl; + log << MPT_USTRING("Position...: ") << seconds_to_string( mod.get_position_seconds() ) << MPT_USTRING(" / ") << seconds_to_string( duration ) << MPT_USTRING(" ") << lf; } } else if ( flags.show_channel_meters ) { if ( flags.show_ui || flags.show_details || flags.show_progress ) { int width = ( flags.terminal_width - 3 ) / mod.get_num_channels(); - log << " "; + log << MPT_USTRING(" "); for ( std::int32_t channel = 0; channel < mod.get_num_channels(); ++channel ) { if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } if ( width == 1 ) { draw_channel_meters_tiny( log, ( mod.get_current_channel_vu_left( channel ) + mod.get_current_channel_vu_right( channel ) ) * (1.0f/std::sqrt(2.0f)) ); @@ -1319,53 +1232,53 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto } } if ( width >= 3 ) { - log << ":"; + log << MPT_USTRING(":"); } } - log << " " << "\r"; + log << MPT_USTRING(" ") << MPT_USTRING("\r"); } else { if ( flags.show_ui ) { - log << " "; - log << std::setw(3) << std::setfill(':') << flags.gain * 0.01f << "dB"; - log << "|"; - log << std::setw(3) << std::setfill(':') << flags.separation << "%"; - log << "|"; - log << std::setw(2) << std::setfill(':') << flags.filtertaps << "taps"; - log << "|"; - log << std::setw(3) << std::setfill(':') << flags.ramping; + log << MPT_USTRING(" "); + log << align_right( MPT_UCHAR(':'), 3, static_cast( flags.gain ) * 0.01f ) << MPT_USTRING("dB"); + log << MPT_USTRING("|"); + log << align_right( MPT_UCHAR(':'), 3, flags.separation ) << MPT_USTRING("%"); + log << MPT_USTRING("|"); + log << align_right( MPT_UCHAR(':'), 2, flags.filtertaps ) << MPT_USTRING("taps"); + log << MPT_USTRING("|"); + log << align_right( MPT_UCHAR(':'), 3, flags.ramping ); } if ( flags.show_meters ) { - log << " "; + log << MPT_USTRING(" "); draw_meters_tiny( log, meter, flags ); } if ( flags.show_details && flags.show_ui ) { - log << " "; - log << "CPU:" << std::setw(6) << std::setfill(':') << cpu_str; - log << "|"; - log << "Chn:" << std::setw(3) << std::setfill(':') << mod.get_current_playing_channels(); + log << MPT_USTRING(" "); + log << MPT_USTRING("CPU:") << align_right( MPT_UCHAR(':'), 6, cpu_str ); + log << MPT_USTRING("|"); + log << MPT_USTRING("Chn:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_playing_channels() ); } if ( flags.show_details && !flags.show_ui ) { if ( flags.show_progress ) { - log << " "; - log << "Ord:" << std::setw(3) << std::setfill(':') << mod.get_current_order() << "/" << std::setw(3) << std::setfill(':') << mod.get_num_orders(); - log << "|"; - log << "Pat:" << std::setw(3) << std::setfill(':') << mod.get_current_pattern(); - log << "|"; - log << "Row:" << std::setw(3) << std::setfill(':') << mod.get_current_row(); - log << " "; - log << "Spd:" << std::setw(2) << std::setfill(':') << mod.get_current_speed(); - log << "|"; - log << "Tmp:" << std::setw(3) << std::setfill(':') << mod.get_current_tempo(); + log << MPT_USTRING(" "); + log << MPT_USTRING("Ord:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_order() ) << MPT_USTRING("/") << align_right( MPT_UCHAR(':'), 3, mod.get_num_orders() ); + log << MPT_USTRING("|"); + log << MPT_USTRING("Pat:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_pattern() ); + log << MPT_USTRING("|"); + log << MPT_USTRING("Row:") << align_right( MPT_UCHAR(':'), 3, mod.get_current_row() ); + log << MPT_USTRING(" "); + log << MPT_USTRING("Spd:") << align_right( MPT_UCHAR(':'), 2, mod.get_current_speed() ); + log << MPT_USTRING("|"); + log << MPT_USTRING("Tmp:") << align_right( MPT_UCHAR(':'), 3, mpt::format::fix( mod.get_current_tempo2(), 2 ) ); } } if ( flags.show_progress ) { - log << " "; + log << MPT_USTRING(" "); log << seconds_to_string( mod.get_position_seconds() ); - log << "/"; + log << MPT_USTRING("/"); log << seconds_to_string( duration ); } if ( flags.show_ui || flags.show_details || flags.show_progress ) { - log << " " << "\r"; + log << MPT_USTRING(" ") << MPT_USTRING("\r"); } } @@ -1386,94 +1299,75 @@ void render_loop( commandlineflags & flags, Tmod & mod, double & duration, texto } template < typename Tmod > -std::map get_metadata( const Tmod & mod ) { - std::map result; +std::map get_metadata( const Tmod & mod ) { + std::map result; const std::vector metadata_keys = mod.get_metadata_keys(); for ( const auto & key : metadata_keys ) { - result[ key ] = mod.get_metadata( key ); + result[ mpt::transcode( libopenmpt_encoding, key ) ] = mpt::transcode( libopenmpt_encoding, mod.get_metadata( key ) ); } return result; } -class set_field : private std::ostringstream { -private: - std::vector & fields; -public: - set_field( std::vector & fields, const std::string & name ) - : fields(fields) - { - fields.push_back( name ); - } - std::ostream & ostream() { - return *this; - } - ~set_field() { - fields.back().val = str(); - } -}; +static void set_field( std::vector & fields, const mpt::ustring & name, const mpt::ustring & value ) { + fields.push_back( field{ name, value } ); +} static void show_fields( textout & log, const std::vector & fields ) { const std::size_t fw = 11; - for ( const auto & field :fields ) { - std::string key = field.key; - std::string val = field.val; + for ( const auto & field : fields ) { + mpt::ustring key = field.key; + mpt::ustring val = field.val; if ( key.length() < fw ) { - key += std::string( fw - key.length(), '.' ); + key += mpt::ustring( fw - key.length(), MPT_UCHAR('.') ); } if ( key.length() > fw ) { key = key.substr( 0, fw ); } - key += ": "; - val = prepend_lines( val, std::string( fw, ' ' ) + ": " ); - log << key << val << std::endl; + key += MPT_USTRING(": "); + val = prepend_lines( val, mpt::ustring( fw, MPT_UCHAR(' ') ) + MPT_USTRING(": ") ); + log << key << val << lf; } } -static void probe_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, std::istream & data_stream, textout & log ) { +static void probe_mod_file( commandlineflags & flags, const mpt::native_path & filename, std::uint64_t filesize, std::istream & data_stream, textout & log ) { log.writeout(); std::vector fields; if ( flags.filenames.size() > 1 ) { - set_field( fields, "Playlist" ).ostream() << flags.playlist_index + 1 << "/" << flags.filenames.size(); - set_field( fields, "Prev/Next" ).ostream() - << "'" - << ( flags.playlist_index > 0 ? get_filename( flags.filenames[ flags.playlist_index - 1 ] ) : std::string() ) - << "'" - << " / " - << "['" << get_filename( filename ) << "']" - << " / " - << "'" - << ( flags.playlist_index + 1 < flags.filenames.size() ? get_filename( flags.filenames[ flags.playlist_index + 1 ] ) : std::string() ) - << "'" - ; + set_field( fields, MPT_USTRING("Playlist"), MPT_UFORMAT_MESSAGE( "{}/{}" )( flags.playlist_index + 1, flags.filenames.size() ) ); + set_field( fields, MPT_USTRING("Prev/Next"), MPT_UFORMAT_MESSAGE( "'{}' / ['{}'] / '{}'" )( + ( flags.playlist_index > 0 ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index - 1 ] ) ) : mpt::ustring() ), + mpt::transcode( get_filename( filename ) ), + ( flags.playlist_index + 1 < flags.filenames.size() ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index + 1 ] ) ) : mpt::ustring() ) + ) ); } if ( flags.verbose ) { - set_field( fields, "Path" ).ostream() << filename; + set_field( fields, MPT_USTRING("Path"), mpt::transcode( filename ) ); } if ( flags.show_details ) { - set_field( fields, "Filename" ).ostream() << get_filename( filename ); - set_field( fields, "Size" ).ostream() << bytes_to_string( filesize ); + set_field( fields, MPT_USTRING("Filename"), mpt::transcode( get_filename( filename ) ) ); + set_field( fields, MPT_USTRING("Size"), bytes_to_string( filesize ) ); } int probe_result = openmpt::probe_file_header( openmpt::probe_file_header_flags_default2, data_stream ); - std::string probe_result_string; + mpt::ustring probe_result_string; switch ( probe_result ) { case openmpt::probe_file_header_result_success: - probe_result_string = "Success"; + probe_result_string = MPT_USTRING("Success"); break; case openmpt::probe_file_header_result_failure: - probe_result_string = "Failure"; + probe_result_string = MPT_USTRING("Failure"); break; case openmpt::probe_file_header_result_wantmoredata: - probe_result_string = "Insufficient Data"; + probe_result_string = MPT_USTRING("Insufficient Data"); break; default: - probe_result_string = "Internal Error"; + probe_result_string = MPT_USTRING("Internal Error"); break; } - set_field( fields, "Probe" ).ostream() << probe_result_string; + set_field( fields, MPT_USTRING("Probe"), probe_result_string ); show_fields( log, fields ); @@ -1482,7 +1376,7 @@ static void probe_mod_file( commandlineflags & flags, const std::string & filena } template < typename Tmod > -void render_mod_file( commandlineflags & flags, const std::string & filename, std::uint64_t filesize, Tmod & mod, textout & log, write_buffers_interface & audio_stream ) { +void render_mod_file( commandlineflags & flags, const mpt::native_path & filename, std::uint64_t filesize, Tmod & mod, textout & log, write_buffers_interface & audio_stream ) { log.writeout(); @@ -1496,60 +1390,54 @@ void render_mod_file( commandlineflags & flags, const std::string & filename, st std::vector fields; if ( flags.filenames.size() > 1 ) { - set_field( fields, "Playlist" ).ostream() << flags.playlist_index + 1 << "/" << flags.filenames.size(); - set_field( fields, "Prev/Next" ).ostream() - << "'" - << ( flags.playlist_index > 0 ? get_filename( flags.filenames[ flags.playlist_index - 1 ] ) : std::string() ) - << "'" - << " / " - << "['" << get_filename( filename ) << "']" - << " / " - << "'" - << ( flags.playlist_index + 1 < flags.filenames.size() ? get_filename( flags.filenames[ flags.playlist_index + 1 ] ) : std::string() ) - << "'" - ; + set_field( fields, MPT_USTRING("Playlist"), MPT_UFORMAT_MESSAGE("{}/{}")( flags.playlist_index + 1, flags.filenames.size() ) ); + set_field( fields, MPT_USTRING("Prev/Next"), MPT_UFORMAT_MESSAGE("'{}' / ['{}'] / '{}'")( + ( flags.playlist_index > 0 ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index - 1 ] ) ) : mpt::ustring() ), + mpt::transcode( get_filename( filename ) ), + ( flags.playlist_index + 1 < flags.filenames.size() ? mpt::transcode( get_filename( flags.filenames[ flags.playlist_index + 1 ] ) ) : mpt::ustring() ) + ) ); } if ( flags.verbose ) { - set_field( fields, "Path" ).ostream() << filename; + set_field( fields, MPT_USTRING("Path"), mpt::transcode( filename ) ); } if ( flags.show_details ) { - set_field( fields, "Filename" ).ostream() << get_filename( filename ); - set_field( fields, "Size" ).ostream() << bytes_to_string( filesize ); + set_field( fields, MPT_USTRING("Filename"), mpt::transcode( get_filename( filename ) ) ); + set_field( fields, MPT_USTRING("Size"), bytes_to_string( filesize ) ); if ( !mod.get_metadata( "warnings" ).empty() ) { - set_field( fields, "Warnings" ).ostream() << mod.get_metadata( "warnings" ); + set_field( fields, MPT_USTRING("Warnings"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "warnings" ) ) ); } if ( !mod.get_metadata( "container" ).empty() ) { - set_field( fields, "Container" ).ostream() << mod.get_metadata( "container" ) << " (" << mod.get_metadata( "container_long" ) << ")"; + set_field( fields, MPT_USTRING("Container"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "container" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "container_long" ) ) ) ); } - set_field( fields, "Type" ).ostream() << mod.get_metadata( "type" ) << " (" << mod.get_metadata( "type_long" ) << ")"; + set_field( fields, MPT_USTRING("Type"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "type" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "type_long" ) ) ) ); if ( !mod.get_metadata( "originaltype" ).empty() ) { - set_field( fields, "Orig. Type" ).ostream() << mod.get_metadata( "originaltype" ) << " (" << mod.get_metadata( "originaltype_long" ) << ")"; + set_field( fields, MPT_USTRING("Orig. Type"), MPT_UFORMAT_MESSAGE("{} ({})")( mpt::transcode( libopenmpt_encoding, mod.get_metadata( "originaltype" ) ), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "originaltype_long" ) ) ) ); } if ( ( mod.get_num_subsongs() > 1 ) && ( flags.subsong != -1 ) ) { - set_field( fields, "Subsong" ).ostream() << flags.subsong; + set_field( fields, MPT_USTRING("Subsong"), mpt::format::val( flags.subsong ) ); } - set_field( fields, "Tracker" ).ostream() << mod.get_metadata( "tracker" ); + set_field( fields, MPT_USTRING("Tracker"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "tracker" ) ) ); if ( !mod.get_metadata( "date" ).empty() ) { - set_field( fields, "Date" ).ostream() << mod.get_metadata( "date" ); + set_field( fields, MPT_USTRING("Date"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "date" ) ) ); } if ( !mod.get_metadata( "artist" ).empty() ) { - set_field( fields, "Artist" ).ostream() << mod.get_metadata( "artist" ); + set_field( fields, MPT_USTRING("Artist"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "artist" ) ) ); } } if ( true ) { - set_field( fields, "Title" ).ostream() << mod.get_metadata( "title" ); - set_field( fields, "Duration" ).ostream() << seconds_to_string( duration ); + set_field( fields, MPT_USTRING("Title"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "title" ) ) ); + set_field( fields, MPT_USTRING("Duration"), seconds_to_string( duration ) ); } if ( flags.show_details ) { - set_field( fields, "Subsongs" ).ostream() << mod.get_num_subsongs(); - set_field( fields, "Channels" ).ostream() << mod.get_num_channels(); - set_field( fields, "Orders" ).ostream() << mod.get_num_orders(); - set_field( fields, "Patterns" ).ostream() << mod.get_num_patterns(); - set_field( fields, "Instruments" ).ostream() << mod.get_num_instruments(); - set_field( fields, "Samples" ).ostream() << mod.get_num_samples(); + set_field( fields, MPT_USTRING("Subsongs"), mpt::format::val( mod.get_num_subsongs() ) ); + set_field( fields, MPT_USTRING("Channels"), mpt::format::val( mod.get_num_channels() ) ); + set_field( fields, MPT_USTRING("Orders"), mpt::format::val( mod.get_num_orders() ) ); + set_field( fields, MPT_USTRING("Patterns"), mpt::format::val( mod.get_num_patterns() ) ); + set_field( fields, MPT_USTRING("Instruments"), mpt::format::val( mod.get_num_instruments() ) ); + set_field( fields, MPT_USTRING("Samples"), mpt::format::val( mod.get_num_samples() ) ); } if ( flags.show_message ) { - set_field( fields, "Message" ).ostream() << mod.get_metadata( "message" ); + set_field( fields, MPT_USTRING("Message"), mpt::transcode( libopenmpt_encoding, mod.get_metadata( "message" ) ) ); } show_fields( log, fields ); @@ -1577,11 +1465,11 @@ void render_mod_file( commandlineflags & flags, const std::string & filename, st render_loop( flags, mod, duration, log, audio_stream ); } if ( flags.show_progress ) { - log << std::endl; + log << lf; } } catch ( ... ) { if ( flags.show_progress ) { - log << std::endl; + log << lf; } throw; } @@ -1590,7 +1478,7 @@ void render_mod_file( commandlineflags & flags, const std::string & filename, st } -static void probe_file( commandlineflags & flags, const std::string & filename, textout & log ) { +static void probe_file( commandlineflags & flags, const mpt::native_path & filename, textout & log ) { log.writeout(); @@ -1598,46 +1486,19 @@ static void probe_file( commandlineflags & flags, const std::string & filename, try { -#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - std::istringstream file_stream; -#else - std::ifstream file_stream; -#endif + std::optional optional_file_stream; std::uint64_t filesize = 0; - bool use_stdin = ( filename == "-" ); + bool use_stdin = ( filename == MPT_NATIVE_PATH("-") ); if ( !use_stdin ) { - #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - // Only MSVC has std::ifstream::ifstream(std::wstring). - // Fake it for other compilers using _wfopen(). - std::string data; - FILE * f = _wfopen( mpt::transcode( mpt::common_encoding::utf8, filename ).c_str(), L"rb" ); - if ( f ) { - while ( !feof( f ) ) { - static const std::size_t BUFFER_SIZE = 4096; - char buffer[BUFFER_SIZE]; - size_t data_read = fread( buffer, 1, BUFFER_SIZE, f ); - std::copy( buffer, buffer + data_read, std::back_inserter( data ) ); - } - fclose( f ); - f = NULL; - } - file_stream.str( data ); - filesize = data.length(); - #elif defined(_MSC_VER) && defined(UNICODE) - file_stream.open( mpt::transcode( mpt::common_encoding::utf8, filename ), std::ios::binary ); - file_stream.seekg( 0, std::ios::end ); - filesize = file_stream.tellg(); - file_stream.seekg( 0, std::ios::beg ); - #else - file_stream.open( filename, std::ios::binary ); - file_stream.seekg( 0, std::ios::end ); - filesize = file_stream.tellg(); - file_stream.seekg( 0, std::ios::beg ); - #endif + optional_file_stream.emplace( filename, std::ios::binary ); + std::istream & file_stream = *optional_file_stream; + file_stream.seekg( 0, std::ios::end ); + filesize = file_stream.tellg(); + file_stream.seekg( 0, std::ios::beg ); } - std::istream & data_stream = use_stdin ? std::cin : file_stream; + std::istream & data_stream = use_stdin ? std::cin : *optional_file_stream; if ( data_stream.fail() ) { - throw exception( "file open error" ); + throw exception( MPT_USTRING("file open error") ); } probe_mod_file( flags, filename, filesize, data_stream, log ); @@ -1646,27 +1507,27 @@ static void probe_file( commandlineflags & flags, const std::string & filename, throw; } catch ( std::exception & e ) { if ( !silentlog.str().empty() ) { - log << "errors probing '" << filename << "': " << silentlog.str() << std::endl; + log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { - log << "errors probing '" << filename << "'" << std::endl; + log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << "error probing '" << filename << "': " << e.what() << std::endl; + log << MPT_USTRING("error probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { if ( !silentlog.str().empty() ) { - log << "errors probing '" << filename << "': " << silentlog.str() << std::endl; + log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { - log << "errors probing '" << filename << "'" << std::endl; + log << MPT_USTRING("errors probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << "unknown error probing '" << filename << "'" << std::endl; + log << MPT_USTRING("unknown error probing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << std::endl; + log << lf; log.writeout(); } -static void render_file( commandlineflags & flags, const std::string & filename, textout & log, write_buffers_interface & audio_stream ) { +static void render_file( commandlineflags & flags, const mpt::native_path & filename, textout & log, write_buffers_interface & audio_stream ) { log.writeout(); @@ -1674,46 +1535,19 @@ static void render_file( commandlineflags & flags, const std::string & filename, try { -#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - std::istringstream file_stream; -#else - std::ifstream file_stream; -#endif + std::optional optional_file_stream; std::uint64_t filesize = 0; - bool use_stdin = ( filename == "-" ); + bool use_stdin = ( filename == MPT_NATIVE_PATH("-") ); if ( !use_stdin ) { - #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - // Only MSVC has std::ifstream::ifstream(std::wstring). - // Fake it for other compilers using _wfopen(). - std::string data; - FILE * f = _wfopen( mpt::transcode( mpt::common_encoding::utf8, filename ).c_str(), L"rb" ); - if ( f ) { - while ( !feof( f ) ) { - static const std::size_t BUFFER_SIZE = 4096; - char buffer[BUFFER_SIZE]; - size_t data_read = fread( buffer, 1, BUFFER_SIZE, f ); - std::copy( buffer, buffer + data_read, std::back_inserter( data ) ); - } - fclose( f ); - f = NULL; - } - file_stream.str( data ); - filesize = data.length(); - #elif defined(_MSC_VER) && defined(UNICODE) - file_stream.open( mpt::transcode( mpt::common_encoding::utf8, filename ), std::ios::binary ); - file_stream.seekg( 0, std::ios::end ); - filesize = file_stream.tellg(); - file_stream.seekg( 0, std::ios::beg ); - #else - file_stream.open( filename, std::ios::binary ); - file_stream.seekg( 0, std::ios::end ); - filesize = file_stream.tellg(); - file_stream.seekg( 0, std::ios::beg ); - #endif + optional_file_stream.emplace( filename, std::ios::binary ); + std::istream & file_stream = *optional_file_stream; + file_stream.seekg( 0, std::ios::end ); + filesize = file_stream.tellg(); + file_stream.seekg( 0, std::ios::beg ); } - std::istream & data_stream = use_stdin ? std::cin : file_stream; + std::istream & data_stream = use_stdin ? std::cin : *optional_file_stream; if ( data_stream.fail() ) { - throw exception( "file open error" ); + throw exception( MPT_USTRING("file open error") ); } { @@ -1731,30 +1565,30 @@ static void render_file( commandlineflags & flags, const std::string & filename, throw; } catch ( std::exception & e ) { if ( !silentlog.str().empty() ) { - log << "errors loading '" << filename << "': " << silentlog.str() << std::endl; + log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding, silentlog.str() ) << lf; } else { - log << "errors loading '" << filename << "'" << std::endl; + log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << "error playing '" << filename << "': " << e.what() << std::endl; + log << MPT_USTRING("error playing '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { if ( !silentlog.str().empty() ) { - log << "errors loading '" << filename << "': " << silentlog.str() << std::endl; + log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::transcode( libopenmpt_encoding,silentlog.str() ) << lf; } else { - log << "errors loading '" << filename << "'" << std::endl; + log << MPT_USTRING("errors loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << "unknown error playing '" << filename << "'" << std::endl; + log << MPT_USTRING("unknown error playing '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log << std::endl; + log << lf; log.writeout(); } -static std::string get_random_filename( std::set & filenames, std::default_random_engine & prng ) { +static mpt::native_path get_random_filename( std::set & filenames, std::default_random_engine & prng ) { std::size_t index = std::uniform_int_distribution( 0, filenames.size() - 1 )( prng ); - std::set::iterator it = filenames.begin(); + std::set::iterator it = filenames.begin(); std::advance( it, index ); return *it; } @@ -1768,13 +1602,13 @@ static void render_files( commandlineflags & flags, textout & log, write_buffers while ( true ) { if ( flags.shuffle ) { // TODO: improve prev/next logic - std::set shuffle_set; + std::set shuffle_set; shuffle_set.insert( flags.filenames.begin(), flags.filenames.end() ); while ( true ) { if ( shuffle_set.empty() ) { break; } - std::string filename = get_random_filename( shuffle_set, prng ); + mpt::native_path filename = get_random_filename( shuffle_set, prng ); try { flags.playlist_index = std::find( flags.filenames.begin(), flags.filenames.end(), filename ) - flags.filenames.begin(); render_file( flags, filename, log, audio_stream ); @@ -1791,7 +1625,7 @@ static void render_files( commandlineflags & flags, textout & log, write_buffers } } } else { - std::vector::iterator filename = flags.filenames.begin(); + std::vector::iterator filename = flags.filenames.begin(); while ( true ) { if ( filename == flags.filenames.end() ) { break; @@ -1828,54 +1662,28 @@ static void render_files( commandlineflags & flags, textout & log, write_buffers } -static bool parse_playlist( commandlineflags & flags, std::string filename, std::ostream & log ) { - log.flush(); +static bool parse_playlist( commandlineflags & flags, mpt::native_path filename, concat_stream & log ) { bool is_playlist = false; bool m3u8 = false; - if ( ends_with( filename, ".m3u") || ends_with( filename, ".m3U") || ends_with( filename, ".M3u") || ends_with( filename, ".M3U") ) { + if ( get_extension( filename ) == MPT_NATIVE_PATH("m3u") || get_extension( filename ) == MPT_NATIVE_PATH("m3U") || get_extension( filename ) == MPT_NATIVE_PATH("M3u") || get_extension( filename ) == MPT_NATIVE_PATH("M3U") ) { is_playlist = true; } - if ( ends_with( filename, ".m3u8") || ends_with( filename, ".m3U8") || ends_with( filename, ".M3u8") || ends_with( filename, ".M3U8") ) { + if ( get_extension( filename ) == MPT_NATIVE_PATH("m3u8") || get_extension( filename ) == MPT_NATIVE_PATH("m3U8") || get_extension( filename ) == MPT_NATIVE_PATH("M3u8") || get_extension( filename ) == MPT_NATIVE_PATH("M3U8") ) { is_playlist = true; m3u8 = true; } - if ( ends_with( filename, ".pls") || ends_with( filename, ".plS") || ends_with( filename, ".pLs") || ends_with( filename, ".pLS") || ends_with( filename, ".Pls") || ends_with( filename, ".PlS") || ends_with( filename, ".PLs") || ends_with( filename, ".PLS") ) { + if ( get_extension( filename ) == MPT_NATIVE_PATH("pls") || get_extension( filename ) == MPT_NATIVE_PATH("plS") || get_extension( filename ) == MPT_NATIVE_PATH("pLs") || get_extension( filename ) == MPT_NATIVE_PATH("pLS") || get_extension( filename ) == MPT_NATIVE_PATH("Pls") || get_extension( filename ) == MPT_NATIVE_PATH("PlS") || get_extension( filename ) == MPT_NATIVE_PATH("PLs") || get_extension( filename ) == MPT_NATIVE_PATH("PLS") ) { is_playlist = true; } - std::string basepath = get_basepath( filename ); + mpt::native_path basepath = get_basepath( filename ); try { -#if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - std::istringstream file_stream; -#else - std::ifstream file_stream; -#endif - #if defined(WIN32) && defined(UNICODE) && !defined(_MSC_VER) - // Only MSVC has std::ifstream::ifstream(std::wstring). - // Fake it for other compilers using _wfopen(). - std::string data; - FILE * f = _wfopen( mpt::transcode( mpt::common_encoding::utf8, filename ).c_str(), L"rb" ); - if ( f ) { - while ( !feof( f ) ) { - static const std::size_t BUFFER_SIZE = 4096; - char buffer[BUFFER_SIZE]; - size_t data_read = fread( buffer, 1, BUFFER_SIZE, f ); - std::copy( buffer, buffer + data_read, std::back_inserter( data ) ); - } - fclose( f ); - f = NULL; - } - file_stream.str( data ); - #elif defined(_MSC_VER) && defined(UNICODE) - file_stream.open( mpt::transcode( mpt::common_encoding::utf8, filename ), std::ios::binary ); - #else - file_stream.open( filename, std::ios::binary ); - #endif + mpt::IO::ifstream file_stream( filename, std::ios::binary ); std::string line; bool first = true; bool extm3u = false; bool pls = false; while ( std::getline( file_stream, line ) ) { - std::string newfile; + mpt::native_path newfile; line = trim_eol( line ); if ( first ) { first = false; @@ -1889,46 +1697,45 @@ static bool parse_playlist( commandlineflags & flags, std::string filename, std: if ( line.empty() ) { continue; } + constexpr auto pls_encoding = mpt::common_encoding::utf8; + constexpr auto m3u8_encoding = mpt::common_encoding::utf8; +#if MPT_OS_WINDOWS + constexpr auto m3u_encoding = mpt::logical_encoding::locale; +#else + constexpr auto m3u_encoding = mpt::common_encoding::utf8; +#endif if ( pls ) { - if ( begins_with( line, "File" ) ) { + if ( mpt::starts_with( line, "File" ) ) { if ( line.find( "=" ) != std::string::npos ) { - flags.filenames.push_back( line.substr( line.find( "=" ) + 1 ) ); + flags.filenames.push_back( mpt::transcode( pls_encoding, line.substr( line.find( "=" ) + 1 ) ) ); } - } else if ( begins_with( line, "Title" ) ) { + } else if ( mpt::starts_with( line, "Title" ) ) { continue; - } else if ( begins_with( line, "Length" ) ) { + } else if ( mpt::starts_with( line, "Length" ) ) { continue; - } else if ( begins_with( line, "NumberOfEntries" ) ) { + } else if ( mpt::starts_with( line, "NumberOfEntries" ) ) { continue; - } else if ( begins_with( line, "Version" ) ) { + } else if ( mpt::starts_with( line, "Version" ) ) { continue; } else { continue; } } else if ( extm3u ) { - if ( begins_with( line, "#EXTINF" ) ) { + if ( mpt::starts_with( line, "#EXTINF" ) ) { continue; - } else if ( begins_with( line, "#" ) ) { + } else if ( mpt::starts_with( line, "#" ) ) { continue; } if ( m3u8 ) { - newfile = line; + newfile = mpt::transcode( m3u8_encoding, line ); } else { -#if defined(WIN32) - newfile = mpt::transcode( mpt::common_encoding::utf8, mpt::logical_encoding::locale, line ); -#else - newfile = line; -#endif + newfile = mpt::transcode( m3u_encoding, line ); } } else { if ( m3u8 ) { - newfile = line; + newfile = mpt::transcode( m3u8_encoding, line ); } else { -#if defined(WIN32) - newfile = mpt::transcode( mpt::common_encoding::utf8, mpt::logical_encoding::locale, line ); -#else - newfile = line; -#endif + newfile = mpt::transcode( m3u_encoding, line ); } } if ( !newfile.empty() ) { @@ -1939,25 +1746,34 @@ static bool parse_playlist( commandlineflags & flags, std::string filename, std: } } } catch ( std::exception & e ) { - log << "error loading '" << filename << "': " << e.what() << std::endl; + log << MPT_USTRING("error loading '") << mpt::transcode( filename ) << MPT_USTRING("': ") << mpt::get_exception_text( e ) << lf; } catch ( ... ) { - log << "unknown error loading '" << filename << "'" << std::endl; + log << MPT_USTRING("unknown error loading '") << mpt::transcode( filename ) << MPT_USTRING("'") << lf; } - log.flush(); return is_playlist; } -static commandlineflags parse_openmpt123( const std::vector & args, std::ostream & log ) { +static void parse_openmpt123( commandlineflags & flags, const std::vector & args, concat_stream & log ) { - log.flush(); + enum class action { + help, + help_keyboard, + man_version, + man_help, + version, + short_version, + long_version, + credits, + license, + }; + + std::optional return_action; if ( args.size() <= 1 ) { throw args_error_exception(); } - commandlineflags flags; - bool files_only = false; // cppcheck false-positive // cppcheck-suppress StlMissingComparison @@ -1966,117 +1782,149 @@ static commandlineflags parse_openmpt123( const std::vector & args, // skip program name continue; } - std::string arg = *i; - std::string nextarg = ( i+1 != args.end() ) ? *(i+1) : ""; + mpt::ustring arg = *i; + mpt::ustring nextarg = ( i+1 != args.end() ) ? *(i+1) : MPT_USTRING(""); if ( files_only ) { - flags.filenames.push_back( arg ); - } else if ( arg.substr( 0, 1 ) != "-" ) { - flags.filenames.push_back( arg ); + flags.filenames.push_back( mpt::transcode( arg ) ); + } else if ( arg.substr( 0, 1 ) != MPT_USTRING("-") ) { + flags.filenames.push_back( mpt::transcode( arg ) ); } else { - if ( arg == "--" ) { + if ( arg == MPT_USTRING("--") ) { files_only = true; - } else if ( arg == "-h" || arg == "--help" ) { - throw show_help_exception(); - } else if ( arg == "--help-keyboard" ) { - throw show_help_keyboard_exception(); - } else if ( arg == "-q" || arg == "--quiet" ) { + } else if ( arg == MPT_USTRING("-h") || arg == MPT_USTRING("--help") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::help; + } else if ( arg == MPT_USTRING("--help-keyboard") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::help_keyboard; + } else if ( arg == MPT_USTRING("--man-version") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::man_version; + } else if ( arg == MPT_USTRING("--man-help") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::man_help; + } else if ( arg == MPT_USTRING("--version") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::version; + } else if ( arg == MPT_USTRING("--short-version") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::short_version; + } else if ( arg == MPT_USTRING("--long-version") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::long_version; + } else if ( arg == MPT_USTRING("--credits") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::credits; + } else if ( arg == MPT_USTRING("--license") ) { + if ( return_action ) { + throw args_error_exception(); + } + return_action = action::license; + } else if ( arg == MPT_USTRING("-q") || arg == MPT_USTRING("--quiet") ) { flags.quiet = true; - } else if ( arg == "-v" || arg == "--verbose" ) { + } else if ( arg == MPT_USTRING("-v") || arg == MPT_USTRING("--verbose") ) { flags.verbose = true; - } else if ( arg == "--man-version" ) { - throw show_man_version_exception(); - } else if ( arg == "--man-help" ) { - throw show_man_help_exception(); - } else if ( arg == "--version" ) { - throw show_version_number_exception(); - } else if ( arg == "--short-version" ) { - throw show_short_version_number_exception(); - } else if ( arg == "--long-version" ) { - throw show_long_version_number_exception(); - } else if ( arg == "--credits" ) { - throw show_credits_exception(); - } else if ( arg == "--license" ) { - throw show_license_exception(); - } else if ( arg == "--probe" ) { + } else if ( arg == MPT_USTRING("--probe") ) { flags.mode = Mode::Probe; - } else if ( arg == "--info" ) { + } else if ( arg == MPT_USTRING("--info") ) { flags.mode = Mode::Info; - } else if ( arg == "--ui" ) { + } else if ( arg == MPT_USTRING("--ui") ) { flags.mode = Mode::UI; - } else if ( arg == "--batch" ) { + } else if ( arg == MPT_USTRING("--batch") ) { flags.mode = Mode::Batch; - } else if ( arg == "--render" ) { + } else if ( arg == MPT_USTRING("--render") ) { flags.mode = Mode::Render; - } else if ( arg == "--terminal-width" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.terminal_width; + } else if ( arg == MPT_USTRING("--assume-terminal") ) { + flags.assume_terminal = true; + } else if ( arg == MPT_USTRING("--banner") && nextarg != MPT_USTRING("") ) { + std::int8_t value = static_cast( flags.banner ); + mpt::parse_into( value, nextarg ); + flags.banner = static_cast( value ); ++i; - } else if ( arg == "--terminal-height" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.terminal_height; + } else if ( arg == MPT_USTRING("--terminal-width") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.terminal_width, nextarg ); ++i; - } else if ( arg == "--progress" ) { + } else if ( arg == MPT_USTRING("--terminal-height") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.terminal_height, nextarg ); + ++i; + } else if ( arg == MPT_USTRING("--progress") ) { flags.show_progress = true; - } else if ( arg == "--no-progress" ) { + } else if ( arg == MPT_USTRING("--no-progress") ) { flags.show_progress = false; - } else if ( arg == "--meters" ) { + } else if ( arg == MPT_USTRING("--meters") ) { flags.show_meters = true; - } else if ( arg == "--no-meters" ) { + } else if ( arg == MPT_USTRING("--no-meters") ) { flags.show_meters = false; - } else if ( arg == "--channel-meters" ) { + } else if ( arg == MPT_USTRING("--channel-meters") ) { flags.show_channel_meters = true; - } else if ( arg == "--no-channel-meters" ) { + } else if ( arg == MPT_USTRING("--no-channel-meters") ) { flags.show_channel_meters = false; - } else if ( arg == "--pattern" ) { + } else if ( arg == MPT_USTRING("--pattern") ) { flags.show_pattern = true; - } else if ( arg == "--no-pattern" ) { + } else if ( arg == MPT_USTRING("--no-pattern") ) { flags.show_pattern = false; - } else if ( arg == "--details" ) { + } else if ( arg == MPT_USTRING("--details") ) { flags.show_details = true; - } else if ( arg == "--no-details" ) { + } else if ( arg == MPT_USTRING("--no-details") ) { flags.show_details = false; - } else if ( arg == "--message" ) { + } else if ( arg == MPT_USTRING("--message") ) { flags.show_message = true; - } else if ( arg == "--no-message" ) { + } else if ( arg == MPT_USTRING("--no-message") ) { flags.show_message = false; - } else if ( arg == "--driver" && nextarg != "" ) { + } else if ( arg == MPT_USTRING("--driver") && nextarg != MPT_USTRING("") ) { if ( false ) { // nothing - } else if ( nextarg == "help" ) { - std::ostringstream drivers; - drivers << " Available drivers:" << std::endl; - drivers << " " << "default" << std::endl; + } else if ( nextarg == MPT_USTRING("help") ) { + string_concat_stream drivers; + drivers << MPT_USTRING(" Available drivers:") << lf; + drivers << MPT_USTRING(" default") << lf; #if defined( MPT_WITH_PULSEAUDIO ) - drivers << " " << "pulseaudio" << std::endl; + drivers << MPT_USTRING(" pulseaudio") << lf; #endif #if defined( MPT_WITH_SDL2 ) - drivers << " " << "sdl2" << std::endl; + drivers << MPT_USTRING(" sdl2") << lf; #endif #if defined( MPT_WITH_PORTAUDIO ) - drivers << " " << "portaudio" << std::endl; + drivers << MPT_USTRING(" portaudio") << lf; #endif -#if defined( WIN32 ) - drivers << " " << "waveout" << std::endl; +#if MPT_OS_WINDOWS + drivers << MPT_USTRING(" waveout") << lf; #endif #if defined( MPT_WITH_ALLEGRO42 ) - drivers << " " << "allegro42" << std::endl; + drivers << MPT_USTRING(" allegro42") << lf; #endif throw show_help_exception( drivers.str() ); - } else if ( nextarg == "default" ) { - flags.driver = ""; + } else if ( nextarg == MPT_USTRING("default") ) { + flags.driver = MPT_USTRING(""); } else { flags.driver = nextarg; } ++i; - } else if ( arg == "--device" && nextarg != "" ) { + } else if ( arg == MPT_USTRING("--device") && nextarg != MPT_USTRING("") ) { if ( false ) { // nothing - } else if ( nextarg == "help" ) { - std::ostringstream devices; - devices << " Available devices:" << std::endl; - devices << " " << "default" << ": " << "default" << std::endl; + } else if ( nextarg == MPT_USTRING("help") ) { + string_concat_stream devices; + devices << MPT_USTRING(" Available devices:") << lf; + devices << MPT_USTRING(" default: default") << lf; #if defined( MPT_WITH_PULSEAUDIO ) - devices << show_pulseaudio_devices( log ); + devices << show_pulseaudio_devices(log); #endif #if defined( MPT_WITH_SDL2 ) devices << show_sdl2_devices( log ); @@ -2084,114 +1932,94 @@ static commandlineflags parse_openmpt123( const std::vector & args, #if defined( MPT_WITH_PORTAUDIO ) devices << show_portaudio_devices( log ); #endif -#if defined( WIN32 ) +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT devices << show_waveout_devices( log ); #endif #if defined( MPT_WITH_ALLEGRO42 ) devices << show_allegro42_devices( log ); #endif throw show_help_exception( devices.str() ); - } else if ( nextarg == "default" ) { - flags.device = ""; + } else if ( nextarg == MPT_USTRING("default") ) { + flags.device = MPT_USTRING(""); } else { flags.device = nextarg; } ++i; - } else if ( arg == "--buffer" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.buffer; + } else if ( arg == MPT_USTRING("--buffer") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.buffer, nextarg ); ++i; - } else if ( arg == "--period" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.period; + } else if ( arg == MPT_USTRING("--period") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.period, nextarg ); ++i; - } else if ( arg == "--update" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.ui_redraw_interval; + } else if ( arg == MPT_USTRING("--update") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.ui_redraw_interval, nextarg ); ++i; - } else if ( arg == "--stdout" ) { + } else if ( arg == MPT_USTRING("--stdout") ) { flags.use_stdout = true; - } else if ( ( arg == "-o" || arg == "--output" ) && nextarg != "" ) { - flags.output_filename = nextarg; + } else if ( ( arg == MPT_USTRING("-o") || arg == MPT_USTRING("--output") ) && nextarg != MPT_USTRING("") ) { + flags.output_filename = mpt::transcode( nextarg ); ++i; - } else if ( arg == "--force" ) { + } else if ( arg == MPT_USTRING("--force") ) { flags.force_overwrite = true; - } else if ( arg == "--output-type" && nextarg != "" ) { - flags.output_extension = nextarg; + } else if ( arg == MPT_USTRING("--output-type") && nextarg != MPT_USTRING("") ) { + flags.output_extension = mpt::transcode( nextarg ); ++i; - } else if ( arg == "--samplerate" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.samplerate; + } else if ( arg == MPT_USTRING("--samplerate") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.samplerate, nextarg ); ++i; - } else if ( arg == "--channels" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.channels; + } else if ( arg == MPT_USTRING("--channels") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.channels, nextarg ); ++i; - } else if ( arg == "--float" ) { + } else if ( arg == MPT_USTRING("--float") ) { flags.use_float = true; - } else if ( arg == "--no-float" ) { + } else if ( arg == MPT_USTRING("--no-float") ) { flags.use_float = false; - } else if ( arg == "--gain" && nextarg != "" ) { - std::istringstream istr( nextarg ); + } else if ( arg == MPT_USTRING("--gain") && nextarg != MPT_USTRING("") ) { double gain = 0.0; - istr >> gain; - flags.gain = static_cast( gain * 100.0 ); + mpt::parse_into( gain, nextarg ); + flags.gain = mpt::saturate_round( gain * 100.0 ); ++i; - } else if ( arg == "--stereo" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.separation; + } else if ( arg == MPT_USTRING("--stereo") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.separation, nextarg ); ++i; - } else if ( arg == "--filter" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.filtertaps; + } else if ( arg == MPT_USTRING("--filter") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.filtertaps, nextarg ); ++i; - } else if ( arg == "--ramping" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.ramping; + } else if ( arg == MPT_USTRING("--ramping") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.ramping, nextarg ); ++i; - } else if ( arg == "--tempo" && nextarg != "" ) { - std::istringstream istr( nextarg ); - double tmp = 1.0; - istr >> tmp; - flags.tempo = double_to_tempo_flag( tmp ); + } else if ( arg == MPT_USTRING("--tempo") && nextarg != MPT_USTRING("") ) { + flags.tempo = double_to_tempo_flag( mpt::parse_or( nextarg, 1.0 ) ); ++i; - } else if ( arg == "--pitch" && nextarg != "" ) { - std::istringstream istr( nextarg ); - double tmp = 1.0; - istr >> tmp; - flags.pitch = double_to_pitch_flag( tmp ); + } else if ( arg == MPT_USTRING("--pitch") && nextarg != MPT_USTRING("") ) { + flags.pitch = double_to_pitch_flag( mpt::parse_or( nextarg, 1.0 ) ); ++i; - } else if ( arg == "--dither" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.dither; + } else if ( arg == MPT_USTRING("--dither") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.dither, nextarg ); ++i; - } else if ( arg == "--playlist" && nextarg != "" ) { - parse_playlist( flags, nextarg, log ); + } else if ( arg == MPT_USTRING("--playlist") && nextarg != MPT_USTRING("") ) { + parse_playlist( flags, mpt::transcode( nextarg ), log ); ++i; - } else if ( arg == "--randomize" ) { + } else if ( arg == MPT_USTRING("--randomize") ) { flags.randomize = true; - } else if ( arg == "--no-randomize" ) { + } else if ( arg == MPT_USTRING("--no-randomize") ) { flags.randomize = false; - } else if ( arg == "--shuffle" ) { + } else if ( arg == MPT_USTRING("--shuffle") ) { flags.shuffle = true; - } else if ( arg == "--no-shuffle" ) { + } else if ( arg == MPT_USTRING("--no-shuffle") ) { flags.shuffle = false; - } else if ( arg == "--restart" ) { + } else if ( arg == MPT_USTRING("--restart") ) { flags.restart = true; - } else if ( arg == "--no-restart" ) { + } else if ( arg == MPT_USTRING("--no-restart") ) { flags.restart = false; - } else if ( arg == "--subsong" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.subsong; + } else if ( arg == MPT_USTRING("--subsong") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.subsong, nextarg ); ++i; - } else if ( arg == "--repeat" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.repeatcount; + } else if ( arg == MPT_USTRING("--repeat") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.repeatcount, nextarg ); ++i; - } else if ( arg == "--ctl" && nextarg != "" ) { - std::istringstream istr( nextarg ); - std::string ctl_c_v; - istr >> ctl_c_v; + } else if ( arg == MPT_USTRING("--ctl") && nextarg != MPT_USTRING("") ) { + std::string ctl_c_v = mpt::transcode( libopenmpt_encoding, nextarg ); if ( ctl_c_v.find( "=" ) == std::string::npos ) { throw args_error_exception(); } @@ -2202,25 +2030,53 @@ static commandlineflags parse_openmpt123( const std::vector & args, } flags.ctls[ ctl ] = val; ++i; - } else if ( arg == "--seek" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.seek_target; + } else if ( arg == MPT_USTRING("--seek") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.seek_target, nextarg ); ++i; - } else if ( arg == "--end-time" && nextarg != "" ) { - std::istringstream istr( nextarg ); - istr >> flags.end_time; + } else if ( arg == MPT_USTRING("--end-time") && nextarg != MPT_USTRING("") ) { + mpt::parse_into( flags.end_time, nextarg ); ++i; - } else if ( arg.size() > 0 && arg.substr( 0, 1 ) == "-" ) { + } else if ( arg.size() > 0 && arg.substr( 0, 1 ) == MPT_USTRING("-") ) { throw args_error_exception(); } } } - return flags; + if ( return_action ) { + switch ( *return_action ) { + case action::help: + throw show_help_exception(); + break; + case action::help_keyboard: + throw show_help_keyboard_exception(); + break; + case action::man_version: + throw show_man_version_exception(); + break; + case action::man_help: + throw show_man_help_exception(); + break; + case action::version: + throw show_version_number_exception(); + break; + case action::short_version: + throw show_short_version_number_exception(); + break; + case action::long_version: + throw show_long_version_number_exception(); + break; + case action::credits: + throw show_credits_exception(); + break; + case action::license: + throw show_license_exception(); + break; + } + } } -#if defined(WIN32) +#if MPT_OS_WINDOWS class FD_utf8_raii { private: @@ -2239,7 +2095,7 @@ public: old_mode = _setmode( _fileno( file ), _O_TEXT ); #endif if ( old_mode == -1 ) { - throw exception( "failed to set TEXT mode on file descriptor" ); + throw exception( MPT_USTRING("failed to set TEXT mode on file descriptor") ); } } } @@ -2265,7 +2121,7 @@ public: fflush( file ); old_mode = _setmode( _fileno( file ), _O_BINARY ); if ( old_mode == -1 ) { - throw exception( "failed to set binary mode on file descriptor" ); + throw exception( MPT_USTRING("failed to set binary mode on file descriptor") ); } } } @@ -2280,27 +2136,45 @@ public: #endif -#if defined(WIN32) && defined(UNICODE) +#if MPT_OS_DJGPP +/* Work-around */ +/* clang-format off */ +extern "C" { + int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +} +/* clang-format on */ +#endif /* MPT_OS_DJGPP */ +#if MPT_OS_WINDOWS && defined(UNICODE) static int wmain( int wargc, wchar_t * wargv [] ) { #else static int main( int argc, char * argv [] ) { #endif - std::vector args; - #if defined(WIN32) && defined(UNICODE) + #if MPT_OS_DJGPP + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ + assert(mpt::platform::libc().is_ok()); + #endif /* MPT_OS_DJGPP */ + std::vector args; + #if MPT_OS_WINDOWS && defined(UNICODE) for ( int arg = 0; arg < wargc; ++arg ) { - args.push_back( mpt::transcode( mpt::common_encoding::utf8, wargv[arg] ) ); + args.push_back( mpt::transcode( wargv[arg] ) ); } #else - args = std::vector( argv, argv + argc ); + for ( int arg = 0; arg < argc; ++arg ) { + args.push_back( mpt::transcode( mpt::logical_encoding::locale, argv[arg] ) ); + } #endif -#if defined(WIN32) +#if MPT_OS_WINDOWS FD_utf8_raii stdin_utf8_guard( stdin, true ); FD_utf8_raii stdout_utf8_guard( stdout, true ); FD_utf8_raii stderr_utf8_guard( stderr, true ); #endif textout_dummy dummy_log; -#if defined(WIN32) +#if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) #if defined(UNICODE) textout_ostream_console std_out( std::wcout, STD_OUTPUT_HANDLE ); textout_ostream_console std_err( std::wclog, STD_ERROR_HANDLE ); @@ -2308,6 +2182,14 @@ static int main( int argc, char * argv [] ) { textout_ostream_console std_out( std::cout, STD_OUTPUT_HANDLE ); textout_ostream_console std_err( std::clog, STD_ERROR_HANDLE ); #endif +#elif MPT_OS_WINDOWS +#if defined(UNICODE) + textout_wostream std_out( std::wcout ); + textout_wostream std_err( std::wclog ); +#else + textout_ostream std_out( std::cout ); + textout_ostream std_err( std::clog ); +#endif #else textout_ostream std_out( std::cout ); textout_ostream std_err( std::clog ); @@ -2317,26 +2199,40 @@ static int main( int argc, char * argv [] ) { try { - flags = parse_openmpt123( args, std::cerr ); + parse_openmpt123( flags, args, std_err ); flags.check_and_sanitize(); - } catch ( args_error_exception & ) { + } catch ( args_nofiles_exception & ) { + show_banner( std_out, flags.banner ); show_help( std_out ); + std_out.writeout(); + return 0; + } catch ( args_error_exception & ) { + show_banner( std_out, flags.banner ); + show_help( std_out ); + std_out.writeout(); + if ( args.size() > 1 ) { + std_err << MPT_USTRING("Error parsing command line.") << lf; + std_err.writeout(); + } return 1; } catch ( show_man_help_exception & ) { - show_help( std_out, false, true, true ); + show_banner( std_out, flags.banner ); + show_help( std_out, true, true ); return 0; } catch ( show_man_version_exception & ) { show_man_version( std_out ); return 0; } catch ( show_help_exception & e ) { - show_help( std_out, true, e.longhelp, false, e.message ); + show_banner( std_out, flags.banner ); + show_help( std_out, e.longhelp, false, e.message ); if ( flags.verbose ) { - show_credits( std_out ); + show_credits( std_out, verbosity_hidden ); } return 0; } catch ( show_help_keyboard_exception & ) { + show_banner( std_out, flags.banner ); show_help_keyboard( std_out ); return 0; } catch ( show_long_version_number_exception & ) { @@ -2349,19 +2245,19 @@ static int main( int argc, char * argv [] ) { show_short_version( std_out ); return 0; } catch ( show_credits_exception & ) { - show_credits( std_out ); + show_credits( std_out, flags.banner ); return 0; } catch ( show_license_exception & ) { - show_license( std_out ); + show_license( std_out, flags.banner ); return 0; } catch ( silent_exit_exception & ) { return 0; } catch ( std::exception & e ) { - std_err << "error: " << e.what() << std::endl; + std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( ... ) { - std_err << "unknown error" << std::endl; + std_err << MPT_USTRING("unknown error") << lf; std_err.writeout(); return 1; } @@ -2370,7 +2266,7 @@ static int main( int argc, char * argv [] ) { bool stdin_can_ui = true; for ( const auto & filename : flags.filenames ) { - if ( filename == "-" ) { + if ( filename == MPT_NATIVE_PATH("-") ) { stdin_can_ui = false; break; } @@ -2382,17 +2278,17 @@ static int main( int argc, char * argv [] ) { } // set stdin binary -#if defined(WIN32) +#if MPT_OS_WINDOWS FD_binary_raii stdin_guard( stdin, !stdin_can_ui ); #endif // set stdout binary -#if defined(WIN32) +#if MPT_OS_WINDOWS FD_binary_raii stdout_guard( stdout, !stdout_can_ui ); #endif // setup terminal - #if !defined(WIN32) + #if !MPT_OS_WINDOWS if ( stdin_can_ui ) { if ( flags.mode == Mode::UI ) { set_input_mode(); @@ -2402,10 +2298,10 @@ static int main( int argc, char * argv [] ) { textout & log = flags.quiet ? static_cast( dummy_log ) : static_cast( stdout_can_ui ? std_out : std_err ); - show_info( log, flags.verbose ); + show_banner( log, flags.banner ); if ( !flags.warnings.empty() ) { - log << flags.warnings << std::endl; + log << flags.warnings << lf; } if ( flags.verbose ) { @@ -2447,42 +2343,42 @@ static int main( int argc, char * argv [] ) { file_audio_stream_raii file_audio_stream( flags, flags.output_filename, log ); render_files( flags, log, file_audio_stream, prng ); #if defined( MPT_WITH_PULSEAUDIO ) - } else if ( flags.driver == "pulseaudio" || flags.driver.empty() ) { + } else if ( flags.driver == MPT_USTRING("pulseaudio") || flags.driver.empty() ) { pulseaudio_stream_raii pulseaudio_stream( flags, log ); render_files( flags, log, pulseaudio_stream, prng ); #endif #if defined( MPT_WITH_SDL2 ) - } else if ( flags.driver == "sdl2" || flags.driver.empty() ) { + } else if ( flags.driver == MPT_USTRING("sdl2") || flags.driver.empty() ) { sdl2_stream_raii sdl2_stream( flags, log ); render_files( flags, log, sdl2_stream, prng ); #endif #if defined( MPT_WITH_PORTAUDIO ) - } else if ( flags.driver == "portaudio" || flags.driver.empty() ) { + } else if ( flags.driver == MPT_USTRING("portaudio") || flags.driver.empty() ) { portaudio_stream_raii portaudio_stream( flags, log ); render_files( flags, log, portaudio_stream, prng ); #endif -#if defined( WIN32 ) - } else if ( flags.driver == "waveout" || flags.driver.empty() ) { +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT + } else if ( flags.driver == MPT_USTRING("waveout") || flags.driver.empty() ) { waveout_stream_raii waveout_stream( flags ); render_files( flags, log, waveout_stream, prng ); #endif #if defined( MPT_WITH_ALLEGRO42 ) - } else if ( flags.driver == "allegro42" || flags.driver.empty() ) { + } else if ( flags.driver == MPT_USTRING("allegro42") || flags.driver.empty() ) { allegro42_stream_raii allegro42_stream( flags, log ); render_files( flags, log, allegro42_stream, prng ); #endif } else { if ( flags.driver.empty() ) { - throw exception( "openmpt123 is compiled without any audio driver" ); + throw exception( MPT_USTRING("openmpt123 is compiled without any audio driver") ); } else { - throw exception( "audio driver '" + flags.driver + "' not found" ); + throw exception( MPT_USTRING("audio driver '") + flags.driver + MPT_USTRING("' not found") ); } } } break; case Mode::Render: { for ( const auto & filename : flags.filenames ) { flags.apply_default_buffer_sizes(); - file_audio_stream_raii file_audio_stream( flags, filename + std::string(".") + flags.output_extension, log ); + file_audio_stream_raii file_audio_stream( flags, filename + MPT_NATIVE_PATH(".") + flags.output_extension, log ); render_file( flags, filename, log, file_audio_stream ); flags.playlist_index++; } @@ -2492,40 +2388,43 @@ static int main( int argc, char * argv [] ) { } } catch ( args_error_exception & ) { + show_banner( std_out, flags.banner ); show_help( std_out ); + std_err << MPT_USTRING("Error parsing command line.") << lf; + std_err.writeout(); return 1; #ifdef MPT_WITH_ALLEGRO42 } catch ( allegro42_exception & e ) { - std_err << "Allegro-4.2 error: " << e.what() << std::endl; + std_err << MPT_USTRING("Allegro-4.2 error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; #endif #ifdef MPT_WITH_PULSEAUDIO } catch ( pulseaudio_exception & e ) { - std_err << "PulseAudio error: " << e.what() << std::endl; + std_err << MPT_USTRING("PulseAudio error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; #endif #ifdef MPT_WITH_PORTAUDIO } catch ( portaudio_exception & e ) { - std_err << "PortAudio error: " << e.what() << std::endl; + std_err << MPT_USTRING("PortAudio error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; #endif #ifdef MPT_WITH_SDL2 } catch ( sdl2_exception & e ) { - std_err << "SDL2 error: " << e.what() << std::endl; + std_err << MPT_USTRING("SDL2 error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; #endif } catch ( silent_exit_exception & ) { return 0; } catch ( std::exception & e ) { - std_err << "error: " << e.what() << std::endl; + std_err << MPT_USTRING("error: ") << mpt::get_exception_text( e ) << lf; std_err.writeout(); return 1; } catch ( ... ) { - std_err << "unknown error" << std::endl; + std_err << MPT_USTRING("unknown error") << lf; std_err.writeout(); return 1; } @@ -2535,7 +2434,7 @@ static int main( int argc, char * argv [] ) { } // namespace openmpt123 -#if defined(WIN32) && defined(UNICODE) +#if MPT_OS_WINDOWS && defined(UNICODE) #if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) // mingw64 does only default to special C linkage for "main", but not for "wmain". extern "C" int wmain( int wargc, wchar_t * wargv [] ); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp index 3e80ca1ec..f585915d8 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.hpp @@ -13,48 +13,138 @@ #include "openmpt123_config.hpp" #include "mpt/base/compiletime_warning.hpp" +#include "mpt/base/detect.hpp" #include "mpt/base/floatingpoint.hpp" +#include "mpt/base/math.hpp" +#include "mpt/base/namespace.hpp" #include "mpt/base/preprocessor.hpp" +#include "mpt/base/saturate_round.hpp" +#include "mpt/exception/exception_text.hpp" +#include "mpt/format/concat.hpp" +#include "mpt/format/message.hpp" +#include "mpt/format/message_macros.hpp" +#include "mpt/format/simple.hpp" +#include "mpt/io_file/fstream.hpp" +#include "mpt/parse/parse.hpp" +#include "mpt/path/native_path.hpp" +#include "mpt/string/types.hpp" +#include "mpt/string/utility.hpp" #include "mpt/string_transcode/transcode.hpp" #include +namespace mpt { +inline namespace MPT_INLINE_NS { + +template <> +struct make_string_type { + using type = mpt::native_path; +}; + + +template <> +struct is_string_type : public std::true_type { }; + +template <> +struct string_transcoder { + using string_type = mpt::native_path; + static inline mpt::widestring decode( const string_type & src ) { + return mpt::transcode( src.AsNative() ); + } + static inline string_type encode( const mpt::widestring & src ) { + return mpt::native_path::FromNative( mpt::transcode( src ) ); + } +}; + +} // namespace MPT_INLINE_NS +} // namespace mpt + namespace openmpt123 { struct exception : public openmpt::exception { - exception( const std::string & text ) : openmpt::exception(text) { } + exception( const mpt::ustring & text ) : openmpt::exception(mpt::transcode( mpt::common_encoding::utf8, text )) { } }; struct show_help_exception { - std::string message; + mpt::ustring message; bool longhelp; - show_help_exception( const std::string & msg = "", bool longhelp_ = true ) : message(msg), longhelp(longhelp_) { } + show_help_exception( const mpt::ustring & msg = MPT_USTRING(""), bool longhelp_ = true ) : message(msg), longhelp(longhelp_) { } +}; + +struct args_nofiles_exception { + args_nofiles_exception() = default; }; struct args_error_exception { - args_error_exception() { } + args_error_exception() = default; }; struct show_help_keyboard_exception { }; -#if defined(WIN32) + +template +inline Tstring align_right( const Tchar pad, std::size_t width, const T val ) { + assert( Tstring( 1, pad ).length() == 1 ); + Tstring str = mpt::default_formatter::template format( val ); + if ( width > str.length() ) { + str.insert( str.begin(), width - str.length(), pad ); + } + return str; +} + +template +struct concat_stream { + virtual concat_stream & append( Tstring str ) = 0; + virtual ~concat_stream() = default; + inline concat_stream & operator<<( concat_stream & (*func)( concat_stream & s ) ) { + return func( *this ); + } +}; + +template +inline concat_stream & lf( concat_stream & s ) { + return s.append( Tstring(1, mpt::char_constants::lf) ); +} + +template +inline concat_stream & operator<<( concat_stream & s, const T & val ) { + return s.append( mpt::default_formatter::template format( val ) ); +} + +template +struct string_concat_stream + : public concat_stream +{ +private: + Tstring m_str; +public: + inline void str( Tstring s ) { + m_str = std::move( s ); + } + inline concat_stream & append( Tstring s ) override { + m_str += std::move( s ); + return *this; + } + inline Tstring str() const { + return m_str; + } + ~string_concat_stream() override = default; +}; + + +struct field { + mpt::ustring key; + mpt::ustring val; +}; + + +#if MPT_OS_WINDOWS bool IsConsole( DWORD stdHandle ); #endif bool IsTerminal( int fd ); - -struct field { - std::string key; - std::string val; - field( const std::string & key ) - : key(key) - { - return; - } -}; - -class textout : public std::ostringstream { +class textout : public string_concat_stream { public: textout() { return; @@ -63,9 +153,9 @@ public: return; } protected: - std::string pop() { - std::string text = str(); - str(std::string()); + mpt::ustring pop() { + mpt::ustring text = str(); + str( mpt::ustring() ); return text; } public: @@ -92,17 +182,17 @@ public: class textout_ostream : public textout { private: std::ostream & s; -#if defined(__DJGPP__) +#if MPT_OS_DJGPP mpt::common_encoding codepage; #endif public: textout_ostream( std::ostream & s_ ) : s(s_) -#if defined(__DJGPP__) +#if MPT_OS_DJGPP , codepage(mpt::common_encoding::cp437) #endif { - #if defined(__DJGPP__) + #if MPT_OS_DJGPP codepage = mpt::djgpp_get_locale_encoding(); #endif return; @@ -112,14 +202,14 @@ public: } private: void writeout_impl() { - std::string text = pop(); + mpt::ustring text = pop(); if ( text.length() > 0 ) { - #if defined(__DJGPP__) - s << mpt::transcode( codepage, mpt::common_encoding::utf8, text ); - #elif defined(__EMSCRIPTEN__) - s << text; + #if MPT_OS_DJGPP + s << mpt::transcode( codepage, text ); + #elif MPT_OS_EMSCRIPTEN + s << mpt::transcode( mpt::common_encoding::utf8, text ) ; #else - s << mpt::transcode( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text ); + s << mpt::transcode( mpt::logical_encoding::locale, text ); #endif s.flush(); } @@ -131,12 +221,48 @@ public: void cursor_up( std::size_t lines ) override { s.flush(); for ( std::size_t line = 0; line < lines; ++line ) { - *this << "\x1b[1A"; + *this << MPT_USTRING("\x1b[1A"); } } }; -#if defined(WIN32) +#if MPT_OS_WINDOWS && defined(UNICODE) + +class textout_wostream : public textout { +private: + std::wostream & s; +public: + textout_wostream( std::wostream & s_ ) + : s(s_) + { + return; + } + virtual ~textout_wostream() { + writeout_impl(); + } +private: + void writeout_impl() { + mpt::ustring text = pop(); + if ( text.length() > 0 ) { + s << mpt::transcode( text ); + s.flush(); + } + } +public: + void writeout() override { + writeout_impl(); + } + void cursor_up( std::size_t lines ) override { + s.flush(); + for ( std::size_t line = 0; line < lines; ++line ) { + *this << MPT_USTRING("\x1b[1A"); + } + } +}; + +#endif // MPT_OS_WINDOWS && UNICODE + +#if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) class textout_ostream_console : public textout { private: @@ -164,22 +290,22 @@ public: } private: void writeout_impl() { - std::string text = pop(); + mpt::ustring text = pop(); if ( text.length() > 0 ) { if ( console ) { DWORD chars_written = 0; #if defined(UNICODE) - std::wstring wtext = mpt::transcode( mpt::common_encoding::utf8, text ); + std::wstring wtext = mpt::transcode( text ); WriteConsole( handle, wtext.data(), static_cast( wtext.size() ), &chars_written, NULL ); #else - std::string ltext = mpt::transcode( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text ); + std::string ltext = mpt::transcode( mpt::logical_encoding::locale, text ); WriteConsole( handle, ltext.data(), static_cast( ltext.size() ), &chars_written, NULL ); #endif } else { #if defined(UNICODE) - s << mpt::transcode( mpt::common_encoding::utf8, text ); + s << mpt::transcode( text ); #else - s << mpt::transcode( mpt::logical_encoding::locale, mpt::common_encoding::utf8, text ); + s << mpt::transcode( mpt::logical_encoding::locale, text ); #endif s.flush(); } @@ -205,39 +331,43 @@ public: } }; -#endif // WIN32 +#endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) -static inline float mpt_round( float val ) { - if ( val >= 0.0f ) { - return std::floor( val + 0.5f ); - } else { - return std::ceil( val - 0.5f ); - } -} - -static inline long mpt_lround( float val ) { - return static_cast< long >( mpt_round( val ) ); -} - -static inline std::string append_software_tag( std::string software ) { - std::string openmpt123 = std::string() + "openmpt123 " + OPENMPT123_VERSION_STRING + " (libopenmpt " + openmpt::string::get( "library_version" ) + ", OpenMPT " + openmpt::string::get( "core_version" ) + ")"; +inline mpt::ustring append_software_tag( mpt::ustring software ) { + mpt::ustring openmpt123 = mpt::ustring() + + MPT_USTRING("openmpt123 ") + + mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) + + MPT_USTRING(" (libopenmpt ") + + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "library_version" ) ) + + MPT_USTRING(", OpenMPT ") + + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "core_version" ) ) + + MPT_USTRING(")") + ; if ( software.empty() ) { software = openmpt123; } else { - software += " (via " + openmpt123 + ")"; + software += MPT_USTRING(" (via ") + openmpt123 + MPT_USTRING(")"); } return software; } -static inline std::string get_encoder_tag() { - return std::string() + "openmpt123 " + OPENMPT123_VERSION_STRING + " (libopenmpt " + openmpt::string::get( "library_version" ) + ", OpenMPT " + openmpt::string::get( "core_version" ) + ")"; +inline mpt::ustring get_encoder_tag() { + return mpt::ustring() + + MPT_USTRING("openmpt123 ") + + mpt::transcode( mpt::source_encoding, OPENMPT123_VERSION_STRING ) + + MPT_USTRING(" (libopenmpt ") + + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "library_version" ) ) + + MPT_USTRING(", OpenMPT ") + + mpt::transcode( mpt::common_encoding::utf8, openmpt::string::get( "core_version" ) ) + + MPT_USTRING(")"); } -static inline std::string get_extension( std::string filename ) { - if ( filename.find_last_of( "." ) != std::string::npos ) { - return filename.substr( filename.find_last_of( "." ) + 1 ); +inline mpt::native_path get_extension( mpt::native_path filename ) { + mpt::native_path tmp = filename.GetFilenameExtension(); + if ( !tmp.empty() ) { + tmp = mpt::native_path::FromNative( tmp.AsNative().substr( 1 ) ); } - return ""; + return tmp; } enum class Mode { @@ -249,28 +379,33 @@ enum class Mode { Render }; -static inline std::string mode_to_string( Mode mode ) { +inline mpt::ustring mode_to_string( Mode mode ) { switch ( mode ) { - case Mode::None: return "none"; break; - case Mode::Probe: return "probe"; break; - case Mode::Info: return "info"; break; - case Mode::UI: return "ui"; break; - case Mode::Batch: return "batch"; break; - case Mode::Render: return "render"; break; + case Mode::None: return MPT_USTRING("none"); break; + case Mode::Probe: return MPT_USTRING("probe"); break; + case Mode::Info: return MPT_USTRING("info"); break; + case Mode::UI: return MPT_USTRING("ui"); break; + case Mode::Batch: return MPT_USTRING("batch"); break; + case Mode::Render: return MPT_USTRING("render"); break; } - return ""; + return MPT_USTRING(""); } -static const std::int32_t default_low = -2; -static const std::int32_t default_high = -1; +inline const std::int32_t default_low = -2; +inline const std::int32_t default_high = -1; + +enum verbosity : std::int8_t { + verbosity_shortversion = -1, + verbosity_hidden = 0, + verbosity_normal = 1, + verbosity_verbose = 2, +}; struct commandlineflags { Mode mode; - bool canUI; std::int32_t ui_redraw_interval; - bool canProgress; - std::string driver; - std::string device; + mpt::ustring driver; + mpt::ustring device; std::int32_t buffer; std::int32_t period; std::int32_t samplerate; @@ -288,7 +423,9 @@ struct commandlineflags { double seek_target; double end_time; bool quiet; + verbosity banner; bool verbose; + bool assume_terminal; int terminal_width; int terminal_height; bool show_details; @@ -304,12 +441,12 @@ struct commandlineflags { bool shuffle; bool restart; std::size_t playlist_index; - std::vector filenames; - std::string output_filename; - std::string output_extension; + std::vector filenames; + mpt::native_path output_filename; + mpt::native_path output_extension; bool force_overwrite; bool paused; - std::string warnings; + mpt::ustring warnings; void apply_default_buffer_sizes() { if ( ui_redraw_interval == default_high ) { ui_redraw_interval = 50; @@ -330,11 +467,11 @@ struct commandlineflags { commandlineflags() { mode = Mode::UI; ui_redraw_interval = default_high; - driver = ""; - device = ""; + driver = MPT_USTRING(""); + device = MPT_USTRING(""); buffer = default_high; period = default_high; -#if defined(__DJGPP__) +#if MPT_OS_DJGPP samplerate = 44100; channels = 2; use_float = false; @@ -355,15 +492,17 @@ struct commandlineflags { seek_target = 0.0; end_time = 0.0; quiet = false; + banner = verbosity_normal; verbose = false; -#if defined(__DJGPP__) + assume_terminal = false; +#if MPT_OS_DJGPP terminal_width = 80; terminal_height = 25; #else terminal_width = 72; terminal_height = 23; #endif -#if defined(WIN32) +#if MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) terminal_width = 72; terminal_height = 23; HANDLE hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE ); @@ -375,22 +514,18 @@ struct commandlineflags { terminal_height = std::min( static_cast( 1 + csbi.srWindow.Bottom - csbi.srWindow.Top ), static_cast( csbi.dwSize.Y ) ); } } -#else // WIN32 +#else // !(MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10)) if ( isatty( STDERR_FILENO ) ) { const char * env_columns = std::getenv( "COLUMNS" ); if ( env_columns ) { - std::istringstream istr( env_columns ); - int tmp = 0; - istr >> tmp; + int tmp = mpt::parse_or( env_columns, 0 ); if ( tmp > 0 ) { terminal_width = tmp; } } const char * env_rows = std::getenv( "ROWS" ); if ( env_rows ) { - std::istringstream istr( env_rows ); - int tmp = 0; - istr >> tmp; + int tmp = mpt::parse_or( env_rows, 0 ); if ( tmp > 0 ) { terminal_height = tmp; } @@ -409,19 +544,12 @@ struct commandlineflags { } #endif } -#endif +#endif // MPT_OS_WINDOWS && !MPT_WINRT_BEFORE(MPT_WIN_10) show_details = true; show_message = false; -#if defined(WIN32) - canUI = IsTerminal( 0 ) ? true : false; - canProgress = IsTerminal( 2 ) ? true : false; -#else // !WIN32 - canUI = isatty( STDIN_FILENO ) ? true : false; - canProgress = isatty( STDERR_FILENO ) ? true : false; -#endif // WIN32 - show_ui = canUI; - show_progress = canProgress; - show_meters = canUI && canProgress; + show_ui = true; + show_progress = true; + show_meters = true; show_channel_meters = false; show_pattern = false; use_stdout = false; @@ -429,13 +557,24 @@ struct commandlineflags { shuffle = false; restart = false; playlist_index = 0; - output_extension = "auto"; + output_extension = MPT_NATIVE_PATH("auto"); force_overwrite = false; paused = false; } void check_and_sanitize() { + bool canUI = true; + bool canProgress = true; + if ( !assume_terminal ) { +#if MPT_OS_WINDOWS + canUI = IsTerminal( 0 ) ? true : false; + canProgress = IsTerminal( 2 ) ? true : false; +#else // !MPT_OS_WINDOWS + canUI = isatty( STDIN_FILENO ) ? true : false; + canProgress = isatty( STDERR_FILENO ) ? true : false; +#endif // MPT_OS_WINDOWS + } if ( filenames.size() == 0 ) { - throw args_error_exception(); + throw args_nofiles_exception(); } if ( use_stdout && ( device != commandlineflags().device || !output_filename.empty() ) ) { throw args_error_exception(); @@ -444,11 +583,17 @@ struct commandlineflags { throw args_error_exception(); } for ( const auto & filename : filenames ) { - if ( filename == "-" ) { + if ( filename == MPT_NATIVE_PATH("-") ) { canUI = false; } } show_ui = canUI; + if ( !canProgress ) { + show_progress = false; + } + if ( !canUI || !canProgress ) { + show_meters = false; + } if ( mode == Mode::None ) { if ( canUI ) { mode = Mode::UI; @@ -510,8 +655,8 @@ struct commandlineflags { if ( samplerate < 0 ) { samplerate = commandlineflags().samplerate; } - if ( output_extension == "auto" ) { - output_extension = ""; + if ( output_extension == MPT_NATIVE_PATH("auto") ) { + output_extension = MPT_NATIVE_PATH(""); } if ( mode != Mode::Render && !output_extension.empty() ) { throw args_error_exception(); @@ -523,7 +668,7 @@ struct commandlineflags { output_extension = get_extension( output_filename ); } if ( output_extension.empty() ) { - output_extension = "wav"; + output_extension = MPT_NATIVE_PATH("wav"); } } }; @@ -545,11 +690,11 @@ protected: return; } public: - virtual void write_metadata( std::map metadata ) { + virtual void write_metadata( std::map metadata ) { (void)metadata; return; } - virtual void write_updated_metadata( std::map metadata ) { + virtual void write_updated_metadata( std::map metadata ) { (void)metadata; return; } @@ -707,11 +852,11 @@ protected: return; } public: - void write_metadata( std::map metadata ) override { + void write_metadata( std::map metadata ) override { (void)metadata; return; } - void write_updated_metadata( std::map metadata ) override { + void write_updated_metadata( std::map metadata ) override { (void)metadata; return; } diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.manifest b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.manifest new file mode 100644 index 000000000..3652b77cd --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123.manifest @@ -0,0 +1,8 @@ + + + + diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_allegro42.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_allegro42.hpp index a0979eaac..0e3d8dc45 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_allegro42.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_allegro42.hpp @@ -19,6 +19,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wfloat-conversion" +#pragma GCC diagnostic ignored "-Wdouble-promotion" #endif #include #if defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER) @@ -27,12 +28,14 @@ namespace openmpt123 { +inline constexpr auto allegro42_encoding = mpt::logical_encoding::locale; + struct allegro42_exception : public exception { - static std::string error_to_string() { + static mpt::ustring error_to_string() { try { - return std::string( allegro_error ); + return mpt::transcode( allegro42_encoding, std::string( allegro_error ) ); } catch ( const std::bad_alloc & ) { - return std::string(); + return mpt::ustring(); } } allegro42_exception() @@ -61,7 +64,7 @@ public: } if ( digi_card == DIGI_NONE ) { remove_sound(); - throw exception( "no audio device found" ); + throw exception( MPT_USTRING("no audio device found") ); } } ~allegro42_sound_raii() { @@ -87,7 +90,7 @@ private: return result; } public: - allegro42_stream_raii( commandlineflags & flags, std::ostream & log ) + allegro42_stream_raii( commandlineflags & flags, concat_stream & log ) : write_buffers_polling_wrapper_int(flags) , stream(NULL) , bits(16) @@ -95,10 +98,10 @@ public: , period_frames(1024) { if ( flags.use_float ) { - throw exception( "floating point is unsupported" ); + throw exception( MPT_USTRING("floating point is unsupported") ); } if ( ( flags.channels != 1 ) && ( flags.channels != 2 ) ) { - throw exception( "only mono or stereo supported" ); + throw exception( MPT_USTRING("only mono or stereo supported") ); } if ( flags.buffer == default_high ) { flags.buffer = 1024 * 2 * 1000 / flags.samplerate; @@ -114,12 +117,12 @@ public: period_frames = round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ); set_queue_size_frames( period_frames ); if ( flags.verbose ) { - log << "Allegro-4.2:" << std::endl; - log << " allegro samplerate: " << get_mixer_frequency() << std::endl; - log << " latency: " << flags.buffer << std::endl; - log << " period: " << flags.period << std::endl; - log << " frames per buffer: " << period_frames << std::endl; - log << " ui redraw: " << flags.ui_redraw_interval << std::endl; + log << MPT_USTRING("Allegro-4.2:") << lf; + log << MPT_USTRING(" allegro samplerate: ") << get_mixer_frequency() << lf; + log << MPT_USTRING(" latency: ") << flags.buffer << lf; + log << MPT_USTRING(" period: ") << flags.period << lf; + log << MPT_USTRING(" frames per buffer: ") << period_frames << lf; + log << MPT_USTRING(" ui redraw: ") << flags.ui_redraw_interval << lf; } stream = play_audio_stream( period_frames, 16, ( flags.channels > 1 ) ? TRUE : FALSE, flags.samplerate, 255, 128 ); if ( !stream ) { @@ -171,10 +174,10 @@ public: } }; -static std::string show_allegro42_devices( std::ostream & /* log */ ) { - std::ostringstream devices; - devices << " allegro42:" << std::endl; - devices << " " << "0" << ": Default Device" << std::endl; +static mpt::ustring show_allegro42_devices( concat_stream & /* log */ ) { + string_concat_stream devices; + devices << MPT_USTRING(" allegro42:") << lf; + devices << MPT_USTRING(" ") << MPT_USTRING("0") << MPT_USTRING(": Default Device") << lf; return devices.str(); } diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_config.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_config.hpp index fd242f1d3..e1abca65f 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_config.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_config.hpp @@ -12,53 +12,6 @@ #define MPT_INLINE_NS mpt_openmpt123 -#if defined(_WIN32) -#ifndef WIN32 -#define WIN32 -#endif -#endif // _WIN32 - -#if defined(WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#ifdef _UNICODE -#ifndef UNICODE -#define UNICODE -#endif -#endif -#ifdef UNICODE -#ifndef _UNICODE -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreserved-id-macro" -#endif -#define _UNICODE -#if defined(__clang__) -#pragma clang diagnostic pop -#endif -#endif -#endif -#endif // WIN32 - -#if defined(WIN32) -#define MPT_WITH_MMIO -#endif // WIN32 - -#if defined(MPT_BUILD_MSVC) - -#define MPT_WITH_FLAC -#define MPT_WITH_PORTAUDIO - -#if defined(MPT_BUILD_MSVC_STATIC) -#define FLAC__NO_DLL -#endif - -#endif // MPT_BUILD_MSVC - #define OPENMPT123_VERSION_STRING OPENMPT_API_VERSION_STRING #endif // OPENMPT123_CONFIG_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_flac.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_flac.hpp index 969c6530d..597913fd3 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_flac.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_flac.hpp @@ -15,6 +15,9 @@ #if defined(MPT_WITH_FLAC) +#include "mpt/base/detect.hpp" +#include "mpt/base/saturate_round.hpp" + #if defined(_MSC_VER) && defined(__clang__) && defined(__c2__) #include #if __STDC__ @@ -33,11 +36,13 @@ typedef _off_t off_t; #endif namespace openmpt123 { - + +inline constexpr auto flac_encoding = mpt::common_encoding::utf8; + class flac_stream_raii : public file_audio_stream_base { private: commandlineflags flags; - std::string filename; + mpt::native_path filename; bool called_init; std::vector< std::pair< std::string, std::string > > tags; FLAC__StreamMetadata * flac_metadata[1]; @@ -51,11 +56,11 @@ private: } } public: - flac_stream_raii( const std::string & filename_, const commandlineflags & flags_, std::ostream & /*log*/ ) : flags(flags_), filename(filename_), called_init(false), encoder(0) { + flac_stream_raii( const mpt::native_path & filename_, const commandlineflags & flags_, concat_stream & /*log*/ ) : flags(flags_), filename(filename_), called_init(false), encoder(0) { flac_metadata[0] = 0; encoder = FLAC__stream_encoder_new(); if ( !encoder ) { - throw exception( "error creating flac encoder" ); + throw exception( MPT_USTRING("error creating flac encoder") ); } FLAC__stream_encoder_set_channels( encoder, flags.channels ); FLAC__stream_encoder_set_bits_per_sample( encoder, flags.use_float ? 24 : 16 ); @@ -73,25 +78,25 @@ public: flac_metadata[0] = 0; } } - void write_metadata( std::map metadata ) override { + void write_metadata( std::map metadata ) override { if ( called_init ) { return; } tags.clear(); - tags.push_back( std::make_pair( "TITLE", metadata[ "title" ] ) ); - tags.push_back( std::make_pair( "ARTIST", metadata[ "artist" ] ) ); - tags.push_back( std::make_pair( "DATE", metadata[ "date" ] ) ); - tags.push_back( std::make_pair( "COMMENT", metadata[ "message" ] ) ); - if ( !metadata[ "type" ].empty() && !metadata[ "tracker" ].empty() ) { - tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + metadata[ "type" ] + "' tracked music file, made with '" + metadata[ "tracker" ] + "', rendered with '" + get_encoder_tag() + "'" ) ); - } else if ( !metadata[ "type_long" ].empty() ) { - tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + metadata[ "type" ] + "' tracked music file, rendered with '" + get_encoder_tag() + "'" ) ); - } else if ( !metadata[ "tracker" ].empty() ) { - tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, made with '" + metadata[ "tracker" ] + "', rendered with '" + get_encoder_tag() + "'" ) ); + tags.push_back( std::make_pair( "TITLE", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("title") ] ) ) ); + tags.push_back( std::make_pair( "ARTIST", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("artist") ] ) ) ); + tags.push_back( std::make_pair( "DATE", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("date") ] ) ) ); + tags.push_back( std::make_pair( "COMMENT", mpt::transcode( flac_encoding, metadata[ MPT_USTRING("message") ] ) ) ); + if ( !metadata[ MPT_USTRING("type") ].empty() && !metadata[ MPT_USTRING("tracker") ].empty() ) { + tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("type") ] ) + "' tracked music file, made with '" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("tracker") ] ) + "', rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); + } else if ( !metadata[ MPT_USTRING("type_long") ].empty() ) { + tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "'" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("type") ] ) + "' tracked music file, rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); + } else if ( !metadata[ MPT_USTRING("tracker") ].empty() ) { + tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, made with '" + mpt::transcode( flac_encoding, metadata[ MPT_USTRING("tracker") ] ) + "', rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } else { - tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, rendered with '" + get_encoder_tag() + "'" ) ); + tags.push_back( std::make_pair( "SOURCEMEDIA", std::string() + "tracked music file, rendered with '" + mpt::transcode( flac_encoding, get_encoder_tag() ) + "'" ) ); } - tags.push_back( std::make_pair( "ENCODER", get_encoder_tag() ) ); + tags.push_back( std::make_pair( "ENCODER", mpt::transcode( flac_encoding, get_encoder_tag() ) ) ); flac_metadata[0] = FLAC__metadata_object_new( FLAC__METADATA_TYPE_VORBIS_COMMENT ); for ( std::vector< std::pair< std::string, std::string > >::iterator tag = tags.begin(); tag != tags.end(); ++tag ) { add_vorbiscomment_field( flac_metadata[0], tag->first, tag->second ); @@ -100,7 +105,11 @@ public: } void write( const std::vector buffers, std::size_t frames ) override { if ( !called_init ) { - FLAC__stream_encoder_init_file( encoder, filename.c_str(), NULL, 0 ); +#if MPT_OS_WINDOWS + FLAC__stream_encoder_init_file( encoder, mpt::transcode( flac_encoding, filename ).c_str(), NULL, 0 ); +#else + FLAC__stream_encoder_init_file( encoder, filename.AsNative().c_str(), NULL, 0 ); +#endif called_init = true; } interleaved_buffer.clear(); @@ -112,7 +121,7 @@ public: } else if ( in >= 1.0f ) { in = 1.0f; } - FLAC__int32 out = mpt_lround( in * (1<<23) ); + FLAC__int32 out = mpt::saturate_round( in * (1<<23) ); out = std::max( 0 - (1<<23), out ); out = std::min( out, 0 + (1<<23) - 1 ); interleaved_buffer.push_back( out ); @@ -122,7 +131,11 @@ public: } void write( const std::vector buffers, std::size_t frames ) override { if ( !called_init ) { - FLAC__stream_encoder_init_file( encoder, filename.c_str(), NULL, 0 ); +#if MPT_OS_WINDOWS + FLAC__stream_encoder_init_file( encoder, mpt::transcode( flac_encoding, filename ).c_str(), NULL, 0 ); +#else + FLAC__stream_encoder_init_file( encoder, filename.AsNative().c_str(), NULL, 0 ); +#endif called_init = true; } interleaved_buffer.clear(); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_mmio.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_mmio.hpp index 24cd4784e..7e47a9555 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_mmio.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_mmio.hpp @@ -13,13 +13,15 @@ #include "openmpt123_config.hpp" #include "openmpt123.hpp" -#if defined(MPT_WITH_MMIO) +#include "mpt/base/detect.hpp" + +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT namespace openmpt123 { class mmio_stream_raii : public file_audio_stream_base { private: - std::ostream & log; + concat_stream & log; commandlineflags flags; WAVEFORMATEX waveformatex; HMMIO mmio; @@ -30,16 +32,16 @@ private: private: void CHECKED( HRESULT err ) { if ( err != 0 ) { - throw exception( "error writing wave file" ); + throw exception( MPT_USTRING("error writing wave file") ); } } void UNCHECKED( HRESULT err ) { if ( err != 0 ) { - log << "error writing wave file" << std::endl; + log << MPT_USTRING("error writing wave file") << lf; } } public: - mmio_stream_raii( const std::string & filename, const commandlineflags & flags_, std::ostream & log_ ) : log(log_), flags(flags_), mmio(NULL) { + mmio_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & log_ ) : log(log_), flags(flags_), mmio(NULL) { ZeroMemory( &waveformatex, sizeof( WAVEFORMATEX ) ); waveformatex.cbSize = 0; @@ -50,13 +52,13 @@ public: waveformatex.nBlockAlign = static_cast( flags.channels * ( waveformatex.wBitsPerSample / 8 ) ); waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign; - #if defined(WIN32) && defined(UNICODE) - wchar_t * tmp = _wcsdup( mpt::transcode( mpt::common_encoding::utf8, filename ).c_str() ); + #if defined(UNICODE) + wchar_t * tmp = _wcsdup( filename.AsNative().c_str() ); mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE ); free( tmp ); tmp = 0; #else - char * tmp = strdup( filename.c_str() ); + char * tmp = strdup( filename.AsNative().c_str() ); mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE ); free( tmp ); tmp = 0; @@ -128,6 +130,6 @@ public: } // namespace openmpt123 -#endif // MPT_WITH_MMIO +#endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT #endif // OPENMPT123_MMIO_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_portaudio.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_portaudio.hpp index 4444c3c0c..c6f3ab534 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_portaudio.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_portaudio.hpp @@ -13,14 +13,24 @@ #include "openmpt123_config.hpp" #include "openmpt123.hpp" +#include "mpt/base/detect.hpp" + #if defined(MPT_WITH_PORTAUDIO) #include +#if defined(MPT_BUILD_MSVC) && MPT_COMPILER_MSVC && MPT_ARCH_X86 +extern "C" { +void PaUtil_InitializeX86PlainConverters(void); +} +#endif + namespace openmpt123 { +inline constexpr auto portaudio_encoding = mpt::common_encoding::utf8; + struct portaudio_exception : public exception { - portaudio_exception( PaError code ) : exception( Pa_GetErrorText( code ) ) { } + portaudio_exception( PaError code ) : exception( mpt::transcode( portaudio_encoding, Pa_GetErrorText( code ) ) ) { } }; typedef void (*PaUtilLogCallback ) (const char *log); @@ -30,14 +40,14 @@ extern "C" void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb); class portaudio_raii { private: - std::ostream & log; + concat_stream & log; bool log_set; bool portaudio_initialized; - static std::ostream * portaudio_log_stream; + static concat_stream * portaudio_log_stream; private: static void portaudio_log_function( const char * log ) { if ( portaudio_log_stream ) { - *portaudio_log_stream << "PortAudio: " << log; + *portaudio_log_stream << MPT_USTRING("PortAudio: ") << mpt::transcode( portaudio_encoding, log ); } } protected: @@ -49,13 +59,13 @@ protected: return; } if ( e == paOutputUnderflowed ) { - log << "PortAudio warning: " << Pa_GetErrorText( e ) << std::endl; + log << MPT_USTRING("PortAudio warning: ") << mpt::transcode( portaudio_encoding, Pa_GetErrorText( e ) ) << lf; return; } throw portaudio_exception( e ); } public: - portaudio_raii( bool verbose, std::ostream & log ) : log(log), log_set(false), portaudio_initialized(false) { + portaudio_raii( bool verbose, concat_stream & log ) : log(log), log_set(false), portaudio_initialized(false) { if ( verbose ) { portaudio_log_stream = &log; } else { @@ -64,11 +74,14 @@ public: #ifdef _MSC_VER PaUtil_SetDebugPrintFunction( portaudio_log_function ); log_set = true; +#endif +#if defined(MPT_BUILD_MSVC) && MPT_COMPILER_MSVC && MPT_ARCH_X86 + PaUtil_InitializeX86PlainConverters(); #endif check_portaudio_error( Pa_Initialize() ); portaudio_initialized = true; if ( verbose ) { - *portaudio_log_stream << std::endl; + *portaudio_log_stream << lf; } } ~portaudio_raii() { @@ -86,7 +99,7 @@ public: } }; -std::ostream * portaudio_raii::portaudio_log_stream = 0; +concat_stream * portaudio_raii::portaudio_log_stream = 0; class portaudio_stream_blocking_raii : public portaudio_raii, public write_buffers_interface { private: @@ -96,7 +109,7 @@ private: std::vector sampleBufFloat; std::vector sampleBufInt; public: - portaudio_stream_blocking_raii( commandlineflags & flags, std::ostream & log ) + portaudio_stream_blocking_raii( commandlineflags & flags, concat_stream & log ) : portaudio_raii(flags.verbose, log) , stream(NULL) , interleaved(false) @@ -104,9 +117,7 @@ public: { PaStreamParameters streamparameters; std::memset( &streamparameters, 0, sizeof(PaStreamParameters) ); - std::istringstream device_string( flags.device ); - int device = -1; - device_string >> device; + const int device = mpt::parse_or( flags.device, -1 ); streamparameters.device = ( device == -1 ) ? Pa_GetDefaultOutputDevice() : device; streamparameters.channelCount = flags.channels; streamparameters.sampleFormat = ( flags.use_float ? paFloat32 : paInt16 ) | paNonInterleaved; @@ -140,16 +151,16 @@ public: } flags.apply_default_buffer_sizes(); if ( flags.verbose ) { - log << "PortAudio:" << std::endl; - log << " device: " + log << MPT_USTRING("PortAudio:") << lf; + log << MPT_USTRING(" device: ") << streamparameters.device - << " [ " << Pa_GetHostApiInfo( Pa_GetDeviceInfo( streamparameters.device )->hostApi )->name << " / " << Pa_GetDeviceInfo( streamparameters.device )->name << " ] " - << std::endl; - log << " low latency: " << Pa_GetDeviceInfo( streamparameters.device )->defaultLowOutputLatency << std::endl; - log << " high latency: " << Pa_GetDeviceInfo( streamparameters.device )->defaultHighOutputLatency << std::endl; - log << " suggested latency: " << streamparameters.suggestedLatency << std::endl; - log << " frames per buffer: " << framesperbuffer << std::endl; - log << " ui redraw: " << flags.period << std::endl; + << MPT_USTRING(" [ ") << mpt::transcode( portaudio_encoding, Pa_GetHostApiInfo( Pa_GetDeviceInfo( streamparameters.device )->hostApi )->name ) << MPT_USTRING(" / ") << mpt::transcode( portaudio_encoding, Pa_GetDeviceInfo( streamparameters.device )->name ) << MPT_USTRING(" ] ") + << lf; + log << MPT_USTRING(" low latency: ") << Pa_GetDeviceInfo( streamparameters.device )->defaultLowOutputLatency << lf; + log << MPT_USTRING(" high latency: ") << Pa_GetDeviceInfo( streamparameters.device )->defaultHighOutputLatency << lf; + log << MPT_USTRING(" suggested latency: ") << streamparameters.suggestedLatency << lf; + log << MPT_USTRING(" frames per buffer: ") << framesperbuffer << lf; + log << MPT_USTRING(" ui redraw: ") << flags.period << lf; } PaError e = PaError(); e = Pa_OpenStream( &stream, NULL, &streamparameters, flags.samplerate, framesperbuffer, ( flags.dither > 0 ) ? paNoFlag : paDitherOff, NULL, NULL ); @@ -165,11 +176,11 @@ public: } check_portaudio_error( Pa_StartStream( stream ) ); if ( flags.verbose ) { - log << " channels: " << streamparameters.channelCount << std::endl; - log << " sampleformat: " << ( ( ( streamparameters.sampleFormat & ~paNonInterleaved ) == paFloat32 ) ? "paFloat32" : "paInt16" ) << std::endl; - log << " latency: " << Pa_GetStreamInfo( stream )->outputLatency << std::endl; - log << " samplerate: " << Pa_GetStreamInfo( stream )->sampleRate << std::endl; - log << std::endl; + log << MPT_USTRING(" channels: ") << streamparameters.channelCount << lf; + log << MPT_USTRING(" sampleformat: ") << ( ( ( streamparameters.sampleFormat & ~paNonInterleaved ) == paFloat32 ) ? MPT_USTRING("paFloat32") : MPT_USTRING("paInt16") ) << lf; + log << MPT_USTRING(" latency: ") << Pa_GetStreamInfo( stream )->outputLatency << lf; + log << MPT_USTRING(" samplerate: ") << Pa_GetStreamInfo( stream )->sampleRate << lf; + log << lf; } } ~portaudio_stream_blocking_raii() { @@ -247,35 +258,35 @@ public: #define portaudio_stream_raii portaudio_stream_blocking_raii -static std::string show_portaudio_devices( std::ostream & log ) { - std::ostringstream devices; - devices << " portaudio:" << std::endl; +static mpt::ustring show_portaudio_devices( concat_stream & log ) { + string_concat_stream devices; + devices << MPT_USTRING(" portaudio:") << lf; portaudio_raii portaudio( false, log ); for ( PaDeviceIndex i = 0; i < Pa_GetDeviceCount(); ++i ) { if ( Pa_GetDeviceInfo( i ) && Pa_GetDeviceInfo( i )->maxOutputChannels > 0 ) { - devices << " " << i << ": "; + devices << MPT_USTRING(" ") << i << MPT_USTRING(": "); if ( Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi ) && Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->name ) { - devices << Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->name; + devices << mpt::transcode( portaudio_encoding, Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->name ); } else { - devices << "Host API " << Pa_GetDeviceInfo( i )->hostApi; + devices << MPT_USTRING("Host API ") << Pa_GetDeviceInfo( i )->hostApi; } if ( Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi ) ) { if ( i == Pa_GetHostApiInfo( Pa_GetDeviceInfo( i )->hostApi )->defaultOutputDevice ) { - devices << " (default)"; + devices << MPT_USTRING(" (default)"); } } - devices << " - "; + devices << MPT_USTRING(" - "); if ( Pa_GetDeviceInfo( i )->name ) { - devices << Pa_GetDeviceInfo( i )->name; + devices << mpt::transcode( portaudio_encoding, Pa_GetDeviceInfo( i )->name ); } else { - devices << "Device " << i; + devices << MPT_USTRING("Device ") << i; } - devices << " ("; - devices << "high latency: " << Pa_GetDeviceInfo( i )->defaultHighOutputLatency; - devices << ", "; - devices << "low latency: " << Pa_GetDeviceInfo( i )->defaultLowOutputLatency; - devices << ")"; - devices << std::endl; + devices << MPT_USTRING(" ("); + devices << MPT_USTRING("high latency: ") << Pa_GetDeviceInfo( i )->defaultHighOutputLatency; + devices << MPT_USTRING(", "); + devices << MPT_USTRING("low latency: ") << Pa_GetDeviceInfo( i )->defaultLowOutputLatency; + devices << MPT_USTRING(")"); + devices << lf; } } return devices.str(); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_pulseaudio.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_pulseaudio.hpp index 9650005fa..22d0862b8 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_pulseaudio.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_pulseaudio.hpp @@ -20,26 +20,28 @@ namespace openmpt123 { +inline constexpr auto pulseaudio_encoding = mpt::common_encoding::utf8; + struct pulseaudio_exception : public exception { - static std::string error_to_string( int error ) { + static mpt::ustring error_to_string( int error ) { try { if ( error == 0 ) { - return std::string(); + return mpt::ustring(); } - std::ostringstream e; + string_concat_stream e; const char * str = pa_strerror( error ); if ( !str ) { - e << "error=" << error; + e << MPT_USTRING("error=)") << error; return e.str(); } if ( std::strlen(str) == 0 ) { - e << "error=" << error; + e << MPT_USTRING("error=") << error; return e.str(); } - e << str << " (error=" << error << ")"; + e << mpt::transcode( pulseaudio_encoding, str ) << MPT_USTRING(" (error=") << error << MPT_USTRING(")"); return e.str(); } catch ( const std::bad_alloc & ) { - return std::string(); + return mpt::ustring(); } } pulseaudio_exception( int error ) : exception( error_to_string( error ) ) { } @@ -53,7 +55,7 @@ private: std::vector sampleBufFloat; std::vector sampleBufInt; public: - pulseaudio_stream_raii( commandlineflags & flags, std::ostream & /* log */ ) + pulseaudio_stream_raii( commandlineflags & flags, concat_stream & /* log */ ) : stream(NULL) , channels(flags.channels) , sampleSize(flags.use_float ? sizeof( float ) : sizeof( std::int16_t )) @@ -63,19 +65,19 @@ public: std::memset( &ss, 0, sizeof( pa_sample_spec ) ); ss.format = ( flags.use_float ? PA_SAMPLE_FLOAT32 : PA_SAMPLE_S16NE ); ss.rate = flags.samplerate; - ss.channels = flags.channels; + ss.channels = static_cast( flags.channels ); pa_buffer_attr ba; std::memset( &ba, 0, sizeof( pa_buffer_attr ) ); bool use_ba = false; if ( flags.buffer != default_high && flags.buffer != default_low ) { use_ba = true; - ba.maxlength = channels * sampleSize * ( flags.buffer * flags.samplerate / 1000 ); + ba.maxlength = static_cast( channels * sampleSize * ( flags.buffer * flags.samplerate / 1000 ) ); } else { ba.maxlength = static_cast(-1); } if ( flags.period != default_high && flags.period != default_low ) { use_ba = true; - ba.minreq = channels * sampleSize * ( flags.period * flags.samplerate / 1000 ); + ba.minreq = static_cast( channels * sampleSize * ( flags.period * flags.samplerate / 1000 ) ); if ( ba.maxlength != static_cast(-1) ) { ba.tlength = ba.maxlength - ba.minreq; ba.prebuf = ba.tlength; @@ -152,10 +154,10 @@ public: } }; -static std::string show_pulseaudio_devices( std::ostream & /* log */ ) { - std::ostringstream devices; - devices << " pulseaudio:" << std::endl; - devices << " " << "0" << ": Default Device" << std::endl; +static mpt::ustring show_pulseaudio_devices( concat_stream & /* log */ ) { + string_concat_stream devices; + devices << MPT_USTRING(" pulseaudio:") << lf; + devices << MPT_USTRING(" ") << MPT_USTRING("0") << MPT_USTRING(": Default Device") << lf; return devices.str(); } diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_raw.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_raw.hpp index cb7d8d5f2..0d76db57c 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_raw.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_raw.hpp @@ -16,21 +16,21 @@ #include namespace openmpt123 { - + class raw_stream_raii : public file_audio_stream_base { private: commandlineflags flags; - std::ofstream file; + mpt::IO::ofstream file; std::vector interleaved_float_buffer; std::vector interleaved_int_buffer; public: - raw_stream_raii( const std::string & filename, const commandlineflags & flags_, std::ostream & /*log*/ ) : flags(flags_), file(filename.c_str(), std::ios::binary) { + raw_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & /*log*/ ) : flags(flags_), file(filename, std::ios::binary) { return; } ~raw_stream_raii() { return; } - void write_metadata( std::map /* metadata */ ) override { + void write_metadata( std::map /* metadata */ ) override { return; } void write( const std::vector buffers, std::size_t frames ) override { diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sdl2.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sdl2.hpp index 5acab163d..9ac0fd3b7 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sdl2.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sdl2.hpp @@ -36,15 +36,17 @@ MPT_WARNING("Support for SDL2 < 2.0.4 has been deprecated and will be removed in namespace openmpt123 { +inline constexpr auto sdl2_encoding = mpt::common_encoding::utf8; + struct sdl2_exception : public exception { private: - static std::string text_from_code( int code ) { - std::ostringstream s; + static mpt::ustring text_from_code( int code ) { + string_concat_stream s; s << code; return s.str(); } public: - sdl2_exception( int code, const char * error ) : exception( text_from_code( code ) + " (" + ( error ? std::string(error) : std::string("NULL") ) + ")" ) { } + sdl2_exception( int code, const char * error ) : exception( text_from_code( code ) + MPT_USTRING(" (") + mpt::transcode( sdl2_encoding, error ? std::string(error) : std::string("NULL") ) + MPT_USTRING(")") ) { } }; static void check_sdl2_error( int e ) { @@ -65,7 +67,7 @@ public: class sdl2_stream_raii : public write_buffers_interface { private: - std::ostream & log; + concat_stream & log; sdl2_raii sdl2; int dev; std::size_t channels; @@ -83,7 +85,7 @@ protected: return result; } public: - sdl2_stream_raii( commandlineflags & flags, std::ostream & log_ ) + sdl2_stream_raii( commandlineflags & flags, concat_stream & log_ ) : log(log_) , sdl2( SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER | SDL_INIT_AUDIO ) , dev(-1) @@ -106,16 +108,16 @@ public: std::memset( &audiospec, 0, sizeof( SDL_AudioSpec ) ); audiospec.freq = flags.samplerate; audiospec.format = ( flags.use_float ? AUDIO_F32SYS : AUDIO_S16SYS ); - audiospec.channels = flags.channels; + audiospec.channels = static_cast( flags.channels ); audiospec.silence = 0; - audiospec.samples = round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ); - audiospec.size = audiospec.samples * audiospec.channels * ( flags.use_float ? sizeof( float ) : sizeof( std::int16_t ) ); + audiospec.samples = static_cast( round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ) ); + audiospec.size = static_cast( audiospec.samples * audiospec.channels * ( flags.use_float ? sizeof( float ) : sizeof( std::int16_t ) ) ); audiospec.callback = NULL; audiospec.userdata = NULL; if ( flags.verbose ) { - log << "SDL2:" << std::endl; - log << " latency: " << ( audiospec.samples * 2.0 / flags.samplerate ) << " (2 * " << audiospec.samples << ")" << std::endl; - log << std::endl; + log << MPT_USTRING("SDL2:") << lf; + log << MPT_USTRING(" latency: ") << ( audiospec.samples * 2.0 / flags.samplerate ) << MPT_USTRING(" (2 * ") << audiospec.samples << MPT_USTRING(")") << lf; + log << lf; } sampleQueueMaxFrames = round_up_power2( ( flags.buffer * flags.samplerate ) / ( 1000 * 2 ) ); SDL_AudioSpec audiospec_obtained; @@ -146,7 +148,7 @@ private: while ( frames > 0 ) { std::size_t chunk_frames = std::min( frames, get_num_writeable_frames() ); if ( chunk_frames > 0 ) { - check_sdl2_error( SDL_QueueAudio( dev, buffer, chunk_frames * channels * ( use_float ? sizeof( float ) : sizeof( std::int16_t ) ) ) ); + check_sdl2_error( SDL_QueueAudio( dev, buffer, static_cast( chunk_frames * channels * ( use_float ? sizeof( float ) : sizeof( std::int16_t ) ) ) ) ); frames -= chunk_frames; buffer += chunk_frames * channels; } else { @@ -187,10 +189,10 @@ public: } }; -static std::string show_sdl2_devices( std::ostream & /* log */ ) { - std::ostringstream devices; +static mpt::ustring show_sdl2_devices( concat_stream & /* log */ ) { + string_concat_stream devices; std::size_t device_index = 0; - devices << " SDL2:" << std::endl; + devices << MPT_USTRING(" SDL2:") << lf; sdl2_raii sdl2( SDL_INIT_NOPARACHUTE | SDL_INIT_AUDIO ); for ( int driver = 0; driver < SDL_GetNumAudioDrivers(); ++driver ) { const char * driver_name = SDL_GetAudioDriver( driver ); @@ -211,7 +213,7 @@ static std::string show_sdl2_devices( std::ostream & /* log */ ) { if ( std::string( device_name ).empty() ) { continue; } - devices << " " << device_index << ": " << driver_name << " - " << device_name << std::endl; + devices << MPT_USTRING(" ") << device_index << MPT_USTRING(": ") << mpt::transcode( sdl2_encoding, driver_name ) << MPT_USTRING(" - ") << mpt::transcode( sdl2_encoding, device_name ) << lf; device_index++; } SDL_AudioQuit(); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp index 8fc3156e9..550c83d49 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_sndfile.hpp @@ -15,14 +15,18 @@ #if defined(MPT_WITH_SNDFILE) +#include "mpt/base/detect.hpp" + #include namespace openmpt123 { + +inline constexpr auto sndfile_encoding = mpt::common_encoding::utf8; class sndfile_stream_raii : public file_audio_stream_base { private: commandlineflags flags; - std::ostream & log; + concat_stream & log; SNDFILE * sndfile; std::vector interleaved_float_buffer; std::vector interleaved_int_buffer; @@ -34,27 +38,27 @@ private: match_better, match_any }; - std::string match_mode_to_string( match_mode_enum match_mode ) { + mpt::ustring match_mode_to_string( match_mode_enum match_mode ) { switch ( match_mode ) { - case match_print : return "print" ; break; - case match_recurse: return "recurse"; break; - case match_exact : return "exact" ; break; - case match_better : return "better" ; break; - case match_any : return "any" ; break; + case match_print : return MPT_USTRING("print") ; break; + case match_recurse: return MPT_USTRING("recurse"); break; + case match_exact : return MPT_USTRING("exact") ; break; + case match_better : return MPT_USTRING("better") ; break; + case match_any : return MPT_USTRING("any") ; break; } - return ""; + return MPT_USTRING(""); } - int matched_result( const SF_FORMAT_INFO & format_info, const SF_FORMAT_INFO & subformat_info, match_mode_enum match_mode ) { + int matched_result( int format, const SF_FORMAT_INFO & format_info, const SF_FORMAT_INFO & subformat_info, match_mode_enum match_mode ) { if ( flags.verbose ) { - log << "sndfile: using format '" - << format_info.name << " (" << format_info.extension << ")" << " / " << subformat_info.name - << "', " - << "match: " << match_mode_to_string( match_mode ) - << std::endl; + log << MPT_USTRING("sndfile: using format '") + << mpt::transcode( sndfile_encoding, format_info.name ) << MPT_USTRING(" (") << mpt::transcode( sndfile_encoding, format_info.extension ) << MPT_USTRING(")") << MPT_USTRING(" / ") << mpt::transcode( sndfile_encoding, subformat_info.name ) + << MPT_USTRING("', ") + << MPT_USTRING("match: ") << match_mode_to_string( match_mode ) + << lf; } - return ( format_info.format & SF_FORMAT_TYPEMASK ) | subformat_info.format; + return format; } - int find_format( const std::string & extension, match_mode_enum match_mode ) { + int find_format( const mpt::native_path & extension, match_mode_enum match_mode ) { if ( match_mode == match_recurse ) { int result = 0; @@ -76,7 +80,6 @@ private: return 0; } - int format = 0; int major_count; sf_command( 0, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof( int ) ); for ( int m = 0; m < major_count; m++ ) { @@ -84,7 +87,6 @@ private: SF_FORMAT_INFO format_info; format_info.format = m; sf_command( 0, SFC_GET_FORMAT_MAJOR, &format_info, sizeof( SF_FORMAT_INFO ) ); - format = format_info.format; int subtype_count; sf_command( 0, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof( int ) ); @@ -93,7 +95,7 @@ private: SF_FORMAT_INFO subformat_info; subformat_info.format = s; sf_command( 0, SFC_GET_FORMAT_SUBTYPE, &subformat_info, sizeof( SF_FORMAT_INFO ) ); - format = ( format & SF_FORMAT_TYPEMASK ) | subformat_info.format; + int format = ( format_info.format & SF_FORMAT_TYPEMASK ) | ( subformat_info.format & SF_FORMAT_SUBMASK ); SF_INFO sfinfo; std::memset( &sfinfo, 0, sizeof( SF_INFO ) ); @@ -103,40 +105,38 @@ private: switch ( match_mode ) { case match_print: - log << "sndfile: " - << ( format_info.name ? format_info.name : "" ) << " (" << ( format_info.extension ? format_info.extension : "" ) << ")" - << " / " - << ( subformat_info.name ? subformat_info.name : "" ) - << " [" - << std::setbase(16) << std::setw(8) << std::setfill('0') << format_info.format - << "|" - << std::setbase(16) << std::setw(8) << std::setfill('0') << subformat_info.format - << "]" - << std::endl; + log << MPT_USTRING("sndfile: ") + << mpt::transcode( sndfile_encoding, ( format_info.name ? format_info.name : "" ) ) << MPT_USTRING(" (.") << mpt::transcode( sndfile_encoding, ( format_info.extension ? format_info.extension : "" ) ) << MPT_USTRING(")") + << MPT_USTRING(" / ") + << mpt::transcode( sndfile_encoding, ( subformat_info.name ? subformat_info.name : "" ) ) + << MPT_USTRING(" [") + << mpt::format::hex0<8>( format ) + << MPT_USTRING("]") + << lf; break; case match_recurse: break; case match_exact: - if ( extension == format_info.extension ) { + if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT ) ) { - return matched_result( format_info, subformat_info, match_mode ); + return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format == SF_FORMAT_PCM_16 ) ) { - return matched_result( format_info, subformat_info, match_mode ); + return matched_result( format, format_info, subformat_info, match_mode ); } } break; case match_better: - if ( extension == format_info.extension ) { + if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { if ( flags.use_float && ( subformat_info.format == SF_FORMAT_FLOAT || subformat_info.format == SF_FORMAT_DOUBLE ) ) { - return matched_result( format_info, subformat_info, match_mode ); + return matched_result( format, format_info, subformat_info, match_mode ); } else if ( !flags.use_float && ( subformat_info.format & ( subformat_info.format == SF_FORMAT_PCM_16 || subformat_info.format == SF_FORMAT_PCM_24 || subformat_info.format == SF_FORMAT_PCM_32 ) ) ) { - return matched_result( format_info, subformat_info, match_mode ); + return matched_result( format, format_info, subformat_info, match_mode ); } } break; case match_any: - if ( extension == format_info.extension ) { - return matched_result( format_info, subformat_info, match_mode ); + if ( mpt::transcode( mpt::common_encoding::utf8, extension ) == format_info.extension ) { + return matched_result( format, format_info, subformat_info, match_mode ); } break; } @@ -154,32 +154,36 @@ private: } } public: - sndfile_stream_raii( const std::string & filename, const commandlineflags & flags_, std::ostream & log_ ) : flags(flags_), log(log_), sndfile(0) { + sndfile_stream_raii( const mpt::native_path & filename, const commandlineflags & flags_, concat_stream & log_ ) : flags(flags_), log(log_), sndfile(0) { if ( flags.verbose ) { - find_format( "", match_print ); - log << std::endl; + find_format( MPT_NATIVE_PATH(""), match_print ); + log << lf; } int format = find_format( flags.output_extension, match_recurse ); if ( !format ) { - throw exception( "unknown file type" ); + throw exception( MPT_USTRING("unknown file type") ); } SF_INFO info; std::memset( &info, 0, sizeof( SF_INFO ) ); info.samplerate = flags.samplerate; info.channels = flags.channels; info.format = format; - sndfile = sf_open( filename.c_str(), SFM_WRITE, &info ); +#if MPT_OS_WINDOWS && defined(UNICODE) + sndfile = sf_wchar_open( filename.AsNative().c_str(), SFM_WRITE, &info ); +#else + sndfile = sf_open( filename.AsNative().c_str(), SFM_WRITE, &info ); +#endif } ~sndfile_stream_raii() { sf_close( sndfile ); sndfile = 0; } - void write_metadata( std::map metadata ) override { - write_metadata_field( SF_STR_TITLE, metadata[ "title" ] ); - write_metadata_field( SF_STR_ARTIST, metadata[ "artist" ] ); - write_metadata_field( SF_STR_DATE, metadata[ "date" ] ); - write_metadata_field( SF_STR_COMMENT, metadata[ "message" ] ); - write_metadata_field( SF_STR_SOFTWARE, append_software_tag( metadata[ "tracker" ] ) ); + void write_metadata( std::map metadata ) override { + write_metadata_field( SF_STR_TITLE, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("title") ] ) ); + write_metadata_field( SF_STR_ARTIST, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("artist") ] ) ); + write_metadata_field( SF_STR_DATE, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("date") ] ) ); + write_metadata_field( SF_STR_COMMENT, mpt::transcode( sndfile_encoding, metadata[ MPT_USTRING("message") ] ) ); + write_metadata_field( SF_STR_SOFTWARE, mpt::transcode( sndfile_encoding, append_software_tag( metadata[ MPT_USTRING("tracker") ] ) ) ); } void write( const std::vector buffers, std::size_t frames ) override { interleaved_float_buffer.clear(); diff --git a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_waveout.hpp b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_waveout.hpp index 11c60bfeb..07b34dbe1 100644 --- a/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_waveout.hpp +++ b/Frameworks/OpenMPT/OpenMPT/openmpt123/openmpt123_waveout.hpp @@ -13,12 +13,14 @@ #include "openmpt123_config.hpp" #include "openmpt123.hpp" -#if defined(WIN32) +#include "mpt/base/detect.hpp" + +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT namespace openmpt123 { struct waveout_exception : public exception { - waveout_exception() : exception( "waveout" ) { } + waveout_exception() : exception( MPT_USTRING("waveout") ) { } }; class waveout_stream_raii : public write_buffers_interface { @@ -59,10 +61,8 @@ public: wfx.nBlockAlign = ( wfx.wBitsPerSample / 8 ) * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.cbSize = 0; - std::istringstream device_string( flags.device ); - int device = -1; - device_string >> device; - waveOutOpen( &waveout, device == -1 ? WAVE_MAPPER : device, &wfx, 0, 0, CALLBACK_NULL ); + const int device = mpt::parse_or( flags.device, -1 ); + waveOutOpen( &waveout, ( device == -1 ) ? WAVE_MAPPER : device, &wfx, 0, 0, CALLBACK_NULL ); num_channels = flags.channels; std::size_t frames_per_buffer = flags.samplerate * flags.buffer / 1000; num_chunks = ( flags.buffer + flags.period - 1 ) / flags.period; @@ -177,22 +177,26 @@ public: } }; -static std::string show_waveout_devices( std::ostream & /*log*/ ) { - std::ostringstream devices; - devices << " waveout:" << std::endl; +static mpt::ustring show_waveout_devices( concat_stream & /*log*/ ) { + string_concat_stream devices; + devices << MPT_USTRING(" waveout:") << lf; for ( UINT i = 0; i < waveOutGetNumDevs(); ++i ) { - devices << " " << i << ": "; - WAVEOUTCAPSW caps; + devices << MPT_USTRING(" ") << i << MPT_USTRING(": "); + WAVEOUTCAPS caps; ZeroMemory( &caps, sizeof( caps ) ); - waveOutGetDevCapsW( i, &caps, sizeof( caps ) ); - devices << mpt::transcode( mpt::common_encoding::utf8, caps.szPname ); - devices << std::endl; + waveOutGetDevCaps( i, &caps, sizeof( caps ) ); + #if defined(UNICODE) + devices << mpt::transcode( caps.szPname ); + #else + devices << mpt::transcode( mpt::logical_encoding::locale, caps.szPname ); + #endif + devices << lf; } return devices.str(); } } // namespace openmpt123 -#endif // WIN32 +#endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT #endif // OPENMPT123_WAVEOUT_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp b/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp index 5ffa22bc4..7ecb7e83b 100644 --- a/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp +++ b/Frameworks/OpenMPT/OpenMPT/sounddsp/EQ.cpp @@ -20,7 +20,9 @@ #include "openmpt/soundbase/MixSampleConvert.hpp" #ifndef NO_EQ -#include "../misc/mptCPU.h" +#if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE) +#include "../common/mptCPU.h" +#endif #endif #include @@ -97,7 +99,7 @@ void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std:: { #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE) unsigned int old_csr = 0; - if(CPU::HasFeatureSet(CPU::feature::sse)) + if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { old_csr = _mm_getcsr(); _mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON); @@ -118,7 +120,7 @@ void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std:: EQFilter<4>(buf, m_Bands, m_ChannelState); } #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE) - if(CPU::HasFeatureSet(CPU::feature::sse)) + if(CPU::HasFeatureSet(CPU::feature::sse) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { _mm_setcsr(old_csr); } diff --git a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp index 5355568ca..36b47a180 100644 --- a/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp +++ b/Frameworks/OpenMPT/OpenMPT/sounddsp/Reverb.cpp @@ -13,6 +13,9 @@ #ifndef NO_REVERB #include "Reverb.h" +#if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) +#include "../common/mptCPU.h" +#endif #include "../soundlib/MixerLoops.h" #include "mpt/base/numbers.hpp" @@ -48,9 +51,9 @@ CReverb::CReverb() } -static int32 OnePoleLowPassCoef(int32 scale, float g, float F_c, float F_s) +static int32 OnePoleLowPassCoef(int32 scale, double g, double F_c, double F_s) { - if(g > 0.999999f) return 0; + if(g > 0.999999) return 0; g *= g; double scale_over_1mg = scale / (1.0 - g); @@ -58,13 +61,13 @@ static int32 OnePoleLowPassCoef(int32 scale, float g, float F_c, float F_s) return mpt::saturate_round((1.0 - (std::sqrt((g + g) * (1.0 - cosw) - g * g * (1.0 - cosw * cosw)) + g * cosw)) * scale_over_1mg); } -static float mBToLinear(int32 value_mB) +static double mBToLinear(int32 value_mB) { if(!value_mB) return 1; if(value_mB <= -100000) return 0; const double val = value_mB * 3.321928094887362304 / (100.0 * 20.0); // log2(10)/(100*20) - return static_cast(std::pow(2.0, val - static_cast(0.5 + val))); + return std::pow(2.0, val - static_cast(0.5 + val)); } static int32 mBToLinear(int32 scale, int32 value_mB) @@ -296,7 +299,7 @@ void CReverb::Initialize(bool bReset, MixSampleInt &gnRvbROfsVol, MixSampleInt & // Room attenuation at high frequencies int32 nRoomLP; - nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, flOutputFrequency); + nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, static_cast(flOutputFrequency)); g_RefDelay.nCoeffs.c.l = (int16)nRoomLP; g_RefDelay.nCoeffs.c.r = (int16)nRoomLP; @@ -357,7 +360,7 @@ void CReverb::Initialize(bool bReset, MixSampleInt &gnRvbROfsVol, MixSampleInt & float fReverbDamping = rvb.flReverbDamping * rvb.flReverbDamping; int32 nDampingLowPass; - nDampingLowPass = OnePoleLowPassCoef(32768, fReverbDamping, 5000, flOutputFrequency); + nDampingLowPass = OnePoleLowPassCoef(32768, static_cast(fReverbDamping), 5000, static_cast(flOutputFrequency)); Limit(nDampingLowPass, 0x100, 0x7f00); g_LateReverb.nDecayLP[0].c.l = (int16)nDampingLowPass; @@ -589,7 +592,7 @@ void CReverb::ReverbProcessPostFiltering2x(const int32 * MPT_RESTRICT pRvb, int3 void CReverb::ReverbProcessPostFiltering1x(const int32 * MPT_RESTRICT pRvb, int32 * MPT_RESTRICT pDry, uint32 nSamples) { #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) - if(CPU::HasFeatureSet(CPU::feature::sse2)) + if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); @@ -651,7 +654,7 @@ void CReverb::ReverbProcessPostFiltering1x(const int32 * MPT_RESTRICT pRvb, int3 void CReverb::ReverbDCRemoval(int32 * MPT_RESTRICT pBuffer, uint32 nSamples) { #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) - if(CPU::HasFeatureSet(CPU::feature::sse2)) + if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i nDCRRvb_Y1 = Load64SSE(gnDCRRvb_Y1); __m128i nDCRRvb_X1 = Load64SSE(gnDCRRvb_X1); @@ -716,7 +719,7 @@ void CReverb::ProcessPreDelay(SWRvbRefDelay * MPT_RESTRICT pPreDelay, const int3 uint32 preDifPos = pPreDelay->nPreDifPos; uint32 delayPos = pPreDelay->nDelayPos - 1; #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) - if(CPU::HasFeatureSet(CPU::feature::sse2)) + if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { __m128i coeffs = _mm_cvtsi32_si128(pPreDelay->nCoeffs.lr); __m128i history = _mm_cvtsi32_si128(pPreDelay->History.lr); @@ -788,7 +791,7 @@ void CReverb::ProcessPreDelay(SWRvbRefDelay * MPT_RESTRICT pPreDelay, const int3 void CReverb::ProcessReflections(SWRvbRefDelay * MPT_RESTRICT pPreDelay, LR16 * MPT_RESTRICT pRefOut, int32 * MPT_RESTRICT pOut, uint32 nSamples) { #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) - if(CPU::HasFeatureSet(CPU::feature::sse2)) + if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { union { @@ -883,7 +886,7 @@ void CReverb::ProcessLateReverb(SWLateReverb * MPT_RESTRICT pReverb, LR16 * MPT_ #define DELAY_OFFSET(x) ((delayPos - (x)) & RVBDLY_MASK) #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE2) - if(CPU::HasFeatureSet(CPU::feature::sse2)) + if(CPU::HasFeatureSet(CPU::feature::sse2) && CPU::HasModesEnabled(CPU::mode::xmm128sse)) { int delayPos = pReverb->nDelayPos & RVBDLY_MASK; __m128i rvbOutGains = Load64SSE(pReverb->RvbOutGains); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/AudioReadTarget.h b/Frameworks/OpenMPT/OpenMPT/soundlib/AudioReadTarget.h index 76799d915..236520161 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/AudioReadTarget.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/AudioReadTarget.h @@ -77,11 +77,11 @@ class AudioTargetBufferWithGain private: using Tbase = AudioTargetBuffer; private: - const float gainFactor; + const MixSampleFloat gainFactor; public: AudioTargetBufferWithGain(Taudio_span buf, TDithers &dithers, float gainFactor_) : Tbase(buf, dithers) - , gainFactor(gainFactor_) + , gainFactor(static_cast(gainFactor_)) { return; } @@ -108,14 +108,14 @@ public: Tbase::Process(buffer); if constexpr(std::is_floating_point::value) { - if(gainFactor != 1.0f) + if(gainFactor != MixSampleFloat(1.0)) { // only apply gain when != +/- 0dB for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) { for(std::size_t channel = 0; channel < buffer.size_channels(); ++channel) { - Tbase::outputBuffer(channel, countRendered_ + frame) *= gainFactor; + Tbase::outputBuffer(channel, countRendered_ + frame) *= static_cast(gainFactor); } } } @@ -123,7 +123,7 @@ public: } void Process(mpt::audio_span_interleaved buffer) override { - if(gainFactor != 1.0f) + if(gainFactor != MixSampleFloat(1.0)) { // only apply gain when != +/- 0dB for(std::size_t frame = 0; frame < buffer.size_frames(); ++frame) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerMMCMP.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerMMCMP.cpp index 0f98338ed..74d988134 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerMMCMP.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerMMCMP.cpp @@ -187,7 +187,7 @@ bool UnpackMMCMP(std::vector &containerItems, FileReader &file, C if(blkPos + sizeof(MMCMPBlock) + blk.sub_blk * sizeof(MMCMPSubBlock) >= file.GetLength()) return false; - uint32 memPos = blkPos + sizeof(MMCMPBlock) + blk.sub_blk * sizeof(MMCMPSubBlock); + uint32 memPos = blkPos + static_cast(sizeof(MMCMPBlock)) + blk.sub_blk * static_cast(sizeof(MMCMPSubBlock)); #ifdef MMCMP_LOG MPT_LOG_GLOBAL(LogDebug, "MMCMP", MPT_UFORMAT("block {}: flags={} sub_blocks={}")(nBlock, mpt::ufmt::HEX0<4>(static_cast(blk.flags)), static_cast(blk.sub_blk))); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerPP20.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerPP20.cpp index cec6502e2..5dc59066f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerPP20.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerPP20.cpp @@ -56,13 +56,13 @@ uint32 PPBITBUFFER::GetBits(uint32 n) } -static bool PP20_DoUnpack(const uint8 *pSrc, uint32 srcLen, uint8 *pDst, uint32 dstLen) +static bool PP20_DoUnpack(mpt::span src, uint8 *pDst, uint32 dstLen) { - const std::array modeTable{pSrc[0], pSrc[1], pSrc[2], pSrc[3]}; + const std::array modeTable{src[0], src[1], src[2], src[3]}; PPBITBUFFER BitBuffer; - BitBuffer.pStart = pSrc; - BitBuffer.pSrc = pSrc + srcLen - 4; - BitBuffer.GetBits(pSrc[srcLen - 1]); + BitBuffer.pStart = src.data(); + BitBuffer.pSrc = src.data() + src.size() - 4; + BitBuffer.GetBits(src.data()[src.size() - 1]); uint32 bytesLeft = dstLen; while(bytesLeft > 0) { @@ -200,7 +200,8 @@ bool UnpackPP20(std::vector &containerItems, FileReader &file, Co return false; } file.Seek(4); - bool result = PP20_DoUnpack(file.GetRawData().data(), static_cast(length - 4), mpt::byte_cast(unpackedData.data()), dstLen); + FileReader::PinnedView compressedData = file.GetPinnedView(mpt::saturate_cast(length - 4)); + bool result = PP20_DoUnpack(mpt::byte_cast>(compressedData.span()), mpt::byte_cast(unpackedData.data()), dstLen); if(result) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerXPK.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerXPK.cpp index 0b9fcfae0..b467ee093 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerXPK.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ContainerXPK.cpp @@ -103,7 +103,7 @@ static uint8 XPK_ReadTable(int32 index) return xpk_table[index]; } -static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector &unpackedData, int32 len) +static bool XPK_DoUnpack(const mpt::const_byte_span src_, std::vector &unpackedData, int32 len) { if(len <= 0) return false; int32 d0,d1,d2,d3,d4,d5,d6,a2,a5; @@ -112,11 +112,11 @@ static bool XPK_DoUnpack(const uint8 *src_, uint32 srcLen, std::vector &un std::size_t src; std::size_t phist = 0; - unpackedData.reserve(std::min(static_cast(len), std::min(srcLen, uint32_max / 20u) * 20u)); + unpackedData.reserve(std::min(static_cast(len), std::min(mpt::saturate_cast(src_.size()), uint32_max / 20u) * 20u)); XPK_BufferBounds bufs; - bufs.pSrcBeg = src_; - bufs.SrcSize = srcLen; + bufs.pSrcBeg = mpt::byte_cast(src_.data()); + bufs.SrcSize = src_.size(); src = 0; c = src; @@ -407,7 +407,8 @@ bool UnpackXPK(std::vector &containerItems, FileReader &file, Con bool result = false; try { - result = XPK_DoUnpack(file.GetRawData().data(), header.SrcLen - (sizeof(XPKFILEHEADER) - 8), unpackedData, header.DstLen); + FileReader::PinnedView compressedData = file.GetPinnedView(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)); + result = XPK_DoUnpack(compressedData.span(), unpackedData, header.DstLen); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp index 680784e5a..7873948ce 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.cpp @@ -13,6 +13,8 @@ #include "Sndfile.h" #ifdef MODPLUG_TRACKER #include "../mptrack/Mptrack.h" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #endif #include "Dlsbank.h" @@ -158,6 +160,9 @@ enum DLSArt : uint32 ART_PITCH_EG_RELEASETIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_RELEASETIME), ART_PITCH_EG_VELTOATTACK = DLSArt(CONN_SRC_KEYONVELOCITY, CONN_SRC_NONE, CONN_DST_EG2_ATTACKTIME), ART_PITCH_EG_KEYTODECAY = DLSArt(CONN_SRC_KEYNUMBER, CONN_SRC_NONE, CONN_DST_EG2_DECAYTIME), + ART_PITCH_EG_DELAYTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_DELAYTIME), + ART_PITCH_EG_HOLDTIME = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_EG2_HOLDTIME), + ART_PITCH_EG_DEPTH = DLSArt(CONN_SRC_EG2, CONN_SRC_NONE, CONN_DST_PITCH), // Default Pan ART_DEFAULTPAN = DLSArt(CONN_SRC_NONE, CONN_SRC_NONE, CONN_DST_PAN), @@ -355,11 +360,18 @@ enum SF2Generators : uint16 { SF2_GEN_START_LOOP_FINE = 2, SF2_GEN_END_LOOP_FINE = 3, + SF2_GEN_MODENVTOPITCH = 7, SF2_GEN_MODENVTOFILTERFC = 11, SF2_GEN_PAN = 17, + SF2_GEN_DELAYMODENV = 25, + SF2_GEN_ATTACKMODENV = 26, + SF2_GEN_HOLDMODENV = 27, SF2_GEN_DECAYMODENV = 28, + SF2_GEN_SUSTAINMODENV = 29, + SF2_GEN_RELEASEMODENV = 30, + SF2_GEN_DELAYVOLENV = 33, SF2_GEN_ATTACKVOLENV = 34, - SF2_GEN_HOLDVOLENV = 34, + SF2_GEN_HOLDVOLENV = 35, SF2_GEN_DECAYVOLENV = 36, SF2_GEN_SUSTAINVOLENV = 37, SF2_GEN_RELEASEVOLENV = 38, @@ -405,6 +417,8 @@ struct SFGenList { uint16le sfGenOper; uint16le genAmount; + + bool ApplyToEnvelope(DLSENVELOPE &env) const; }; MPT_BINARY_STRUCT(SFGenList, 4) @@ -425,13 +439,7 @@ struct SFInstBag MPT_BINARY_STRUCT(SFInstBag, 4) -struct SFInstGenList -{ - uint16le sfGenOper; - uint16le genAmount; -}; - -MPT_BINARY_STRUCT(SFInstGenList, 4) +using SFInstGenList = SFGenList; struct SFSample { @@ -479,6 +487,13 @@ static uint8 DLSSustainLevelToLinear(int32 sustain) } +static int16 SF2TimeToDLS(int16 amount) +{ + int32 time = CDLSBank::DLS32BitTimeCentsToMilliseconds(static_cast(amount) << 16); + return static_cast(Clamp(time, 20, 20000) / 20); +} + + static uint8 SF2SustainLevelToLinear(int32 sustain) { // 0.1% units @@ -487,6 +502,60 @@ static uint8 SF2SustainLevelToLinear(int32 sustain) } +bool SFGenList::ApplyToEnvelope(DLSENVELOPE &env) const +{ + switch(sfGenOper) + { + case SF2_GEN_DELAYVOLENV: + env.volumeEnv.delay = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_ATTACKVOLENV: + env.volumeEnv.attack = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_HOLDVOLENV: + env.volumeEnv.hold = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_DECAYVOLENV: + env.volumeEnv.decay = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_SUSTAINVOLENV: + // 0.1% units + if(genAmount >= 0) + { + env.volumeEnv.sustainLevel = SF2SustainLevelToLinear(genAmount); + } + break; + case SF2_GEN_RELEASEVOLENV: + env.volumeEnv.release = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_DELAYMODENV: + env.pitchEnv.delay = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_ATTACKMODENV: + env.pitchEnv.attack = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_HOLDMODENV: + env.pitchEnv.hold = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_DECAYMODENV: + env.pitchEnv.decay = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_SUSTAINMODENV: + env.pitchEnv.sustainLevel = SF2SustainLevelToLinear(genAmount); + break; + case SF2_GEN_RELEASEMODENV: + env.pitchEnv.release = SF2TimeToDLS(genAmount); + break; + case SF2_GEN_MODENVTOPITCH: + env.pitchEnvDepth = static_cast(genAmount); + break; + + default: return false; + } + return true; +} + + int32 CDLSBank::DLS32BitTimeCentsToMilliseconds(int32 lTimeCents) { // tc = log2(time[secs]) * 1200*65536 @@ -499,6 +568,20 @@ int32 CDLSBank::DLS32BitTimeCentsToMilliseconds(int32 lTimeCents) } +uint16 CDLSBank::DLSEnvelopeTimeCentsToMilliseconds(int32 value) +{ + if(value <= -0x40000000) + return 0; + + int32 decaytime = DLS32BitTimeCentsToMilliseconds(value); + if(decaytime > 20000) + decaytime = 20000; + if(decaytime >= 20) + return static_cast(decaytime / 20); + return 0; +} + + // 0dB = 0x10000 int32 CDLSBank::DLS32BitRelativeGainToLinear(int32 lCentibels) { @@ -584,51 +667,65 @@ bool CDLSBank::IsDLSBank(const mpt::PathString &filename) const DLSINSTRUMENT *CDLSBank::FindInstrument(bool isDrum, uint32 bank, uint32 program, uint32 key, uint32 *pInsNo) const { - // This helps finding the "more correct" instrument if we search for an instrument in any bank, and the higher-bank instruments appear first in the file - // Fixes issues when loading GeneralUser GS into OpenMPT's MIDI library. - std::vector> sortedInstr{m_Instruments.begin(), m_Instruments.end()}; - if(bank >= 0x4000 || program >= 0x80) + uint32 minBank = ((bank << 1) & 0x7F00) | (bank & 0x7F); + uint32 maxBank = minBank; + if(bank >= 0x4000) { - std::sort(sortedInstr.begin(), sortedInstr.end(), [](const DLSINSTRUMENT &l, const DLSINSTRUMENT &r) - { return std::tie(l.ulBank, l.ulInstrument) < std::tie(r.ulBank, r.ulInstrument); }); + minBank = 0x0000; + maxBank = 0x7F7F; + } + if(isDrum) + { + minBank |= F_INSTRUMENT_DRUMS; + maxBank |= F_INSTRUMENT_DRUMS; } - for(const DLSINSTRUMENT &dlsIns : sortedInstr) + const bool singleInstr = (minBank == maxBank) && (program < 0x80); + const auto CompareInstrFunc = [singleInstr](const DLSINSTRUMENT &l, const DLSINSTRUMENT &r) { - uint32 insbank = ((dlsIns.ulBank & 0x7F00) >> 1) | (dlsIns.ulBank & 0x7F); - if((bank >= 0x4000) || (insbank == bank)) - { - if(isDrum && (dlsIns.ulBank & F_INSTRUMENT_DRUMS)) - { - if((program >= 0x80) || (program == (dlsIns.ulInstrument & 0x7F))) - { - for(const auto ®ion : dlsIns.Regions) - { - if(region.IsDummy()) - continue; + if(singleInstr) + return l < r; + else + return l.ulBank < r.ulBank; + }; - if((!key || key >= 0x80) - || (key >= region.uKeyMin && key <= region.uKeyMax)) - { - if(pInsNo) - *pInsNo = static_cast(std::distance(m_Instruments.data(), &dlsIns)); - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime - return &dlsIns; - } - } - } - } else if(!isDrum && !(dlsIns.ulBank & F_INSTRUMENT_DRUMS)) + DLSINSTRUMENT findInstr{}; + findInstr.ulInstrument = program; + findInstr.ulBank = minBank; + const auto minInstr = std::lower_bound(m_Instruments.begin(), m_Instruments.end(), findInstr, CompareInstrFunc); + findInstr.ulBank = maxBank; + const auto maxInstr = std::upper_bound(m_Instruments.begin(), m_Instruments.end(), findInstr, CompareInstrFunc); + const auto instrRange = mpt::as_span(m_Instruments.data() + std::distance(m_Instruments.begin(), minInstr), std::distance(minInstr, maxInstr)); + + for(const DLSINSTRUMENT &dlsIns : instrRange) + { + if((program < 0x80) && program != (dlsIns.ulInstrument & 0x7F)) + continue; + + if(isDrum) + { + const bool anyKey = !key || key >= 0x80; + for(const auto ®ion : dlsIns.Regions) { - if((program >= 0x80) || (program == (dlsIns.ulInstrument & 0x7F))) + if(region.IsDummy()) + continue; + + if(anyKey || (key >= region.uKeyMin && key <= region.uKeyMax)) { if(pInsNo) *pInsNo = static_cast(std::distance(m_Instruments.data(), &dlsIns)); - // cppcheck false-positive - // cppcheck-suppress returnDanglingLifetime return &dlsIns; + } else if(region.uKeyMin > key) + { + // Regions are sorted, if we arrived here we won't find anything in the remaining regions + break; } } + } else + { + if(pInsNo) + *pInsNo = static_cast(std::distance(m_Instruments.data(), &dlsIns)); + return &dlsIns; } } @@ -779,13 +876,14 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chu if(!(pDlsIns->ulBank & F_INSTRUMENT_DRUMS)) { pDlsIns->nMelodicEnv = static_cast(m_Envelopes.size() + 1); + } else + { + if(!pDlsIns->Regions.empty()) + pDlsIns->Regions.back().uPercEnv = static_cast(m_Envelopes.size() + 1); } if(art1.cbSize + art1.cConnectionBlocks * sizeof(ConnectionBlock) > header.len) break; DLSENVELOPE dlsEnv; - MemsetZero(dlsEnv); - dlsEnv.nDefPan = 128; - dlsEnv.nVolSustainLevel = 128; //Log(" art1 (%3d bytes): cbSize=%d cConnectionBlocks=%d\n", p->len, p->cbSize, p->cConnectionBlocks); chunk.Seek(sizeof(IFFCHUNK) + art1.cbSize); for (uint32 iblk = 0; iblk < art1.cConnectionBlocks; iblk++) @@ -802,57 +900,85 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chu case ART_DEFAULTPAN: { int32 pan = 128 + blk.lScale / (65536000/128); - dlsEnv.nDefPan = mpt::saturate_cast(pan); + dlsEnv.defaultPan = mpt::saturate_cast(pan); } break; + case ART_VOL_EG_DELAYTIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.volumeEnv.delay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + case ART_VOL_EG_ATTACKTIME: // 32-bit time cents units. range = [0s, 20s] - dlsEnv.wVolAttack = 0; if(blk.lScale > -0x40000000) { - int32 l = blk.lScale - 78743200; // maximum velocity - if (l > 0) l = 0; - int32 attacktime = DLS32BitTimeCentsToMilliseconds(l); - if (attacktime < 0) attacktime = 0; - if (attacktime > 20000) attacktime = 20000; - if (attacktime >= 20) dlsEnv.wVolAttack = (uint16)(attacktime / 20); - //Log("%3d: Envelope Attack Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), attacktime, pblk->lScale); + int32 l = std::min(0, blk.lScale - 78743200); // maximum velocity + dlsEnv.volumeEnv.attack = DLSEnvelopeTimeCentsToMilliseconds(l); } break; + case ART_VOL_EG_HOLDTIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.volumeEnv.hold = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + case ART_VOL_EG_DECAYTIME: // 32-bit time cents units. range = [0s, 20s] - dlsEnv.wVolDecay = 0; - if(blk.lScale > -0x40000000) - { - int32 decaytime = DLS32BitTimeCentsToMilliseconds(blk.lScale); - if (decaytime > 20000) decaytime = 20000; - if (decaytime >= 20) dlsEnv.wVolDecay = (uint16)(decaytime / 20); - //Log("%3d: Envelope Decay Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), decaytime, pblk->lScale); - } + dlsEnv.volumeEnv.decay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_RELEASETIME: // 32-bit time cents units. range = [0s, 20s] - dlsEnv.wVolRelease = 0; - if(blk.lScale > -0x40000000) - { - int32 releasetime = DLS32BitTimeCentsToMilliseconds(blk.lScale); - if (releasetime > 20000) releasetime = 20000; - if (releasetime >= 20) dlsEnv.wVolRelease = (uint16)(releasetime / 20); - //Log("%3d: Envelope Release Time set to %d (%d time cents)\n", (uint32)(dlsEnv.ulInstrument & 0x7F)|((dlsEnv.ulBank >> 16) & 0x8000), dlsEnv.wVolRelease, pblk->lScale); - } + dlsEnv.volumeEnv.release = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); break; case ART_VOL_EG_SUSTAINLEVEL: // 0.1% units if(blk.lScale >= 0) { - dlsEnv.nVolSustainLevel = DLSSustainLevelToLinear(blk.lScale); + dlsEnv.volumeEnv.sustainLevel = DLSSustainLevelToLinear(blk.lScale); } break; + case ART_PITCH_EG_DELAYTIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.pitchEnv.delay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + + case ART_PITCH_EG_ATTACKTIME: + // 32-bit time cents units. range = [0s, 20s] + if(blk.lScale > -0x40000000) + { + int32 l = std::min(0, blk.lScale - 78743200); // maximum velocity + dlsEnv.pitchEnv.attack = DLSEnvelopeTimeCentsToMilliseconds(l); + } + break; + + case ART_PITCH_EG_HOLDTIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.pitchEnv.hold = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + + case ART_PITCH_EG_DECAYTIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.pitchEnv.decay = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + + case ART_PITCH_EG_RELEASETIME: + // 32-bit time cents units. range = [0s, 20s] + dlsEnv.pitchEnv.release = DLSEnvelopeTimeCentsToMilliseconds(blk.lScale); + break; + + case ART_PITCH_EG_SUSTAINLEVEL: + // 0.1% units + dlsEnv.pitchEnv.sustainLevel = DLSSustainLevelToLinear(blk.lScale); + break; + + case ART_PITCH_EG_DEPTH: + dlsEnv.pitchEnvDepth = mpt::saturate_cast(blk.lScale / 65536); + break; + //default: // Log(" Articulation = 0x%08X value=%d\n", dwArticulation, blk.lScale); } @@ -864,15 +990,15 @@ bool CDLSBank::UpdateInstrumentDefinition(DLSINSTRUMENT *pDlsIns, FileReader chu case IFFID_INAM: chunk.ReadString(pDlsIns->szName, header.len); break; - #if 0 default: - { - char sid[5]; +#ifdef DLSINSTR_LOG + { + char sid[5]{}; memcpy(sid, &header.id, 4); - sid[4] = 0; - Log(" \"%s\": %d bytes\n", (uint32)sid, header.len.get()); + MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Unsupported DLS chunk: {} ({} bytes)")(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(sid)), header.len.get())); } - #endif +#endif + break; } } return true; @@ -1010,27 +1136,20 @@ bool CDLSBank::UpdateSF2PresetData(SF2LoaderInfo &sf2info, const IFFCHUNK &heade } break; - #ifdef DLSINSTR_LOG default: +#ifdef DLSINSTR_LOG { - char sdbg[5]; + char sdbg[5]{}; memcpy(sdbg, &header.id, 4); - sdbg[4] = 0; MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Unsupported SF2 chunk: {} ({} bytes)")(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(sdbg)), header.len.get())); } - #endif +#endif + break; } return true; } -static int16 SF2TimeToDLS(int16 amount) -{ - int32 time = CDLSBank::DLS32BitTimeCentsToMilliseconds(static_cast(amount) << 16); - return static_cast(Clamp(time, 20, 20000) / 20); -} - - // Convert all instruments to the DLS format bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) { @@ -1049,12 +1168,6 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) DLSENVELOPE dlsEnv; int32 instrAttenuation = 0; int16 instrFinetune = 0; - // Default Envelope Values - dlsEnv.wVolAttack = 0; - dlsEnv.wVolDecay = 0; - dlsEnv.wVolRelease = 0; - dlsEnv.nVolSustainLevel = 128; - dlsEnv.nDefPan = 128; // Load Preset Bags sf2info.presetBags.Seek(dlsIns.wPresetBagNdx * sizeof(SFPresetBag)); for(uint32 ipbagcnt = 0; ipbagcnt < dlsIns.wPresetBagNum; ipbagcnt++) @@ -1074,22 +1187,6 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) const int16 value = static_cast(gen.genAmount); switch(gen.sfGenOper) { - case SF2_GEN_ATTACKVOLENV: - dlsEnv.wVolAttack = SF2TimeToDLS(gen.genAmount); - break; - case SF2_GEN_DECAYVOLENV: - dlsEnv.wVolDecay = SF2TimeToDLS(gen.genAmount); - break; - case SF2_GEN_SUSTAINVOLENV: - // 0.1% units - if(gen.genAmount >= 0) - { - dlsEnv.nVolSustainLevel = SF2SustainLevelToLinear(gen.genAmount); - } - break; - case SF2_GEN_RELEASEVOLENV: - dlsEnv.wVolRelease = SF2TimeToDLS(gen.genAmount); - break; case SF2_GEN_INSTRUMENT: if(const auto instr = std::make_pair(gen.genAmount.get(), keyRange); !mpt::contains(instruments, instr)) instruments.push_back(instr); @@ -1107,12 +1204,15 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) case SF2_GEN_FINETUNE: instrFinetune += static_cast(Util::muldiv(static_cast(value), 128, 100)); break; -#if 0 default: - Log("Ins %3d: bag %3d gen %3d: ", nIns, ipbagndx, ipgenndx); - Log("genoper=%d amount=0x%04X ", gen.sfGenOper, gen.genAmount); - Log((pSmp->ulBank & F_INSTRUMENT_DRUMS) ? "(drum)\n" : "\n"); + if(!gen.ApplyToEnvelope(dlsEnv)) + { +#ifdef DLSINSTR_LOG + MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Preset {} bag {} gen {}: genoper={} amount={}{}") + (static_cast(&dlsIns - m_Instruments.data()), ipbagcnt, static_cast(&gen - generators.data()), gen.sfGenOper, gen.genAmount, (dlsIns.ulBank & F_INSTRUMENT_DRUMS) ? U_(" (drum)") : U_(""))); #endif + } + break; } } } @@ -1164,6 +1264,13 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) DLSREGION rgn = globalZone; + if(dlsIns.ulBank & F_INSTRUMENT_DRUMS) + { + m_Envelopes.push_back(dlsEnv); + rgn.uPercEnv = static_cast(m_Envelopes.size()); + pDlsEnv = &m_Envelopes[rgn.uPercEnv - 1]; + } + // Region Default Values int32 regionAttn = 0; // Load Generators @@ -1198,28 +1305,12 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) case SF2_GEN_UNITYNOTE: if (value < 128) rgn.uUnityNote = static_cast(value); break; - case SF2_GEN_ATTACKVOLENV: - pDlsEnv->wVolAttack = SF2TimeToDLS(gen.genAmount); - break; - case SF2_GEN_DECAYVOLENV: - pDlsEnv->wVolDecay = SF2TimeToDLS(gen.genAmount); - break; - case SF2_GEN_SUSTAINVOLENV: - // 0.1% units - if(gen.genAmount >= 0) - { - pDlsEnv->nVolSustainLevel = SF2SustainLevelToLinear(gen.genAmount); - } - break; - case SF2_GEN_RELEASEVOLENV: - pDlsEnv->wVolRelease = SF2TimeToDLS(gen.genAmount); - break; case SF2_GEN_PAN: { int32 pan = static_cast(value); pan = std::clamp(Util::muldivr(pan + 500, 256, 1000), 0, 256); rgn.panning = static_cast(pan); - pDlsEnv->nDefPan = mpt::saturate_cast(pan); + pDlsEnv->defaultPan = mpt::saturate_cast(pan); } break; case SF2_GEN_ATTENUATION: @@ -1268,8 +1359,15 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) case SF2_GEN_END_LOOP_COARSE: loopEnd += static_cast(value) * 32768; break; - //default: - // Log(" gen=%d value=%04X\n", pgen->sfGenOper, pgen->genAmount); + default: + if(!gen.ApplyToEnvelope(*pDlsEnv)) + { +#ifdef DLSINSTR_LOG + MPT_LOG_GLOBAL(LogDebug, "DLSINSTR", MPT_UFORMAT("Instr {} region {} gen {}: genoper={} amount={}{}") + (nInstrNdx, nRgn, static_cast(&gen - instrGenerators.data()), gen.sfGenOper, gen.genAmount, (dlsIns.ulBank & F_INSTRUMENT_DRUMS) ? U_(" (drum)") : U_(""))); +#endif + } + break; } } int32 linearVol = DLS32BitRelativeGainToLinear(((instrAttenuation + regionAttn) * 65536) / 10) / 256; @@ -1280,7 +1378,6 @@ bool CDLSBank::ConvertSF2ToDLS(SF2LoaderInfo &sf2info) globalZone = rgn; else if(!rgn.IsDummy()) dlsIns.Regions.push_back(rgn); - //Log("\n"); } } } @@ -1295,7 +1392,7 @@ bool CDLSBank::Open(const mpt::PathString &filename) { if(filename.empty()) return false; m_szFileName = filename; - InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); if(!f.IsValid()) return false; return Open(GetFileReader(f)); } @@ -1549,9 +1646,17 @@ bool CDLSBank::Open(FileReader file) { ConvertSF2ToDLS(sf2info); } -#ifdef DLSBANK_LOG - MPT_LOG_GLOBAL(LogDebug, "DLSBANK", U_("DLS bank closed")); -#endif + + // FindInstrument requires the instrument to be sorted for picking the best instrument from the MIDI library when there are multiple banks. + // And of course this is also helpful for creating the treeview UI + std::sort(m_Instruments.begin(), m_Instruments.end()); + // Sort regions (for drums) + for(auto &instr : m_Instruments) + { + std::sort(instr.Regions.begin(), instr.Regions.end(), [](const DLSREGION &l, const DLSREGION &r) + { return std::tie(l.uKeyMin, l.uKeyMax) < std::tie(r.uKeyMin, r.uKeyMax); }); + } + return true; } @@ -1566,7 +1671,10 @@ uint32 CDLSBank::GetRegionFromKey(uint32 nIns, uint32 nKey) const for(uint32 rgn = 0; rgn < static_cast(dlsIns.Regions.size()); rgn++) { const auto ®ion = dlsIns.Regions[rgn]; - if(nKey < region.uKeyMin || nKey > region.uKeyMax) + // Regions are sorted, if we arrived here we won't find anything in the remaining regions + if(region.uKeyMin > nKey) + break; + if(nKey > region.uKeyMax) continue; if(region.nWaveLink == Util::MaxValueOfType(region.nWaveLink)) continue; @@ -1643,7 +1751,7 @@ bool CDLSBank::ExtractWaveForm(uint32 nIns, uint32 nRgn, std::vector &wav { waveData.assign(chunk.len + sizeof(IFFCHUNK), 0); memcpy(waveData.data(), &chunk, sizeof(chunk)); - mpt::IO::ReadRaw(f, &waveData[sizeof(chunk)], length - sizeof(chunk)); + mpt::IO::ReadRaw(f, waveData.data() + sizeof(chunk), length - sizeof(chunk)); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -1800,6 +1908,129 @@ static uint16 ScaleEnvelope(uint32 time, float tempoScale) } +uint32 DLSENVELOPE::Envelope::ConvertToMPT(InstrumentEnvelope &mptEnv, const EnvelopeType envType, const float tempoScale, const int16 valueScale) const +{ + if(!attack && decay >= 20 * 50 && (!sustainLevel && envType != ENV_PITCH) && release >= 20 * 50) + return uint32_max; + + const EnvelopeNode::value_t neutralValue = (envType == ENV_VOLUME) ? 0 : ENVELOPE_MID; + + mptEnv.dwFlags.set(ENV_ENABLED); + mptEnv.clear(); + // Delay section + uint16 attackStart = 0; + if(delay) + { + mptEnv.push_back(0, neutralValue); + attackStart = ScaleEnvelope(delay, tempoScale); + } + // Attack section + const auto attackValue = mpt::saturate_cast(neutralValue + Util::muldivr(ENVELOPE_MAX, valueScale, 3200)); + if(attack) + { + mptEnv.push_back(attackStart, static_cast(attackValue / (attack / 2 + 2) + 8)); // /----- + mptEnv.push_back(attackStart + ScaleEnvelope(attack, tempoScale), attackValue); // | + } else + { + mptEnv.push_back(attackStart, attackValue); + } + // Hold section + if(EnvelopeNode::tick_t holdTick = attackStart + ScaleEnvelope(attack + hold, tempoScale); hold > 0 && holdTick > mptEnv.back().tick) + mptEnv.push_back(holdTick, attackValue); + // Sustain Level + if(sustainLevel > 0 || envType == ENV_PITCH) + { + if(sustainLevel < 128) + { + uint16 lStartTime = mptEnv.back().tick; + int32 lSusLevel = -CDLSBank::DLS32BitRelativeLinearToGain(sustainLevel << 9) / 65536; + int32 lDecayTime = 1; + if(lSusLevel > 0) + { + lDecayTime = (lSusLevel * (int32)decay) / 960; + for(uint32 i = 0; i < 7; i++) + { + int32 lFactor = 128 - (1 << i); + if(lFactor <= sustainLevel) break; + int32 lev = -CDLSBank::DLS32BitRelativeLinearToGain(lFactor << 9) / 65536; + if(lev > 0) + { + int32 ltime = (lev * (int32)decay) / 960; + if((ltime > 1) && (ltime < lDecayTime)) + { + uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); + if(tick > mptEnv.back().tick) + { + mptEnv.push_back(tick, mpt::saturate_cast(neutralValue + Util::muldivr(lFactor, valueScale, 6400))); + } + } + } + } + } + + uint16 decayEnd = lStartTime + ScaleEnvelope(lDecayTime, tempoScale); + if(decayEnd > mptEnv.back().tick) + { + mptEnv.push_back(decayEnd, mpt::saturate_cast(neutralValue + Util::muldivr(sustainLevel + 1, valueScale, 6400))); + } + } + mptEnv.dwFlags.set(ENV_SUSTAIN); + } else + { + mptEnv.dwFlags.set(ENV_SUSTAIN); + mptEnv.push_back(mptEnv.back().tick + 1u, mptEnv.back().value); + } + mptEnv.nSustainStart = mptEnv.nSustainEnd = (uint8)(mptEnv.size() - 1); + if(mptEnv.nSustainEnd > 0 && envType == ENV_VOLUME) + mptEnv.nReleaseNode = mptEnv.nSustainEnd; + // Release section + const bool lastIsNeutral = mptEnv.back().value > 1 && mptEnv.back().value == neutralValue; + if(release && mptEnv.back().value > 1 && !lastIsNeutral) + { + int32 lReleaseTime = release; + uint16 lStartTime = mptEnv.back().tick; + int32 lStartFactor = mptEnv.back().value; + int32 lSusLevel = -CDLSBank::DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536; + int32 lDecayEndTime = (lReleaseTime * lSusLevel) / 960; + lReleaseTime -= lDecayEndTime; + int32 prevFactor = lStartFactor; + for(uint32 i = 0; i < 7; i++) + { + int32 lFactor = 1 + ((lStartFactor * 3) >> (i + 2)); + if((lFactor < 1) ||(lFactor == 1 && prevFactor == 1) || (lFactor >= lStartFactor)) + continue; + prevFactor = lFactor; + int32 lev = -CDLSBank::DLS32BitRelativeLinearToGain(lFactor << 10) / 65536; + if(lev > 0) + { + int32 ltime = (((int32)release * lev) / 960) - lDecayEndTime; + if((ltime > 1) && (ltime < lReleaseTime)) + { + uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); + if(tick > mptEnv.back().tick) + { + mptEnv.push_back(tick, mpt::saturate_cast(neutralValue + Util::muldivr(lFactor, valueScale, 3200))); + if(mptEnv.back().value == neutralValue) + break; + } + } + } + } + if(lReleaseTime < 1) lReleaseTime = 1; + auto releaseTicks = ScaleEnvelope(lReleaseTime, tempoScale); + mptEnv.push_back(lStartTime + releaseTicks, neutralValue); + if(releaseTicks > 0) + { + return 32768 / releaseTicks; + } + } else if(!lastIsNeutral) + { + mptEnv.push_back(mptEnv.back().tick + 1u, neutralValue); + } + return uint32_max; +} + + bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, uint32 nIns, uint32 nDrumRgn) const { uint32 minRegion, maxRegion, nEnv; @@ -2032,109 +2263,10 @@ bool CDLSBank::ExtractInstrument(CSoundFile &sndFile, INSTRUMENTINDEX nInstr, ui if ((nEnv) && (nEnv <= m_Envelopes.size())) { const DLSENVELOPE &part = m_Envelopes[nEnv - 1]; - // Volume Envelope - if ((part.wVolAttack) || (part.wVolDecay < 20*50) || (part.nVolSustainLevel) || (part.wVolRelease < 20*50)) - { - pIns->VolEnv.dwFlags.set(ENV_ENABLED); - // Delay section - // -> DLS level 2 - // Attack section - pIns->VolEnv.clear(); - if (part.wVolAttack) - { - pIns->VolEnv.push_back(0, (uint8)(ENVELOPE_MAX / (part.wVolAttack / 2 + 2) + 8)); // /----- - pIns->VolEnv.push_back(ScaleEnvelope(part.wVolAttack, tempoScale), ENVELOPE_MAX); // | - } else - { - pIns->VolEnv.push_back(0, ENVELOPE_MAX); - } - // Hold section - // -> DLS Level 2 - // Sustain Level - if (part.nVolSustainLevel > 0) - { - if (part.nVolSustainLevel < 128) - { - uint16 lStartTime = pIns->VolEnv.back().tick; - int32 lSusLevel = - DLS32BitRelativeLinearToGain(part.nVolSustainLevel << 9) / 65536; - int32 lDecayTime = 1; - if (lSusLevel > 0) - { - lDecayTime = (lSusLevel * (int32)part.wVolDecay) / 960; - for (uint32 i=0; i<7; i++) - { - int32 lFactor = 128 - (1 << i); - if (lFactor <= part.nVolSustainLevel) break; - int32 lev = - DLS32BitRelativeLinearToGain(lFactor << 9) / 65536; - if (lev > 0) - { - int32 ltime = (lev * (int32)part.wVolDecay) / 960; - if ((ltime > 1) && (ltime < lDecayTime)) - { - uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); - if(tick > pIns->VolEnv.back().tick) - { - pIns->VolEnv.push_back(tick, (uint8)(lFactor / 2)); - } - } - } - } - } - - uint16 decayEnd = lStartTime + ScaleEnvelope(lDecayTime, tempoScale); - if (decayEnd > pIns->VolEnv.back().tick) - { - pIns->VolEnv.push_back(decayEnd, (uint8)((part.nVolSustainLevel+1) / 2)); - } - } - pIns->VolEnv.dwFlags.set(ENV_SUSTAIN); - } else - { - pIns->VolEnv.dwFlags.set(ENV_SUSTAIN); - pIns->VolEnv.push_back(pIns->VolEnv.back().tick + 1u, pIns->VolEnv.back().value); - } - pIns->VolEnv.nSustainStart = pIns->VolEnv.nSustainEnd = (uint8)(pIns->VolEnv.size() - 1); - // Release section - if ((part.wVolRelease) && (pIns->VolEnv.back().value > 1)) - { - int32 lReleaseTime = part.wVolRelease; - uint16 lStartTime = pIns->VolEnv.back().tick; - int32 lStartFactor = pIns->VolEnv.back().value; - int32 lSusLevel = - DLS32BitRelativeLinearToGain(lStartFactor << 10) / 65536; - int32 lDecayEndTime = (lReleaseTime * lSusLevel) / 960; - lReleaseTime -= lDecayEndTime; - if(pIns->VolEnv.nSustainEnd > 0) - pIns->VolEnv.nReleaseNode = pIns->VolEnv.nSustainEnd; - for (uint32 i=0; i<5; i++) - { - int32 lFactor = 1 + ((lStartFactor * 3) >> (i+2)); - if ((lFactor <= 1) || (lFactor >= lStartFactor)) continue; - int32 lev = - DLS32BitRelativeLinearToGain(lFactor << 10) / 65536; - if (lev > 0) - { - int32 ltime = (((int32)part.wVolRelease * lev) / 960) - lDecayEndTime; - if ((ltime > 1) && (ltime < lReleaseTime)) - { - uint16 tick = lStartTime + ScaleEnvelope(ltime, tempoScale); - if(tick > pIns->VolEnv.back().tick) - { - pIns->VolEnv.push_back(tick, (uint8)lFactor); - } - } - } - } - if (lReleaseTime < 1) lReleaseTime = 1; - auto releaseTicks = ScaleEnvelope(lReleaseTime, tempoScale); - pIns->VolEnv.push_back(lStartTime + releaseTicks, ENVELOPE_MIN); - if(releaseTicks > 0) - { - pIns->nFadeOut = 32768 / releaseTicks; - } - } else - { - pIns->VolEnv.push_back(pIns->VolEnv.back().tick + 1u, ENVELOPE_MIN); - } - } + if(const auto fadeout = part.volumeEnv.ConvertToMPT(pIns->VolEnv, ENV_VOLUME, tempoScale, 3200); fadeout != uint32_max) + pIns->nFadeOut = fadeout; + if(std::abs(part.pitchEnvDepth) >= 50) + part.pitchEnv.ConvertToMPT(pIns->PitchEnv, ENV_PITCH, tempoScale, part.pitchEnvDepth); } if(isDrum) { @@ -2189,13 +2321,13 @@ uint16 CDLSBank::GetPanning(uint32 ins, uint32 region) const { if(rgn.uPercEnv > 0 && rgn.uPercEnv <= m_Envelopes.size()) { - return m_Envelopes[rgn.uPercEnv - 1].nDefPan; + return m_Envelopes[rgn.uPercEnv - 1].defaultPan; } } else { if(dlsIns.nMelodicEnv > 0 && dlsIns.nMelodicEnv <= m_Envelopes.size()) { - return m_Envelopes[dlsIns.nMelodicEnv - 1].nDefPan; + return m_Envelopes[dlsIns.nMelodicEnv - 1].defaultPan; } } return 128; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h index d1189d165..3f953df33 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Dlsbank.h @@ -25,17 +25,17 @@ OPENMPT_NAMESPACE_BEGIN struct DLSREGION { - uint32 ulLoopStart; - uint32 ulLoopEnd; - uint16 nWaveLink; - uint16 uPercEnv; - uint16 usVolume; // 0..256 - uint16 fuOptions; // flags + key group - int16 sFineTune; // +128 = +1 semitone - int16 panning = -1; // -1= unset (DLS), otherwise 0...256 - uint8 uKeyMin; - uint8 uKeyMax; - uint8 uUnityNote; + uint32 ulLoopStart = 0; + uint32 ulLoopEnd = 0; + uint32 uPercEnv = 0; + uint16 nWaveLink = 0; + uint16 usVolume = 256; // 0..256 + uint16 fuOptions = 0; // flags + key group + int16 sFineTune = 0; // +128 = +1 semitone + int16 panning = -1; // -1= unset (DLS), otherwise 0...256 + uint8 uKeyMin = 0; + uint8 uKeyMax = 0; + uint8 uUnityNote = 0xFF; uint8 tuning = 100; constexpr bool IsDummy() const noexcept { return uKeyMin == 0xFF || nWaveLink == Util::MaxValueOfType(nWaveLink); } @@ -43,12 +43,21 @@ struct DLSREGION struct DLSENVELOPE { - // Volume Envelope - uint16 wVolAttack; // Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] - uint16 wVolDecay; // Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] - uint16 wVolRelease; // Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] - uint8 nVolSustainLevel; // Sustain Level: 0-128, 128=100% - uint8 nDefPan; // Default Pan + struct Envelope + { + uint16 delay = 0; // Delay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] + uint16 attack = 0; // Attack Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] + uint16 hold = 0; // Hold Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] + uint16 decay = 0; // Decay Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] + uint16 release = 0; // Release Time: 0-1000, 1 = 20ms (1/50s) -> [0-20s] + uint8 sustainLevel = 128; // Sustain Level: 0-128, 128=100% + + uint32 ConvertToMPT(InstrumentEnvelope &mptEnv, const EnvelopeType envType, const float tempoScale, const int16 valueScale) const; + }; + + Envelope volumeEnv, pitchEnv; + int16 pitchEnvDepth = 0; // Cents + uint8 defaultPan = 128; }; // Special Bank bits @@ -62,6 +71,11 @@ struct DLSINSTRUMENT char szName[32]; // SF2 stuff (DO NOT USE! -> used internally by the SF2 loader) uint16 wPresetBagNdx = 0, wPresetBagNum = 0; + + constexpr bool operator<(const DLSINSTRUMENT &other) const + { + return std::tie(ulBank, ulInstrument) < std::tie(other.ulBank, other.ulInstrument); + } }; struct DLSSAMPLEEX @@ -112,7 +126,7 @@ protected: public: CDLSBank(); - bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathString::CompareNoCase(m_szFileName, other.m_szFileName); } + bool operator==(const CDLSBank &other) const noexcept { return !mpt::PathCompareNoCase(m_szFileName, other.m_szFileName); } static bool IsDLSBank(const mpt::PathString &filename); static uint32 MakeMelodicCode(uint32 bank, uint32 instr) { return ((bank << 16) | (instr));} @@ -147,6 +161,7 @@ protected: public: // DLS Unit conversion static int32 DLS32BitTimeCentsToMilliseconds(int32 lTimeCents); + static uint16 DLSEnvelopeTimeCentsToMilliseconds(int32 lTimeCents); static int32 DLS32BitRelativeGainToLinear(int32 lCentibels); // 0dB = 0x10000 static int32 DLS32BitRelativeLinearToGain(int32 lGain); // 0dB = 0x10000 static int32 DLSMidiVolumeToLinear(uint32 nMidiVolume); // [0-127] -> [0-0x10000] diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Fastmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Fastmix.cpp index 8ce8a1b8a..a73399a11 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Fastmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Fastmix.cpp @@ -69,9 +69,9 @@ struct MixLoopState lookaheadStart = chn.nLoopStart; else lookaheadStart = std::max(chn.nLoopStart, chn.nLoopEnd - InterpolationLookaheadBufferSize); - // We only need to apply the loop wrap-around logic if the sample is actually looping and if interpolation is applied. - // If there is no interpolation happening, there is no lookahead happening the sample read-out is exact. - if(chn.dwFlags[CHN_LOOP] && chn.resamplingMode != SRCMODE_NEAREST) + // We only need to apply the loop wrap-around logic if the sample is actually looping. + // As we round rather than truncate with No Interpolation, we also need the wrap-around logic for samples that are not interpolated. + if(chn.dwFlags[CHN_LOOP]) { const bool inSustainLoop = chn.InSustainLoop() && chn.nLoopStart == chn.pModSample->nSustainStart && chn.nLoopEnd == chn.pModSample->nSustainEnd; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/FloatMixer.h b/Frameworks/OpenMPT/OpenMPT/soundlib/FloatMixer.h index d53fbabc6..c594f7034 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/FloatMixer.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/FloatMixer.h @@ -29,10 +29,10 @@ struct IntToFloatTraits : public MixerTraits } }; -typedef IntToFloatTraits<2, 1, mixsample_t, int8, -int8_min> Int8MToFloatS; -typedef IntToFloatTraits<2, 1, mixsample_t, int16, -int16_min> Int16MToFloatS; -typedef IntToFloatTraits<2, 2, mixsample_t, int8, -int8_min> Int8SToFloatS; -typedef IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min> Int16SToFloatS; +using Int8MToFloatS = IntToFloatTraits<2, 1, mixsample_t, int8, -int8_min>; +using Int16MToFloatS = IntToFloatTraits<2, 1, mixsample_t, int16, -int16_min>; +using Int8SToFloatS = IntToFloatTraits<2, 2, mixsample_t, int8, -int8_min>; +using Int16SToFloatS = IntToFloatTraits<2, 2, mixsample_t, int16, -int16_min>; ////////////////////////////////////////////////////////////////////////// diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp index d83731b90..b7ed19970 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ITCompression.cpp @@ -279,7 +279,7 @@ void ITCompression::WriteBits(int8 width, int v) { while(width > remBits) { - byteVal |= (v << bitPos); + byteVal |= static_cast(v << bitPos); width -= remBits; v >>= remBits; bitPos = 0; @@ -290,7 +290,7 @@ void ITCompression::WriteBits(int8 width, int v) if(width > 0) { - byteVal |= (v & ((1 << width) - 1)) << bitPos; + byteVal |= static_cast((v & ((1 << width) - 1)) << bitPos); remBits -= width; bitPos += width; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.cpp index e72184f94..898f247e9 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.cpp @@ -511,13 +511,14 @@ void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compr cvt = ITSample::cvtOPLInstrument; } else if(mptSmp.uFlags[SMP_KEEPONDISK]) { -#ifndef MPT_EXTERNAL_SAMPLES - allowExternal = false; -#endif // MPT_EXTERNAL_SAMPLES // Save external sample (filename at sample pointer) - if(allowExternal && mptSmp.HasSampleData()) + if(mptSmp.HasSampleData()) { - cvt = ITSample::cvtExternalSample; +#if !defined(MPT_EXTERNAL_SAMPLES) + allowExternal = false; +#endif // MPT_EXTERNAL_SAMPLES + if(allowExternal) + cvt = ITSample::cvtExternalSample; } else { length = loopbegin = loopend = susloopbegin = susloopend = 0; @@ -637,15 +638,15 @@ SampleIO ITSample::GetSampleFormat(uint16 cwtv) const void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const { // Decode FAT date and time - MemsetZero(mptHistory.loadDate); + mptHistory.loadDate = mpt::Date::AnyGregorian{}; if(fatdate != 0 || fattime != 0) { - mptHistory.loadDate.tm_year = ((fatdate >> 9) & 0x7F) + 80; - mptHistory.loadDate.tm_mon = Clamp((fatdate >> 5) & 0x0F, 1, 12) - 1; - mptHistory.loadDate.tm_mday = Clamp(fatdate & 0x1F, 1, 31); - mptHistory.loadDate.tm_hour = Clamp((fattime >> 11) & 0x1F, 0, 23); - mptHistory.loadDate.tm_min = Clamp((fattime >> 5) & 0x3F, 0, 59); - mptHistory.loadDate.tm_sec = Clamp((fattime & 0x1F) * 2, 0, 59); + mptHistory.loadDate.year = ((fatdate >> 9) & 0x7F) + 1980; + mptHistory.loadDate.month = Clamp((fatdate >> 5) & 0x0F, 1, 12); + mptHistory.loadDate.day = Clamp(fatdate & 0x1F, 1, 31); + mptHistory.loadDate.hours = Clamp((fattime >> 11) & 0x1F, 0, 23); + mptHistory.loadDate.minutes = Clamp((fattime >> 5) & 0x3F, 0, 59); + mptHistory.loadDate.seconds = Clamp((fattime & 0x1F) * 2, 0, 59); } mptHistory.openTime = static_cast(runtime * (HISTORY_TIMER_PRECISION / 18.2)); } @@ -657,8 +658,8 @@ void ITHistoryStruct::ConvertToIT(const FileHistory &mptHistory) // Create FAT file dates if(mptHistory.HasValidDate()) { - fatdate = static_cast(mptHistory.loadDate.tm_mday | ((mptHistory.loadDate.tm_mon + 1) << 5) | ((mptHistory.loadDate.tm_year - 80) << 9)); - fattime = static_cast((mptHistory.loadDate.tm_sec / 2) | (mptHistory.loadDate.tm_min << 5) | (mptHistory.loadDate.tm_hour << 11)); + fatdate = static_cast(mptHistory.loadDate.day | (mptHistory.loadDate.month << 5) | ((mptHistory.loadDate.year - 1980) << 9)); + fattime = static_cast((mptHistory.loadDate.seconds / 2) | (mptHistory.loadDate.minutes << 5) | (mptHistory.loadDate.hours << 11)); } else { fatdate = 0; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.h index 4176df70a..6d6013d8d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ITTools.h @@ -23,49 +23,49 @@ struct ITFileHeader // Header Flags enum ITHeaderFlags { - useStereoPlayback = 0x01, - vol0Optimisations = 0x02, - instrumentMode = 0x04, - linearSlides = 0x08, - itOldEffects = 0x10, - itCompatGxx = 0x20, - useMIDIPitchController = 0x40, - reqEmbeddedMIDIConfig = 0x80, - extendedFilterRange = 0x1000, + useStereoPlayback = 0x01, + vol0Optimisations = 0x02, + instrumentMode = 0x04, + linearSlides = 0x08, + itOldEffects = 0x10, + itCompatGxx = 0x20, + useMIDIPitchController = 0x40, + reqEmbeddedMIDIConfig = 0x80, + extendedFilterRange = 0x1000, }; // Special Flags enum ITHeaderSpecialFlags { - embedSongMessage = 0x01, - embedEditHistory = 0x02, - embedPatternHighlights = 0x04, - embedMIDIConfiguration = 0x08, + embedSongMessage = 0x01, + embedEditHistory = 0x02, + embedPatternHighlights = 0x04, + embedMIDIConfiguration = 0x08, }; - char id[4]; // Magic Bytes (IMPM) - char songname[26]; // Song Name, null-terminated (but may also contain nulls) - uint8le highlight_minor; // Rows per Beat highlight - uint8le highlight_major; // Rows per Measure highlight - uint16le ordnum; // Number of Orders - uint16le insnum; // Number of Instruments - uint16le smpnum; // Number of Samples - uint16le patnum; // Number of Patterns - uint16le cwtv; // "Made With" Tracker - uint16le cmwt; // "Compatible With" Tracker - uint16le flags; // Header Flags - uint16le special; // Special Flags, for embedding extra information - uint8le globalvol; // Global Volume (0...128) - uint8le mv; // Master Volume (0...128), referred to as Sample Volume in OpenMPT - uint8le speed; // Initial Speed (1...255) - uint8le tempo; // Initial Tempo (31...255) - uint8le sep; // Pan Separation (0...128) - uint8le pwd; // Pitch Wheel Depth - uint16le msglength; // Length of Song Message - uint32le msgoffset; // Offset of Song Message in File (IT crops message after first null) - uint32le reserved; // Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT and Schism Tracker save extended version information here. - uint8le chnpan[64]; // Initial Channel Panning - uint8le chnvol[64]; // Initial Channel Volume + char id[4]; // Magic Bytes (IMPM) + char songname[26]; // Song Name, null-terminated (but may also contain nulls) + uint8le highlight_minor; // Rows per Beat highlight + uint8le highlight_major; // Rows per Measure highlight + uint16le ordnum; // Number of Orders + uint16le insnum; // Number of Instruments + uint16le smpnum; // Number of Samples + uint16le patnum; // Number of Patterns + uint16le cwtv; // "Made With" Tracker + uint16le cmwt; // "Compatible With" Tracker + uint16le flags; // Header Flags + uint16le special; // Special Flags, for embedding extra information + uint8le globalvol; // Global Volume (0...128) + uint8le mv; // Master Volume (0...128), referred to as Sample Volume in OpenMPT + uint8le speed; // Initial Speed (1...255) + uint8le tempo; // Initial Tempo (31...255) + uint8le sep; // Pan Separation (0...128) + uint8le pwd; // Pitch Wheel Depth + uint16le msglength; // Length of Song Message + uint32le msgoffset; // Offset of Song Message in File (IT crops message after first null) + uint32le reserved; // Some IT versions save an edit timer here. ChibiTracker writes "CHBI" here. OpenMPT and Schism Tracker save extended version information here. + uint8le chnpan[64]; // Initial Channel Panning + uint8le chnvol[64]; // Initial Channel Volume }; MPT_BINARY_STRUCT(ITFileHeader, 192) @@ -76,11 +76,11 @@ struct ITEnvelope // Envelope Flags enum ITEnvelopeFlags { - envEnabled = 0x01, - envLoop = 0x02, - envSustain = 0x04, - envCarry = 0x08, - envFilter = 0x80, + envEnabled = 0x01, + envLoop = 0x02, + envSustain = 0x04, + envCarry = 0x08, + envFilter = 0x80, }; struct Node @@ -89,14 +89,14 @@ struct ITEnvelope uint16le tick; }; - uint8 flags; // Envelope Flags - uint8 num; // Number of Envelope Nodes - uint8 lpb; // Loop Start - uint8 lpe; // Loop End - uint8 slb; // Sustain Start - uint8 sle; // Sustain End - Node data[25]; // Envelope Node Positions / Values - uint8 reserved; // Reserved + uint8 flags; // Envelope Flags + uint8 num; // Number of Envelope Nodes + uint8 lpb; // Loop Start + uint8 lpe; // Loop End + uint8 slb; // Sustain Start + uint8 sle; // Sustain End + Node data[25]; // Envelope Node Positions / Values + uint8 reserved; // Reserved // Convert OpenMPT's internal envelope format to an IT/MPTM envelope. void ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault); @@ -113,30 +113,30 @@ struct ITOldInstrument { enum ITOldInstrFlags { - envEnabled = 0x01, - envLoop = 0x02, - envSustain = 0x04, + envEnabled = 0x01, + envLoop = 0x02, + envSustain = 0x04, }; - char id[4]; // Magic Bytes (IMPI) - char filename[13]; // DOS Filename, null-terminated - uint8le flags; // Volume Envelope Flags - uint8le vls; // Envelope Loop Start - uint8le vle; // Envelope Loop End - uint8le sls; // Envelope Sustain Start - uint8le sle; // Envelope Sustain End - char reserved1[2]; // Reserved - uint16le fadeout; // Instrument Fadeout (0...128) - uint8le nna; // New Note Action - uint8le dnc; // Duplicate Note Check Type - uint16le trkvers; // Tracker ID - uint8le nos; // Number of embedded samples - char reserved2; // Reserved - char name[26]; // Instrument Name, null-terminated (but may also contain nulls) - char reserved3[6]; // Even more reserved bytes - uint8le keyboard[240]; // Sample / Transpose map - uint8le volenv[200]; // This appears to be a pre-computed (interpolated) version of the volume envelope data found below. - uint8le nodes[25 * 2]; // Volume Envelope Node Positions / Values + char id[4]; // Magic Bytes (IMPI) + char filename[13]; // DOS Filename, null-terminated + uint8le flags; // Volume Envelope Flags + uint8le vls; // Envelope Loop Start + uint8le vle; // Envelope Loop End + uint8le sls; // Envelope Sustain Start + uint8le sle; // Envelope Sustain End + char reserved1[2]; // Reserved + uint16le fadeout; // Instrument Fadeout (0...128) + uint8le nna; // New Note Action + uint8le dnc; // Duplicate Note Check Type + uint16le trkvers; // Tracker ID + uint8le nos; // Number of embedded samples + char reserved2; // Reserved + char name[26]; // Instrument Name, null-terminated (but may also contain nulls) + char reserved3[6]; // Even more reserved bytes + uint8le keyboard[240]; // Sample / Transpose map + uint8le volenv[200]; // This appears to be a pre-computed (interpolated) version of the volume envelope data found below. + uint8le nodes[25 * 2]; // Volume Envelope Node Positions / Values // Convert an ITOldInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; @@ -148,39 +148,39 @@ MPT_BINARY_STRUCT(ITOldInstrument, 554) // Impulse Instrument Format struct ITInstrument { - enum ITInstrumentFlags + enum ITInstrumentFlags : uint8 { - ignorePanning = 0x80, - enableCutoff = 0x80, - enableResonance = 0x80, + ignorePanning = 0x80, + enableCutoff = 0x80, + enableResonance = 0x80, }; - char id[4]; // Magic Bytes (IMPI) - char filename[13]; // DOS Filename, null-terminated - uint8le nna; // New Note Action - uint8le dct; // Duplicate Note Check Type - uint8le dca; // Duplicate Note Check Action - uint16le fadeout; // Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128) - int8le pps; // Pitch/Pan Separatation - uint8le ppc; // Pitch/Pan Centre - uint8le gbv; // Global Volume - uint8le dfp; // Panning - uint8le rv; // Vol Swing - uint8le rp; // Pan Swing - uint16le trkvers; // Tracker ID - uint8le nos; // Number of embedded samples - char reserved1; // Reserved - char name[26]; // Instrument Name, null-terminated (but may also contain nulls) - uint8le ifc; // Filter Cutoff - uint8le ifr; // Filter Resonance - uint8le mch; // MIDI Channel - uint8le mpr; // MIDI Program - uint8le mbank[2]; // MIDI Bank - uint8le keyboard[240]; // Sample / Transpose map - ITEnvelope volenv; // Volume Envelope - ITEnvelope panenv; // Pan Envelope - ITEnvelope pitchenv; // Pitch / Filter Envelope - char dummy[4]; // IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks. + char id[4]; // Magic Bytes (IMPI) + char filename[13]; // DOS Filename, null-terminated + uint8le nna; // New Note Action + uint8le dct; // Duplicate Note Check Type + uint8le dca; // Duplicate Note Check Action + uint16le fadeout; // Instrument Fadeout (0...256, although values up to 1024 would be sensible. Up to IT2.07, the limit was 0...128) + int8le pps; // Pitch/Pan Separatation + uint8le ppc; // Pitch/Pan Centre + uint8le gbv; // Global Volume + uint8le dfp; // Panning + uint8le rv; // Vol Swing + uint8le rp; // Pan Swing + uint16le trkvers; // Tracker ID + uint8le nos; // Number of embedded samples + char reserved1; // Reserved + char name[26]; // Instrument Name, null-terminated (but may also contain nulls) + uint8le ifc; // Filter Cutoff + uint8le ifr; // Filter Resonance + uint8le mch; // MIDI Channel + uint8le mpr; // MIDI Program + uint8le mbank[2]; // MIDI Bank + uint8le keyboard[240]; // Sample / Transpose map + ITEnvelope volenv; // Volume Envelope + ITEnvelope panenv; // Pan Envelope + ITEnvelope pitchenv; // Pitch / Filter Envelope + char dummy[4]; // IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks. // Convert OpenMPT's internal instrument representation to an ITInstrument. Returns amount of bytes that need to be written. uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); @@ -194,8 +194,8 @@ MPT_BINARY_STRUCT(ITInstrument, 554) // MPT IT Instrument Extension struct ITInstrumentEx { - ITInstrument iti; // Normal IT Instrument - uint8 keyboardhi[120]; // High Byte of Sample map + ITInstrument iti; // Normal IT Instrument + uint8 keyboardhi[120]; // High Byte of Sample map // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written. uint32 ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); @@ -209,55 +209,49 @@ MPT_BINARY_STRUCT(ITInstrumentEx, sizeof(ITInstrument) + 120) // IT Sample Format struct ITSample { - // Magic Bytes - enum Magic + enum ITSampleFlags : uint8 { - magic = 0x53504D49, // "IMPS" IT Sample Header Magic Bytes - }; + sampleDataPresent = 0x01, + sample16Bit = 0x02, + sampleStereo = 0x04, + sampleCompressed = 0x08, + sampleLoop = 0x10, + sampleSustain = 0x20, + sampleBidiLoop = 0x40, + sampleBidiSustain = 0x80, - enum ITSampleFlags - { - sampleDataPresent = 0x01, - sample16Bit = 0x02, - sampleStereo = 0x04, - sampleCompressed = 0x08, - sampleLoop = 0x10, - sampleSustain = 0x20, - sampleBidiLoop = 0x40, - sampleBidiSustain = 0x80, + enablePanning = 0x80, - enablePanning = 0x80, - - cvtSignedSample = 0x01, - cvtOPLInstrument = 0x40, // FM instrument in MPTM - cvtExternalSample = 0x80, // Keep MPTM sample on disk - cvtADPCMSample = 0xFF, // MODPlugin :( + cvtSignedSample = 0x01, + cvtOPLInstrument = 0x40, // FM instrument in MPTM + cvtExternalSample = 0x80, // Keep MPTM sample on disk + cvtADPCMSample = 0xFF, // MODPlugin :( // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :) - cvtBigEndian = 0x02, - cvtDelta = 0x04, - cvtPTM8to16 = 0x08, + cvtBigEndian = 0x02, + cvtDelta = 0x04, + cvtPTM8to16 = 0x08, }; - char id[4]; // Magic Bytes (IMPS) - char filename[13]; // DOS Filename, null-terminated - uint8le gvl; // Global Volume - uint8le flags; // Sample Flags - uint8le vol; // Default Volume - char name[26]; // Sample Name, null-terminated (but may also contain nulls) - uint8le cvt; // Sample Import Format - uint8le dfp; // Sample Panning - uint32le length; // Sample Length (in samples) - uint32le loopbegin; // Sample Loop Begin (in samples) - uint32le loopend; // Sample Loop End (in samples) - uint32le C5Speed; // C-5 frequency - uint32le susloopbegin; // Sample Sustain Begin (in samples) - uint32le susloopend; // Sample Sustain End (in samples) - uint32le samplepointer; // Pointer to sample data - uint8le vis; // Auto-Vibrato Rate (called Sweep in IT) - uint8le vid; // Auto-Vibrato Depth - uint8le vir; // Auto-Vibrato Sweep (called Rate in IT) - uint8le vit; // Auto-Vibrato Type + char id[4]; // Magic Bytes (IMPS) + char filename[13]; // DOS Filename, null-terminated + uint8le gvl; // Global Volume + uint8le flags; // Sample Flags + uint8le vol; // Default Volume + char name[26]; // Sample Name, null-terminated (but may also contain nulls) + uint8le cvt; // Sample Import Format + uint8le dfp; // Sample Panning + uint32le length; // Sample Length (in samples) + uint32le loopbegin; // Sample Loop Begin (in samples) + uint32le loopend; // Sample Loop End (in samples) + uint32le C5Speed; // C-5 frequency + uint32le susloopbegin; // Sample Sustain Begin (in samples) + uint32le susloopend; // Sample Sustain End (in samples) + uint32le samplepointer; // Pointer to sample data + uint8le vis; // Auto-Vibrato Rate (called Sweep in IT) + uint8le vid; // Auto-Vibrato Depth + uint8le vir; // Auto-Vibrato Sweep (called Rate in IT) + uint8le vit; // Auto-Vibrato Type // Convert OpenMPT's internal sample representation to an ITSample. void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp index 8698e73e9..8997a111a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/InstrumentExtensions.cpp @@ -345,7 +345,7 @@ template static bool IsPropertyNeeded(const TIns &Instruments, PropType ModInstrument::*Prop) { const ModInstrument defaultIns; - for(const auto &ins : Instruments) + for(const auto ins : Instruments) { if(ins != nullptr && defaultIns.*Prop != ins->*Prop) return true; @@ -389,11 +389,28 @@ void CSoundFile::SaveExtendedInstrumentProperties(INSTRUMENTINDEX numInstruments if(!(GetType() & MOD_TYPE_XM)) { // XM instrument headers already stores full-precision fade-out - WritePropertyIfNeeded(*this, &ModInstrument::nFadeOut, MagicBE("FO.."), sizeof(ModInstrument::nFadeOut), f, numInstruments); + bool writeFadeOut = false, writePan = false, writePWD = false; + int32 prevPWD = int32_min; + for(const auto ins : Instruments) + { + if(ins == nullptr) + continue; + if((ins->nFadeOut % 32u) || ins->nFadeOut > 8192) + writeFadeOut = true; + if(ins->dwFlags[INS_SETPANNING] && (ins->nPan % 4u)) + writePan = true; + if((prevPWD != int32_min && ins->midiPWD != prevPWD) || (ins->midiPWD < 0)) + writePWD = true; + prevPWD = ins->midiPWD; + } + if(writeFadeOut) + WriteInstrumentPropertyForAllInstruments(MagicBE("FO.."), sizeof(ModInstrument::nFadeOut), f, numInstruments); // XM instrument headers already have support for this - WritePropertyIfNeeded(*this, &ModInstrument::midiPWD, MagicBE("MPWD"), sizeof(ModInstrument::midiPWD), f, numInstruments); + if(writePWD) + WriteInstrumentPropertyForAllInstruments(MagicBE("MPWD"), sizeof(ModInstrument::midiPWD), f, numInstruments); // We never supported these as hacks in XM (luckily!) - WritePropertyIfNeeded(*this, &ModInstrument::nPan, MagicBE("P..."), sizeof(ModInstrument::nPan), f, numInstruments); + if(writePan) + WriteInstrumentPropertyForAllInstruments(MagicBE("P..."), sizeof(ModInstrument::nPan), f, numInstruments); WritePropertyIfNeeded(*this, &ModInstrument::nCutSwing, MagicBE("CS.."), sizeof(ModInstrument::nCutSwing), f, numInstruments); WritePropertyIfNeeded(*this, &ModInstrument::nResSwing, MagicBE("RS.."), sizeof(ModInstrument::nResSwing), f, numInstruments); WritePropertyIfNeeded(*this, &ModInstrument::filterMode, MagicBE("FM.."), sizeof(ModInstrument::filterMode), f, numInstruments); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/IntMixer.h b/Frameworks/OpenMPT/OpenMPT/soundlib/IntMixer.h index e13762194..30484b477 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/IntMixer.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/IntMixer.h @@ -22,9 +22,9 @@ OPENMPT_NAMESPACE_BEGIN template struct IntToIntTraits : public MixerTraits { - typedef MixerTraits base_t; - typedef typename base_t::input_t input_t; - typedef typename base_t::output_t output_t; + using base_t = MixerTraits; + using input_t = typename base_t::input_t; + using output_t = typename base_t::output_t; static MPT_CONSTEXPRINLINE output_t Convert(const input_t x) { @@ -36,10 +36,10 @@ struct IntToIntTraits : public MixerTraits } }; -typedef IntToIntTraits<2, 1, mixsample_t, int8, 16> Int8MToIntS; -typedef IntToIntTraits<2, 1, mixsample_t, int16, 16> Int16MToIntS; -typedef IntToIntTraits<2, 2, mixsample_t, int8, 16> Int8SToIntS; -typedef IntToIntTraits<2, 2, mixsample_t, int16, 16> Int16SToIntS; +using Int8MToIntS = IntToIntTraits<2, 1, mixsample_t, int8, 16>; +using Int16MToIntS = IntToIntTraits<2, 1, mixsample_t, int16, 16>; +using Int8SToIntS = IntToIntTraits<2, 2, mixsample_t, int8, 16>; +using Int16SToIntS = IntToIntTraits<2, 2, mixsample_t, int16, 16>; ////////////////////////////////////////////////////////////////////////// @@ -266,7 +266,7 @@ struct Ramp template struct MixMonoFastNoRamp : public NoRamp { - typedef NoRamp base_t; + using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { typename Traits::output_t vol = outSample[0] * base_t::lVol; @@ -281,7 +281,7 @@ struct MixMonoFastNoRamp : public NoRamp template struct MixMonoNoRamp : public NoRamp { - typedef NoRamp base_t; + using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { outBuffer[0] += outSample[0] * base_t::lVol; @@ -306,7 +306,7 @@ struct MixMonoRamp : public Ramp template struct MixStereoNoRamp : public NoRamp { - typedef NoRamp base_t; + using base_t = NoRamp; MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer) { outBuffer[0] += outSample[0] * base_t::lVol; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_667.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_667.cpp new file mode 100644 index 000000000..f7f78226f --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_667.cpp @@ -0,0 +1,197 @@ +/* + * Load_667.cpp + * ------------ + * Purpose: Composer 667 module loader + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Loaders.h" + +OPENMPT_NAMESPACE_BEGIN + +struct _667FileHeader +{ + using InstrName = std::array; + + char magic[2]; // 'gf' (0x6667, ha ha) + InstrName names[64]; + uint8 speed; + uint8 numOrders; + uint16le patOffsets[128]; // Relative to end of instrument definitions + + bool IsValid() const + { + if(memcmp(magic, "gf", 2) || speed < 1 || speed > 15 || numOrders > 128) + return false; + for(const auto &name : names) + { + for(const char c : name) + { + if(static_cast(c) <= 31) + return false; + } + } + int32 prevOffset = -1; + for(const int32 offset : patOffsets) + { + if(offset <= prevOffset) + return false; + prevOffset = offset; + } + return true; + } + + uint32 GetHeaderMinimumAdditionalSize() const + { + return numOrders + 64 * 11; + } +}; + +MPT_BINARY_STRUCT(_667FileHeader, 772) + + +CSoundFile::ProbeResult CSoundFile::ProbeFileHeader667(MemoryFileReader file, const uint64 *pfilesize) +{ + _667FileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return ProbeWantMoreData; + if(!fileHeader.IsValid()) + return ProbeFailure; + return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); +} + + +bool CSoundFile::Read667(FileReader &file, ModLoadingFlags loadFlags) +{ + _667FileHeader fileHeader; + + file.Rewind(); + if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) + return false; + if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) + return false; + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_S3M); + m_SongFlags.set(SONG_IMPORTED); + m_nDefaultTempo.Set(150); + m_nDefaultSpeed = fileHeader.speed; + m_nChannels = 18; + m_nSamples = 64; + + ReadOrderFromFile(Order(), file, fileHeader.numOrders); + for(PATTERNINDEX pat : Order()) + { + if(pat >= 128) + return false; + } + + InitializeChannels(); + + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + { + // Reorder OPL patch bytes (interleave modulator and carrier) + const auto fm = file.ReadArray(); + OPLPatch patch{{}}; + patch[0] = fm[1]; patch[1] = fm[6]; + patch[2] = fm[2]; patch[3] = fm[7]; + patch[4] = fm[3]; patch[5] = fm[8]; + patch[6] = fm[4]; patch[7] = fm[9]; + patch[8] = fm[5]; patch[9] = fm[10]; + patch[10] = fm[0]; + + ModSample &mptSmp = Samples[smp]; + mptSmp.Initialize(MOD_TYPE_S3M); + mptSmp.SetAdlib(true, patch); + + m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.names[smp - 1]); + } + + if(loadFlags & loadPatternData) + { + const auto patternOffset = file.GetPosition(); + bool leftChn = false, rightChn = false; + Patterns.ResizeArray(128); + for(PATTERNINDEX pat = 0; pat < 128; pat++) + { + // 4674 bytes is the largest sensible pattern size (every cell is written to exactly once + jump at end of pattern) + FileReader patData = file.GetChunkAt(patternOffset + fileHeader.patOffsets[pat], 4674); + if(!patData.IsValid() || !Patterns.Insert(pat, 32)) + break; + ROWINDEX row = 0; + auto rowData = Patterns[pat].GetRow(row); + while(patData.CanRead(1)) + { + uint8 b = patData.ReadUint8(); + if(b == 0xFF) + { + // End of row + uint8 skip = patData.ReadUint8(); + row += skip; + if(row >= 32 || skip == 0) + break; + rowData = Patterns[pat].GetRow(row); + } else if(b == 0xFE) + { + // Instrument + auto instr = patData.ReadArray(); + if(instr[0] >= m_nChannels || instr[1] > 63) + return false; + rowData[instr[0]].instr = instr[1] + 1; + } else if(b == 0xFD) + { + // Volume + auto vol = patData.ReadArray(); + if(vol[0] >= m_nChannels || vol[1] > 63) + return false; + rowData[vol[0]].SetVolumeCommand(VOLCMD_VOLUME, 63u - vol[1]); + } else if(b == 0xFC) + { + // Jump to pattern + uint8 target = patData.ReadUint8(); + rowData[0].SetEffectCommand(CMD_POSITIONJUMP, target); + } else if(b == 0xFB) + { + // Pattern break + rowData[0].SetEffectCommand(CMD_PATTERNBREAK, 0); + } else if(b < m_nChannels) + { + // Note data + uint8 note = patData.ReadUint8(); + if(note >= 0x7C) + return false; + rowData[b].note = NOTE_MIN + 12 + (note & 0x0F) + (note >> 4) * 12; + if(b % 2u) + rightChn = true; + else + leftChn = true; + } else + { + return false; + } + } + } + if(leftChn && rightChn) + { + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].nPan = (chn % 2u) ? 256 : 0; + } + } + } + + m_modFormat.formatName = UL_("Composer 667"); + m_modFormat.type = UL_("667"); + m_modFormat.madeWithTracker = UL_("Composer 667"); + m_modFormat.charset = mpt::Charset::CP437; + + return true; +} + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp index ea39fe626..402e11c49 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_669.cpp @@ -1,7 +1,7 @@ /* * Load_669.cpp * ------------ - * Purpose: 669 Composer / UNIS 669 module loader + * Purpose: Composer 669 / UNIS 669 module loader * Notes : This is better than Schism's 669 loader :) * (some of this code is "heavily inspired" by Storlek's code from Schism Tracker, and improvements have been made where necessary.) * Authors: Olivier Lapicque @@ -17,10 +17,10 @@ OPENMPT_NAMESPACE_BEGIN struct _669FileHeader { - char magic[2]; // 'if' (0x6669, ha ha) or 'JN' - char songMessage[108]; // Song Message - uint8 samples; // number of samples (1-64) - uint8 patterns; // number of patterns (1-128) + char magic[2]; // 'if' (0x6669, ha ha) or 'JN' + char songMessage[108]; // Song Message + uint8 samples; // number of samples (1-64) + uint8 patterns; // number of patterns (1-128) uint8 restartPos; uint8 orders[128]; uint8 tempoList[128]; @@ -50,8 +50,7 @@ struct _669Sample if(mptSmp.nLoopEnd > mptSmp.nLength && mptSmp.nLoopStart == 0) { mptSmp.nLoopEnd = 0; - } - if(mptSmp.nLoopEnd != 0) + } else if(mptSmp.nLoopEnd != 0) { mptSmp.uFlags = CHN_LOOP; mptSmp.SanitizeLoops(); @@ -71,6 +70,12 @@ static bool ValidateHeader(const _669FileHeader &fileHeader) { return false; } + uint8 invalidCharCount = 0; + for(const char c : fileHeader.songMessage) + { + if(c > 0 && c <= 31 && ++invalidCharCount > 40) + return false; + } for(std::size_t i = 0; i < std::size(fileHeader.breaks); i++) { if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE) @@ -189,20 +194,20 @@ bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags) static constexpr ModCommand::COMMAND effTrans[] = { - CMD_PORTAMENTOUP, // Slide up (param * 80) Hz on every tick - CMD_PORTAMENTODOWN, // Slide down (param * 80) Hz on every tick - CMD_TONEPORTAMENTO, // Slide to note by (param * 40) Hz on every tick - CMD_S3MCMDEX, // Add (param * 80) Hz to sample frequency - CMD_VIBRATO, // Add (param * 669) Hz on every other tick - CMD_SPEED, // Set ticks per row - CMD_PANNINGSLIDE, // Extended UNIS 669 effect - CMD_RETRIG, // Extended UNIS 669 effect + CMD_PORTAMENTOUP, // Slide up (param * 80) Hz on every tick + CMD_PORTAMENTODOWN, // Slide down (param * 80) Hz on every tick + CMD_TONEPORTAMENTO, // Slide to note by (param * 40) Hz on every tick + CMD_S3MCMDEX, // Add (param * 80) Hz to sample frequency + CMD_VIBRATO, // Add (param * 669) Hz on every other tick + CMD_SPEED, // Set ticks per row + CMD_PANNINGSLIDE, // Extended UNIS 669 effect + CMD_RETRIG, // Extended UNIS 669 effect }; uint8 effect[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; for(ROWINDEX row = 0; row < 64; row++) { - PatternRow m = Patterns[pat].GetRow(row); + ModCommand *m = Patterns[pat].GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < 8; chn++, m++) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp index a40b3a18d..dd0ac6fd5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_amf.cpp @@ -5,6 +5,10 @@ * Notes : There are two types of AMF files, the ASYLUM Music Format (used in Crusader: No Remorse and Crusader: No Regret) * and Advanced Music Format (DSMI / Digital Sound And Music Interface, used in various games such as Pinball World). * Both module types are handled here. + * To make things complete, there appears to be a (potentially unofficial) variant of the DSMI AMF format called DMF, + * used in various games published by Webfoot (Tronic, H2O, PowBall, ...). + * It mostly resembles "normal" AMF files, but with all song and sample names removed and using delta-encoded samples + * (probably the origin of the "D" in DMF). * Authors: Olivier Lapicque * OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. @@ -13,6 +17,7 @@ #include "stdafx.h" #include "Loaders.h" +#include "mpt/endian/int24.hpp" #include @@ -169,9 +174,7 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags) m.note = note + 12 + NOTE_MIN; } m.instr = instr; - m.command = command; - m.param = param; - ConvertModCommand(m); + ConvertModCommand(m, command, param); #ifdef MODPLUG_TRACKER if(m.command == CMD_PANNING8) { @@ -201,19 +204,53 @@ bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags) } +// DSMI AMF magic bytes +struct AMFFileSignature +{ + char amf[3]; // "AMF" for regular AMF files, "DMF" for the compact format found in Webfoot games + uint8 version; + + bool IsValidAMF() const + { + return !std::memcmp(amf, "AMF", 3) && (version == 1 || (version >= 8 && version <= 14)); + } + + bool IsValidDMF() const + { + // Version checks are only an assumption; All Webfoot games use version 14 files, but we can probably assume + // that if there are earlier versions, they differ in exactly the same way from regular AMF as those files do. + return !std::memcmp(amf, "DMF", 3) && (version >= 10 && version <= 14); + } +}; + +MPT_BINARY_STRUCT(AMFFileSignature, 4) + + // DSMI AMF File Header struct AMFFileHeader { - char amf[3]; - uint8le version; - char title[32]; uint8le numSamples; uint8le numOrders; uint16le numTracks; - uint8le numChannels; + uint8le numChannels; // v9+ + + bool IsValid(const uint8 version) const + { + if(!numSamples || !numOrders || !numTracks) + return false; + if(version < 9) + return true; + return (numChannels >= 1 && numChannels <= 32); + } + + // How much of AMFFileHeader should actually be read + static size_t GetHeaderSize(const uint8 version) + { + return (version >= 9) ? sizeof(AMFFileHeader) : 4u; + } }; -MPT_BINARY_STRUCT(AMFFileHeader, 41) +MPT_BINARY_STRUCT(AMFFileHeader, 5) // DSMI AMF Sample Header (v1-v9) @@ -286,6 +323,37 @@ struct AMFSampleHeaderNew MPT_BINARY_STRUCT(AMFSampleHeaderNew, 65) +// DSMI DMF ("compact AMF") Sample Header +struct AMFSampleHeaderCompact +{ + using uint24le = mpt::uint24le; + + uint8le type; + char leftOverFirstCharOfSampleName; + uint32le index; + uint32le length; + uint16le sampleRate; + uint8le volume; + uint32le loopStart; + uint24le loopEnd; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + mptSmp.filename = std::string(1, leftOverFirstCharOfSampleName); // Why not :) + mptSmp.nLength = length; + mptSmp.nC5Speed = sampleRate; + mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd.get(); + if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength) + mptSmp.uFlags.set(CHN_LOOP); + } +}; + +MPT_BINARY_STRUCT(AMFSampleHeaderCompact, 20) + + // Read a single AMF track (channel) into a pattern. static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &fileChunk) { @@ -324,23 +392,20 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file } else { // Effect - static constexpr ModCommand::COMMAND effTrans[] = + static constexpr EffectCommand effTrans[] = { - CMD_NONE, CMD_SPEED, CMD_VOLUMESLIDE, CMD_VOLUME, - CMD_PORTAMENTOUP, CMD_NONE, CMD_TONEPORTAMENTO, CMD_TREMOR, - CMD_ARPEGGIO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, - CMD_PATTERNBREAK, CMD_POSITIONJUMP, CMD_NONE, CMD_RETRIG, - CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PORTAMENTOUP, CMD_S3MCMDEX, - CMD_S3MCMDEX, CMD_TEMPO, CMD_PORTAMENTOUP, CMD_PANNING8, + CMD_NONE, CMD_SPEED, CMD_VOLUMESLIDE, CMD_VOLUME, + CMD_PORTAMENTOUP, CMD_NONE, CMD_TONEPORTAMENTO, CMD_TREMOR, + CMD_ARPEGGIO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, + CMD_PATTERNBREAK, CMD_POSITIONJUMP, CMD_NONE, CMD_RETRIG, + CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PORTAMENTOUP, CMD_S3MCMDEX, + CMD_S3MCMDEX, CMD_TEMPO, CMD_PORTAMENTOUP, CMD_PANNING8, }; - uint8 cmd = (command & 0x7F); uint8 param = value; - - if(cmd < std::size(effTrans)) - cmd = effTrans[cmd]; - else - cmd = CMD_NONE; + EffectCommand cmd = CMD_NONE; + if(uint8 maskedCmd = command & 0x7F; maskedCmd < std::size(effTrans)) + cmd = effTrans[maskedCmd]; // Fix some commands... switch(command & 0x7F) @@ -396,7 +461,7 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file case 0x16: if(param) { - cmd = static_cast((param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN); + cmd = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; if(param & 0x80) { param = ((-static_cast(param)) & 0x0F); @@ -453,26 +518,27 @@ static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &file } -static bool ValidateHeader(const AMFFileHeader &fileHeader) -{ - if(std::memcmp(fileHeader.amf, "AMF", 3) - || (fileHeader.version < 8 && fileHeader.version != 1) || fileHeader.version > 14 - || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 9)) - { - return false; - } - return true; -} - - CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize) { + AMFFileSignature fileSignature; + if(!file.ReadStruct(fileSignature)) + { + return CSoundFile::ProbeWantMoreData; + } + if(fileSignature.IsValidAMF()) + { + if(!file.Skip(32)) + return CSoundFile::ProbeWantMoreData; + } else if(!fileSignature.IsValidDMF()) + { + return ProbeFailure; + } AMFFileHeader fileHeader; - if(!file.ReadStruct(fileHeader)) + if(!file.ReadStructPartial(fileHeader, AMFFileHeader::GetHeaderSize(fileSignature.version))) { return ProbeWantMoreData; } - if(!ValidateHeader(fileHeader)) + if(!fileHeader.IsValid(fileSignature.version)) { return ProbeFailure; } @@ -485,44 +551,60 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) { file.Rewind(); + AMFFileSignature fileSignature; + if(!file.ReadStruct(fileSignature)) + return false; + + char title[32] = {}; + bool isDMF = false; + if(fileSignature.IsValidAMF() && file.CanRead(sizeof(title))) + file.ReadArray(title); + else if(fileSignature.IsValidDMF()) + isDMF = true; + else + return false; + AMFFileHeader fileHeader; - if(!file.ReadStruct(fileHeader)) - { + if(!file.ReadStructPartial(fileHeader, AMFFileHeader::GetHeaderSize(fileSignature.version))) return false; - } - if(!ValidateHeader(fileHeader)) - { + if(!fileHeader.IsValid(fileSignature.version)) return false; - } + if(loadFlags == onlyVerifyHeader) - { return true; - } InitializeGlobals(MOD_TYPE_AMF); InitializeChannels(); - m_modFormat.formatName = MPT_UFORMAT("DSMI v{}")(fileHeader.version); - m_modFormat.type = U_("amf"); + if(isDMF) + { + m_modFormat.formatName = MPT_UFORMAT("DSMI Compact v{}")(fileSignature.version); + m_modFormat.type = U_("dmf"); + } else + { + m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, title); + m_modFormat.formatName = MPT_UFORMAT("DSMI v{}")(fileSignature.version); + m_modFormat.type = U_("amf"); + } m_modFormat.charset = mpt::Charset::CP437; m_nChannels = fileHeader.numChannels; m_nSamples = fileHeader.numSamples; - m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.title); - - if(fileHeader.version < 9) + if(fileSignature.version < 9) { // Old format revisions are fixed to 4 channels m_nChannels = 4; - file.SkipBack(1); - SetupMODPanning(true); + for(CHANNELINDEX chn = 0; chn < 4; chn++) + { + ChnSettings[chn].nPan = (chn & 1) ? 0xC0 : 0x40; + } } // Setup Channel Pan Positions - if(fileHeader.version >= 11) + if(fileSignature.version >= 11) { - const CHANNELINDEX readChannels = fileHeader.version >= 12 ? 32 : 16; + const CHANNELINDEX readChannels = fileSignature.version >= 12 ? 32 : 16; for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { int8 pan = file.ReadInt8(); @@ -531,18 +613,22 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) else ChnSettings[chn].nPan = static_cast(std::clamp((pan + 64) * 2, 0, 256)); } - } else if(fileHeader.version >= 9) + } else if(fileSignature.version >= 9) { - uint8 panPos[16]; - file.ReadArray(panPos); + // Internally, DSMI assigns an Amiga-like LRRL panning scheme to the channels in pre-v11 files, + // but channels are stored in LRLR order (0 1 3 2 typically). The channel remap table that follows + // would normally undo this mapping, so that the panning is as expected again. + // This can be observed by looking at a 4-channel MOD and the converted AMF file: The last two channels are swapped. + // We ignore all this mess and simply assume that all AMF files use the standard remap table. + file.Skip(16); for(CHANNELINDEX chn = 0; chn < 16; chn++) { - ChnSettings[chn].nPan = (panPos[chn] & 1) ? 0x40 : 0xC0; + ChnSettings[chn].nPan = (chn & 1) ? 0xC0 : 0x40; } } // Get Tempo/Speed - if(fileHeader.version >= 13) + if(fileSignature.version >= 13) { auto [tempo, speed] = file.ReadArray(); if(tempo < 32) @@ -558,8 +644,8 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) // Setup Order List Order().resize(fileHeader.numOrders); std::vector patternLength; - const FileReader::off_t trackStartPos = file.GetPosition() + (fileHeader.version >= 14 ? 2 : 0); - if(fileHeader.version >= 14) + const FileReader::off_t trackStartPos = file.GetPosition() + (fileSignature.version >= 14 ? 2 : 0); + if(fileSignature.version >= 14) { patternLength.resize(fileHeader.numOrders); } @@ -567,7 +653,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++) { Order()[ord] = ord; - if(fileHeader.version >= 14) + if(fileSignature.version >= 14) { patternLength[ord] = file.ReadUint16LE(); } @@ -577,7 +663,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) // Read Sample Headers bool truncatedSampleHeaders = false; - if(fileHeader.version == 10) + if(fileSignature.version == 10) { // M2AMF 1.3 included with DMP 2.32 wrote new (v10+) sample headers, but using the old struct length. const auto startPos = file.GetPosition(); @@ -596,13 +682,20 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) std::vector sampleMap(GetNumSamples(), 0); for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { - if(fileHeader.version < 10) + if(fileSignature.version < 10) { AMFSampleHeaderOld sample; file.ReadStruct(sample); sample.ConvertToMPT(Samples[smp]); m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name); sampleMap[smp - 1] = sample.index; + } else if(isDMF) + { + AMFSampleHeaderCompact sample; + file.ReadStruct(sample); + sample.ConvertToMPT(Samples[smp]); + m_szNames[smp] = ""; + sampleMap[smp - 1] = sample.index; } else { AMFSampleHeaderNew sample; @@ -631,7 +724,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) uint16 numEvents = file.ReadUint16LE(); file.Skip(1); if(numEvents) - trackData[i] = file.ReadChunk(numEvents * 3 + (fileHeader.version == 1 ? 3 : 0)); + trackData[i] = file.ReadChunk(numEvents * 3 + (fileSignature.version == 1 ? 3 : 0)); } if(loadFlags & loadSampleData) @@ -641,7 +734,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, - SampleIO::unsignedPCM); + isDMF ? SampleIO::deltaPCM : SampleIO::unsignedPCM); // Note: in theory a sample can be reused by several instruments and appear in a different order in the file // However, M2AMF doesn't take advantage of this and just writes instruments in the order they appear, @@ -654,7 +747,16 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) if(sampleMap[target] != smp) continue; file.Seek(startPos); - sampleIO.ReadSample(Samples[target + 1], file); + ModSample &sample = Samples[target + 1]; + sampleIO.ReadSample(sample, file); + if(isDMF) + { + // Unsigned delta samples, how novel! + for(auto &v : mpt::as_span(sample.sample8(), sample.nLength)) + { + v ^= 0x80; + } + } } } } @@ -675,7 +777,7 @@ bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags) } // Get table with per-channel track assignments - file.Seek(trackStartPos + pat * (GetNumChannels() * 2 + (fileHeader.version >= 14 ? 2 : 0))); + file.Seek(trackStartPos + pat * (GetNumChannels() * 2 + (fileSignature.version >= 14 ? 2 : 0))); std::vector tracks; if(!file.ReadVector(tracks, GetNumChannels())) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp index fef51dc4f..5c99cb93a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ams.cpp @@ -42,7 +42,7 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte }; // Effect translation table for extended (non-Protracker) effects - static constexpr ModCommand::COMMAND effTrans[] = + static constexpr EffectCommand effTrans[] = { CMD_S3MCMDEX, // Forward / Backward CMD_PORTAMENTOUP, // Extra fine slide up @@ -78,7 +78,7 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte ModCommand dummy; for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { - PatternRow baseRow = pattern.GetRow(row); + auto baseRow = pattern.GetRow(row); while(patternChunk.CanRead(1)) { const uint8 flags = patternChunk.ReadUint8(); @@ -128,8 +128,7 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte if(effect < 0x10) { // PT commands - m.command = effect; - CSoundFile::ConvertModCommand(m); + CSoundFile::ConvertModCommand(m, effect, m.param); // Post-fix some commands switch(m.command) @@ -156,6 +155,9 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte m.ExtendedMODtoS3MEffect(); } break; + + default: + break; } } else if(effect < 0x10 + mpt::array_size::size) { @@ -230,11 +232,10 @@ static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patte if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command)) { - if(m.volcmd == VOLCMD_NONE && ModCommand::ConvertVolEffect(m.command, m.param, true)) + if(m.volcmd == VOLCMD_NONE) { // Volume column to the rescue! - m.volcmd = m.command; - m.vol = m.param; + m.SetVolumeCommand(ModCommand::ConvertToVolCommand(m.command, m.param, true)); } m.command = origCmd.command; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_c67.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_c67.cpp index 8592a72ca..4d73e17dd 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_c67.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_c67.cpp @@ -26,13 +26,16 @@ MPT_BINARY_STRUCT(C67SampleHeader, 16) struct C67FileHeader { - uint8 speed; - uint8 restartPos; - char sampleNames[32][13]; + using InstrName = std::array; + using OPLInstr = std::array; + + uint8 speed; + uint8 restartPos; + InstrName sampleNames[32]; C67SampleHeader samples[32]; - char fmInstrNames[32][13]; - uint8 fmInstr[32][11]; - uint8 orders[256]; + InstrName fmInstrNames[32]; + OPLInstr fmInstr[32]; + uint8 orders[256]; }; MPT_BINARY_STRUCT(C67FileHeader, 1954) @@ -69,7 +72,7 @@ static bool ValidateHeader(const C67FileHeader &fileHeader) return false; } } - if(!anyNonSilent && (fileHeader.samples[smp].length != 0 || memcmp(fileHeader.fmInstr[smp], "\0\0\0\0\0\0\0\0\0\0\0", 11))) + if(!anyNonSilent && (fileHeader.samples[smp].length != 0 || fileHeader.fmInstr[smp] != C67FileHeader::OPLInstr{{}})) { anyNonSilent = true; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp index 1b8fdf9b5..f041f78ac 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dbm.cpp @@ -126,7 +126,7 @@ MPT_BINARY_STRUCT(DBMEnvelope, 136) // Note: Unlike in MOD, 1Fx, 2Fx, 5Fx / 5xF, 6Fx / 6xF and AFx / AxF are fine slides. -static constexpr ModCommand::COMMAND dbmEffects[] = +static constexpr EffectCommand dbmEffects[] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, @@ -146,13 +146,11 @@ static constexpr ModCommand::COMMAND dbmEffects[] = }; -static void ConvertDBMEffect(uint8 &command, uint8 ¶m) +static std::pair ConvertDBMEffect(const uint8 cmd, uint8 param) { - uint8 oldCmd = command; - if(command < std::size(dbmEffects)) - command = dbmEffects[command]; - else - command = CMD_NONE; + EffectCommand command = CMD_NONE; + if(cmd < std::size(dbmEffects)) + command = dbmEffects[cmd]; switch(command) { @@ -230,7 +228,7 @@ static void ConvertDBMEffect(uint8 &command, uint8 ¶m) break; case CMD_KEYOFF: - if (param == 0) + if(param == 0) { // TODO key off at tick 0 } @@ -238,8 +236,13 @@ static void ConvertDBMEffect(uint8 &command, uint8 ¶m) case CMD_MIDI: // Encode echo parameters into fixed MIDI macros - param = 128 + (oldCmd - 32) * 32 + param / 8; + param = 128 + (cmd - 32) * 32 + param / 8; + break; + + default: + break; } + return {command, param}; } @@ -480,7 +483,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) patternNameChunk.ReadSizedString(patName); Patterns[pat].SetName(patName); - PatternRow patRow = Patterns[pat].GetRow(0); + auto patRow = Patterns[pat].GetRow(0); ROWINDEX row = 0; lostGlobalCommands.clear(); while(chunk.CanRead(1)) @@ -503,7 +506,7 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) continue; } - ModCommand dummy = ModCommand::Empty(); + ModCommand dummy{}; ModCommand &m = ch <= GetNumChannels() ? patRow[ch - 1] : dummy; const uint8 b = chunk.ReadUint8(); @@ -523,28 +526,24 @@ bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags) } if(b & 0x3C) { - uint8 cmd1 = 0, cmd2 = 0, param1 = 0, param2 = 0; - if(b & 0x04) cmd2 = chunk.ReadUint8(); - if(b & 0x08) param2 = chunk.ReadUint8(); - if(b & 0x10) cmd1 = chunk.ReadUint8(); - if(b & 0x20) param1 = chunk.ReadUint8(); - ConvertDBMEffect(cmd1, param1); - ConvertDBMEffect(cmd2, param2); + uint8 c1 = 0, p1 = 0, c2 = 0, p2 = 0; + if(b & 0x04) c2 = chunk.ReadUint8(); + if(b & 0x08) p2 = chunk.ReadUint8(); + if(b & 0x10) c1 = chunk.ReadUint8(); + if(b & 0x20) p1 = chunk.ReadUint8(); + auto [cmd1, param1] = ConvertDBMEffect(c1, p1); + auto [cmd2, param2] = ConvertDBMEffect(c2, p2); - if (cmd2 == CMD_VOLUME || (cmd2 == CMD_NONE && cmd1 != CMD_VOLUME)) + if(cmd2 == CMD_VOLUME || (cmd2 == CMD_NONE && cmd1 != CMD_VOLUME)) { std::swap(cmd1, cmd2); std::swap(param1, param2); } - const auto lostCommand = ModCommand::TwoRegularCommandsToMPT(cmd1, param1, cmd2, param2); + const auto lostCommand = m.FillInTwoCommands(cmd1, param1, cmd2, param2); if(ModCommand::IsGlobalCommand(lostCommand.first, lostCommand.second)) lostGlobalCommands.insert(lostGlobalCommands.begin(), lostCommand); // Insert at front so that the last command of same type "wins" - m.volcmd = cmd1; - m.vol = param1; - m.command = cmd2; - m.param = param2; #ifdef MODPLUG_TRACKER m.ExtendedMODtoS3MEffect(); #endif // MODPLUG_TRACKER diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_digi.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_digi.cpp index a7048d9f8..fbcebc503 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_digi.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_digi.cpp @@ -37,8 +37,8 @@ MPT_BINARY_STRUCT(DIGIFileHeader, 610) static void ReadDIGIPatternEntry(FileReader &file, ModCommand &m) { - CSoundFile::ReadMODPatternEntry(file, m); - CSoundFile::ConvertModCommand(m); + const auto [command, param] = CSoundFile::ReadMODPatternEntry(file, m); + CSoundFile::ConvertModCommand(m, command, param); if(m.command == CMD_MODCMDEX) { switch(m.param & 0xF0) @@ -185,15 +185,13 @@ bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags) // Compressed patterns are stored in row-major order... for(ROWINDEX row = 0; row < 64; row++) { - PatternRow patRow = Patterns[pat].GetRow(row); + uint8 bit = 0x80; - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, bit >>= 1) + for(ModCommand &m : Patterns[pat].GetRow(row)) { if(eventMask[row] & bit) - { - ModCommand &m = patRow[chn]; ReadDIGIPatternEntry(patternChunk, m); - } + bit >>= 1; } } } else diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp index 78a16f0b3..58daa3c07 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dmf.cpp @@ -227,7 +227,7 @@ static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks) // Try using effect memory (zero paramer) to give the effect swapper some optimization hints. -static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, uint8 effect, uint8 ¶m) +static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, EffectCommand effect, uint8 ¶m) { if(effect == CMD_NONE || param == 0) return; @@ -328,7 +328,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, return pat; } - PatternRow m = sndFile.Patterns[pat].GetRow(0); + ModCommand *m = sndFile.Patterns[pat].GetpModCommand(0, 0); const CHANNELINDEX numChannels = std::min(static_cast(sndFile.GetNumChannels() - 1), static_cast(patHead.numTracks)); // When breaking to a pattern with less channels that the previous pattern, @@ -531,7 +531,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, settings.channels[chn].playDir = false; } - uint8 effect1 = CMD_NONE, effect2 = CMD_NONE, effect3 = CMD_NONE; + EffectCommand effect1 = CMD_NONE, effect2 = CMD_NONE, effect3 = CMD_NONE; uint8 effectParam1 = 0, effectParam2 = 0, effectParam3 = 0; bool useMem2 = false, useMem3 = false; // Effect can use memory if necessary @@ -547,10 +547,10 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, // 0x08: Instrument effect if((channelInfo & patInsEff) != 0) { - effect1 = file.ReadUint8(); + const uint8 command = file.ReadUint8(); effectParam1 = file.ReadUint8(); - switch(effect1) + switch(command) { case 1: // Stop Sample m->note = NOTE_NOTECUT; @@ -591,11 +591,11 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, case 8: // Offset + 128k case 9: // Offset + 192k // Put high offset on previous row - if(row > 0 && effect1 != settings.channels[chn].highOffset) + if(row > 0 && command != settings.channels[chn].highOffset) { - if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(row - 1).Channel(chn).RetryPreviousRow())) + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (command - 6))).Row(row - 1).Channel(chn).RetryPreviousRow())) { - settings.channels[chn].highOffset = effect1; + settings.channels[chn].highOffset = command; } } effect1 = CMD_OFFSET; @@ -624,10 +624,10 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, // 0x04: Note effect if((channelInfo & patNoteEff) != 0) { - effect2 = file.ReadUint8(); + const uint8 command = file.ReadUint8(); effectParam2 = file.ReadUint8(); - switch(effect2) + switch(command) { case 1: // Note Finetune (1/16th of a semitone signed 8-bit value, not 1/128th as the interface claims) { @@ -657,7 +657,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, case 4: // Portamento Up case 5: // Portamento Down effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true); - effect2 = (effect2 == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; + effect2 = (command == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; useMem2 = true; break; case 6: // Portamento to Note @@ -679,11 +679,11 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, case 9: // Vibrato Triangle (ramp down should be close enough) case 10: // Vibrato Square // Put vibrato type on previous row - if(row > 0 && effect2 != settings.channels[chn].vibratoType) + if(row > 0 && command != settings.channels[chn].vibratoType) { - if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(row - 1).Channel(chn).RetryPreviousRow())) + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (command - 8))).Row(row - 1).Channel(chn).RetryPreviousRow())) { - settings.channels[chn].vibratoType = effect2; + settings.channels[chn].vibratoType = command; } } effect2 = CMD_VIBRATO; @@ -718,14 +718,14 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, // 0x02: Volume effect if((channelInfo & patVolEff) != 0) { - effect3 = file.ReadUint8(); + const uint8 command = file.ReadUint8(); effectParam3 = file.ReadUint8(); - switch(effect3) + switch(command) { case 1: // Volume Slide Up case 2: // Volume Slide Down - effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (effect3 == 1)); + effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (command == 1)); effect3 = CMD_VOLUMESLIDE; useMem3 = true; break; @@ -738,11 +738,11 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, case 5: // Tremolo Triangle (ramp down should be close enough) case 6: // Tremolo Square // Put tremolo type on previous row - if(row > 0 && effect3 != settings.channels[chn].tremoloType) + if(row > 0 && command != settings.channels[chn].tremoloType) { - if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(row - 1).Channel(chn).RetryPreviousRow())) + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (command - 4))).Row(row - 1).Channel(chn).RetryPreviousRow())) { - settings.channels[chn].tremoloType = effect3; + settings.channels[chn].tremoloType = command; } } effect3 = CMD_TREMOLO; @@ -754,7 +754,7 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, break; case 8: // Slide Balance Left case 9: // Slide Balance Right - effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (effect3 == 8)); + effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (command == 8)); effect3 = CMD_PANNINGSLIDE; useMem3 = true; break; @@ -804,28 +804,25 @@ static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, } } - ModCommand::TwoRegularCommandsToMPT(effect2, effectParam2, effect3, effectParam3); + ModCommand combinedCmd; + combinedCmd.FillInTwoCommands(effect2, effectParam2, effect3, effectParam3); - if(m->volcmd == VOLCMD_NONE && effect2 != VOLCMD_NONE) + if(m->volcmd == VOLCMD_NONE && combinedCmd.volcmd != VOLCMD_NONE) { - m->volcmd = effect2; - m->vol = effectParam2; + m->SetVolumeCommand(combinedCmd); } // Prefer instrument effects over any other effects if(effect1 != CMD_NONE) { - ModCommand::TwoRegularCommandsToMPT(effect3, effectParam3, effect1, effectParam1); - if(m->volcmd == VOLCMD_NONE && effect3 != VOLCMD_NONE) + combinedCmd.FillInTwoCommands(combinedCmd.command, combinedCmd.param, effect1, effectParam1); + if(m->volcmd == VOLCMD_NONE && combinedCmd.volcmd != VOLCMD_NONE) { - m->volcmd = effect3; - m->vol = effectParam3; + m->SetVolumeCommand(combinedCmd); } - m->command = effect1; - m->param = effectParam1; - } else if(effect3 != CMD_NONE) + m->SetEffectCommand(combinedCmd); + } else if(combinedCmd.command != CMD_NONE) { - m->command = effect3; - m->param = effectParam3; + m->SetEffectCommand(combinedCmd); } } else @@ -914,9 +911,9 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags) m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.composer)); FileHistory mptHistory; - mptHistory.loadDate.tm_mday = Clamp(fileHeader.creationDay, uint8(1), uint8(31)); - mptHistory.loadDate.tm_mon = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)) - 1; - mptHistory.loadDate.tm_year = fileHeader.creationYear; + mptHistory.loadDate.day = Clamp(fileHeader.creationDay, uint8(1), uint8(31)); + mptHistory.loadDate.month = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)); + mptHistory.loadDate.year = 1900 + fileHeader.creationYear; m_FileHistory.clear(); m_FileHistory.push_back(mptHistory); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp index 5b7ee2e9f..a302267a5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsm.cpp @@ -1,21 +1,17 @@ /* * Load_dsm.cpp * ------------ - * Purpose: Digisound Interface Kit (DSIK) Internal Format (DSM v2 / RIFF) module loader + * Purpose: - Digisound Interface Kit (DSIK) Internal Format (DSM v2 / RIFF) module loader + * - Dynamic Studio (DSM) module loader * Notes : 1. There is also another fundamentally different DSIK DSM v1 module format, not handled here. * MilkyTracker can load it, but the only files of this format seen in the wild are also * available in their original format, so I did not bother implementing it so far. * - * 2. Using both PLAY.EXE v1.02 and v2.00, commands not supported in MOD do not seem to do - * anything at all. - * In particular commands 0x11-0x13 handled below are ignored, and no files have been spotted - * in the wild using any commands > 0x0F at all. - * S3M-style retrigger does not seem to exist - it is translated to volume slides by CONV.EXE, + * 2. S3M-style retrigger does not seem to exist - it is translated to volume slides by CONV.EXE, * and J00 in S3M files is not converted either. S3M pattern loops (SBx) are not converted * properly by CONV.EXE and completely ignored by PLAY.EXE. * Command 8 (set panning) uses 00-80 for regular panning and A4 for surround, probably - * making DSIK one of the first applications to use this particular encoding scheme still - * used in "extended" S3Ms today. + * making DSIK one of the first applications to use this convention established by DSMI's AMF format. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ @@ -26,6 +22,10 @@ OPENMPT_NAMESPACE_BEGIN + +///////////////////////////////////////////////////////////////////// +// DMS (DSIK) loader + struct DSMChunk { char magic[4]; @@ -65,7 +65,7 @@ struct DSMSampleHeader uint32le length; uint32le loopStart; uint32le loopEnd; - uint32le dataPtr; // Interal sample pointer during playback in DSIK + uint32le dataPtr; // Interal sample pointer during playback in DSIK uint32le sampleRate; char sampleName[28]; @@ -219,12 +219,9 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) m_nDefaultGlobalVolume = std::min(songHeader.globalVol.get(), uint8(64)) * 4u; if(!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; if(songHeader.mastervol == 0x80) - { m_nSamplePreAmp = std::min(256u / m_nChannels, 128u); - } else - { + else m_nSamplePreAmp = songHeader.mastervol & 0x7F; - } // Read channel panning for(CHANNELINDEX chn = 0; chn < 16; chn++) @@ -255,7 +252,7 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) } chunk.Skip(2); - ModCommand dummy = ModCommand::Empty(); + ModCommand dummy{}; ROWINDEX row = 0; while(chunk.CanRead(1) && row < 64) { @@ -290,26 +287,7 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) if(flag & 0x10) { auto [command, param] = chunk.ReadArray(); - switch(command) - { - // Portamentos - case 0x11: - case 0x12: - command &= 0x0F; - break; - // 3D Sound (?) - case 0x13: - command = 'X' - 55; - param = 0x91; - break; - default: - // Volume + Offset (?) - if(command > 0x10) - command = ((command & 0xF0) == 0x20) ? 0x09 : 0xFF; - } - m.command = command; - m.param = param; - ConvertModCommand(m); + ConvertModCommand(m, command, param); } } patNum++; @@ -336,4 +314,217 @@ bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags) } +///////////////////////////////////////////////////////////////////// +// DSM (Dynamic Studio) loader + + +struct DSmSampleHeader +{ + char name[22]; + uint8 type; + uint16le length; + uint8 finetune; + uint8 volume; + uint16le loopStart; + uint16le loopLength; + uint8 padding; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.nVolume = std::min(volume, uint8(64)) * 4u; + mptSmp.nFineTune = MOD2XMFineTune(finetune); + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + mptSmp.uFlags.set(CHN_LOOP, loopLength > 2); + mptSmp.uFlags.set(CHN_16BIT, type == 16); + } +}; + +MPT_BINARY_STRUCT(DSmSampleHeader, 32) + + +struct DSmFileHeader +{ + char magic[4]; // "DSm\x1A" + uint8 version; + char title[20]; + char artist[20]; + uint8 numChannels; + uint8 numSamples; + uint8 numOrders; + uint8 packInformation; + uint8 globalVol; // 0...100 + char padding[14]; + + bool IsValid() const noexcept + { + return !memcmp(magic, "DSm\x1A", 4) + && version == 0x20 + && numChannels >= 1 && numChannels <= 32 + && numSamples > 0 + && numOrders > 0 + && globalVol <= 100; + } + + uint32 GetHeaderMinimumAdditionalSize() const noexcept + { + return numChannels + numOrders + numSamples * sizeof(DSmSampleHeader); + } +}; + +MPT_BINARY_STRUCT(DSmFileHeader, 64) + + +CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSm(MemoryFileReader file, const uint64 *pfilesize) +{ + DSmFileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return ProbeWantMoreData; + if(!fileHeader.IsValid()) + return ProbeFailure; + + return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); +} + + +bool CSoundFile::ReadDSm(FileReader &file, ModLoadingFlags loadFlags) +{ + file.Rewind(); + + DSmFileHeader fileHeader; + if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid()) + return false; + if(!file.CanRead(fileHeader.GetHeaderMinimumAdditionalSize())) + return false; + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_MOD); + m_SongFlags.set(SONG_IMPORTED); + m_nChannels = fileHeader.numChannels; + static_assert(MAX_BASECHANNELS >= 32 && MAX_SAMPLES > 255); + m_nSamples = fileHeader.numSamples; + m_nDefaultGlobalVolume = Util::muldivr_unsigned(fileHeader.globalVol, MAX_GLOBAL_VOLUME, 100); + + m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.title); + m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.artist)); + + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].Reset(); + ChnSettings[chn].nPan = (file.ReadUint8() & 0x0F) * 0x11; + } + + ReadOrderFromFile(Order(), file, fileHeader.numOrders); + PATTERNINDEX numPatterns = 0; + for(PATTERNINDEX pat : Order()) + { + numPatterns = std::max(pat, numPatterns); + } + numPatterns++; + + if(!file.CanRead((numPatterns * m_nChannels * 8) + (m_nSamples * sizeof(DSmSampleHeader)) + (numPatterns * m_nChannels * 64 * 4))) + return false; + + // Track names for each pattern - we only read the track names of the first pattern + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].szName = mpt::String::ReadBuf(mpt::String::spacePadded, file.ReadArray()); + } + file.Skip((numPatterns - 1) * m_nChannels * 8); + + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) + { + DSmSampleHeader sampleHeader; + file.ReadStruct(sampleHeader); + sampleHeader.ConvertToMPT(Samples[smp]); + m_szNames[smp] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); + } + + Patterns.ResizeArray(numPatterns); + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) + { + file.Skip(m_nChannels * 64 * 4); + continue; + } + for(ModCommand &m : Patterns[pat]) + { + const auto data = file.ReadArray(); + if(data[1] > 0 && data[1] <= 84 * 2) + m.note = (data[1] >> 1) + NOTE_MIN + 35; + m.instr = data[0]; + m.param = data[3]; + if(data[2] == 0x08) + { + switch(m.param & 0xF0) + { + case 0x00: // 4-bit panning + m.command = CMD_MODCMDEX; + m.param |= 0x80; + break; + case 0x10: // Default volume slide Up (should stop at sample's default volume) + m.command = CMD_VOLUMESLIDE; + m.param <<= 4; + break; + case 0x20: // Default fine volume slide Up (should stop at sample's default volume) + m.command = CMD_MODCMDEX; + m.param |= 0xA0; + break; + case 0x30: // Fine porta up (support all 5 octaves) + case 0x40: // Fine porta down (support all 5 octaves) + m.command = CMD_MODCMDEX; + m.param -= 0x20; + break; + default: + break; + } + } else if(data[2] == 0x13) + { + // 3D Simulate + m.command = CMD_PANNING8; + uint32 param = (m.param & 0x7F) * 2u; + if(m.param <= 0x40) // 00 Front -> 40 Right + param += 0x80; + else if(m.param < 0x80) // 40 Right -> 80 Back + param = 0x180 - param; + else if(m.param < 0xC0) // 80 Back -> C0 Left + param = 0x80 - param; + else // C0 Left -> FF Front + param -= 0x80; + m.param = mpt::saturate_cast(param); + } else if((data[2] & 0xF0) == 0x20) + { + // Offset + volume + m.command = CMD_OFFSET; + m.volcmd = VOLCMD_VOLUME; + m.vol = (data[2] & 0x0F) * 4 + 4; + } else if(data[2] <= 0x0F || data[2] == 0x11 || data[2] == 0x12) + { + // 0x11 and 0x12 support the full 5-octave range, 0x01 and 0x02 presumably only the ProTracker 3-octave range + ConvertModCommand(m, data[2] & 0x0F, data[3]); + } + } + } + + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= m_nSamplePreAmp; smp++) + { + SampleIO(Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM).ReadSample(Samples[smp], file); + } + } + + m_modFormat.formatName = U_("Dynamic Studio"); + m_modFormat.type = U_("dsm"); + m_modFormat.charset = mpt::Charset::CP437; + + return true; +} + OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp index 5223df7df..7d8e3a18d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dsym.cpp @@ -11,18 +11,20 @@ #include "stdafx.h" #include "Loaders.h" #include "BitReader.h" +#include "mpt/endian/int24.hpp" OPENMPT_NAMESPACE_BEGIN struct DSymFileHeader { + using uint24le = mpt::uint24le; + char magic[8]; uint8le version; // 0 / 1 uint8le numChannels; // 1...8 uint16le numOrders; // 0...4096 uint16le numTracks; // 0...4096 - uint16le infoLenLo; - uint8le infoLenHi; + uint24le infoLen; bool Validate() const { @@ -112,7 +114,7 @@ static std::vector DecompressDSymLZW(FileReader &file, uint32 size) dictionary[nextIndex].value = match[writeOffset]; dictionary[nextIndex].prev = prevCode; - + nextIndex++; if(nextIndex != MaxNodes && nextIndex == (1u << codeSize)) codeSize++; @@ -314,10 +316,9 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) if(command == 0 && param == 0) continue; - m->command = command; m->param = static_cast(param); m->vol = static_cast(param >> 8); - + switch(command) { case 0x00: // 00 xyz Normal play or Arpeggio + Volume Slide Up @@ -326,8 +327,7 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) case 0x20: // 20 xyz Normal play or Arpeggio + Volume Slide Down case 0x21: // 21 xyy Slide Up + Volume Slide Down case 0x22: // 22 xyy Slide Down + Volume Slide Down - m->command &= 0x0F; - ConvertModCommand(*m); + ConvertModCommand(*m, command & 0x0F, m->param); if(m->vol) m->volcmd = (command < 0x20) ? VOLCMD_VOLSLIDEUP : VOLCMD_VOLSLIDEDOWN; break; @@ -337,7 +337,7 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) case 0x06: // 06 xyz Vibrato + Volume Slide case 0x07: // 07 xyz Tremolo case 0x0C: // 0C xyy Set Volume - ConvertModCommand(*m); + ConvertModCommand(*m, command, m->param); break; case 0x09: // 09 xxx Set Sample Offset m->command = CMD_OFFSET; @@ -352,8 +352,7 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) case 0x2A: // 2A xyz Volume Slide + Fine Slide Down if(param < 0xFF) { - m->command &= 0x0F; - ConvertModCommand(*m); + ConvertModCommand(*m, command & 0x0F, m->param); } else { m->command = CMD_MODCMDEX; @@ -594,7 +593,7 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) } } - if(const uint32 infoLen = fileHeader.infoLenLo | (fileHeader.infoLenHi << 16); infoLen > 0) + if(const uint32 infoLen = fileHeader.infoLen.get(); infoLen > 0) { std::vector infoData; if(!ReadDSymChunk(file, infoData, infoLen)) @@ -613,3 +612,4 @@ bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags) OPENMPT_NAMESPACE_END + diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp index 6b8931400..d6ae58a65 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_dtm.cpp @@ -463,9 +463,7 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) } if(command || param) { - m->command = command; - m->param = param; - ConvertModCommand(*m); + ConvertModCommand(*m, command, param); #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); #endif @@ -481,62 +479,54 @@ bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags) } } else { - ModCommand *m = Patterns[patNum].GetpModCommand(0, 0); - for(ROWINDEX row = 0; row < numRows; row++) + for(ModCommand &m : Patterns[patNum]) { - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, m++) + const auto data = chunk.ReadArray(); + uint8 command = 0; + if(patternFormat == DTM_204_PATTERN_FORMAT) { - const auto data = chunk.ReadArray(); - if(patternFormat == DTM_204_PATTERN_FORMAT) + const auto [note, instrVol, instrCmd, param] = data; + if(note > 0 && note < 0x80) { - const auto [note, instrVol, instrCmd, param] = data; - if(note > 0 && note < 0x80) - { - m->note = (note >> 4) * 12 + (note & 0x0F) + NOTE_MIN + 11; - } - uint8 vol = instrVol >> 2; - if(vol) - { - m->volcmd = VOLCMD_VOLUME; - m->vol = vol - 1u; - } - m->instr = ((instrVol & 0x03) << 4) | (instrCmd >> 4); - m->command = instrCmd & 0x0F; - m->param = param; - } else - { - ReadMODPatternEntry(data, *m); - m->instr |= data[0] & 0x30; // Allow more than 31 instruments + m.note = (note >> 4) * 12 + (note & 0x0F) + NOTE_MIN + 11; } - ConvertModCommand(*m); - // Fix commands without memory and slide nibble precedence - switch(m->command) + uint8 vol = instrVol >> 2; + if(vol) { - case CMD_PORTAMENTOUP: - case CMD_PORTAMENTODOWN: - if(!m->param) - { - m->command = CMD_NONE; - } - break; - case CMD_VOLUMESLIDE: - case CMD_TONEPORTAVOL: - case CMD_VIBRATOVOL: - if(m->param & 0xF0) - { - m->param &= 0xF0; - } else if(!m->param) - { - m->command = CMD_NONE; - } - break; - default: - break; + m.volcmd = VOLCMD_VOLUME; + m.vol = vol - 1u; } -#ifdef MODPLUG_TRACKER - m->Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); -#endif + m.instr = ((instrVol & 0x03) << 4) | (instrCmd >> 4); + command = instrCmd & 0x0F; + m.param = param; + } else + { + std::tie(command, m.param) = ReadMODPatternEntry(data, m); + m.instr |= data[0] & 0x30; // Allow more than 31 instruments } + ConvertModCommand(m, command, m.param); + // Fix commands without memory and slide nibble precedence + switch(m.command) + { + case CMD_PORTAMENTOUP: + case CMD_PORTAMENTODOWN: + if(!m.param) + m.command = CMD_NONE; + break; + case CMD_VOLUMESLIDE: + case CMD_TONEPORTAVOL: + case CMD_VIBRATOVOL: + if(m.param & 0xF0) + m.param &= 0xF0; + else if(!m.param) + m.command = CMD_NONE; + break; + default: + break; + } +#ifdef MODPLUG_TRACKER + m.Convert(MOD_TYPE_MOD, MOD_TYPE_IT, *this); +#endif } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_far.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_far.cpp index 57230d7cc..6992ffb6a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_far.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_far.cpp @@ -254,11 +254,8 @@ bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags) // Read pattern data for(ROWINDEX row = 0; row < numRows; row++) { - PatternRow rowBase = Patterns[pat].GetRow(row); - for(CHANNELINDEX chn = 0; chn < 16; chn++) + for(ModCommand &m : Patterns[pat].GetRow(row)) { - ModCommand &m = rowBase[chn]; - const auto [note, instr, volume, effect] = patternChunk.ReadArray(); if(note > 0 && note <= 72) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp index 789727af8..5c6a4b123 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gdm.cpp @@ -341,7 +341,7 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) for(ROWINDEX row = 0; row < 64; row++) { - PatternRow rowBase = Patterns[pat].GetRow(row); + auto rowBase = Patterns[pat].GetRow(row); uint8 channelByte; // If channel byte is zero, advance to next row. @@ -474,6 +474,9 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags) m.command = CMD_NONE; } break; + + default: + break; } // Move pannings to volume column - should never happen diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gt2.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gt2.cpp new file mode 100644 index 000000000..39fea249c --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_gt2.cpp @@ -0,0 +1,1593 @@ +/* + * Load_gt2.cpp + * ------------ + * Purpose: Graoumf Tracker 1/2 module loader (GTK and GT2) + * Notes : DSPs (delay, filter) are currently not supported. They are kinda tricky because DSP to track assignments are established using pattern commands and can change at any time. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Loaders.h" + +#include "mpt/parse/parse.hpp" + +OPENMPT_NAMESPACE_BEGIN + +// GTK File Header +struct GTKFileHeader +{ + char signature[3]; + uint8be fileVersion; + char songName[32]; + char smallComment[160]; + uint16be numSamples; + uint16be numRows; + uint16be numChannels; + uint16be numOrders; + uint16be restartPos; + + bool Validate() const + { + return !std::memcmp(signature, "GTK", 3) + && fileVersion >= 1 + && fileVersion <= 4 + && numSamples <= 255 + && numRows > 0 && numRows <= 256 + && numChannels > 0 && numChannels <= 32 + && numOrders <= 256 + && restartPos < numOrders; + } + + uint64 GetHeaderMinimumAdditionalSize() const + { + return ((fileVersion < 3) ? 48 : 64) * numSamples + + 512 // Order list + + ((fileVersion < 4) ? 4 : 5) * numRows * numChannels; // One pattern minimum + } +}; + +MPT_BINARY_STRUCT(GTKFileHeader, 206) + + +static uint16 GT2LogToLinearVolume(uint16 logVolume) +{ + LimitMax(logVolume, uint16(0xFFF)); + return mpt::saturate_round(std::pow(2.0, (logVolume & 0xFF) / 256.0) * 32768.0) >> (15 - (logVolume >> 8)); +} + + +static void TranslateGraoumfEffect(CSoundFile &sndFile, ModCommand &m, const uint8 effect, const uint8 param, const int16 fileVersion, const ModCommand::NOTE lastNote, const ModCommand::INSTR lastInstr, TEMPO ¤tTempo, uint32 ¤tSpeed) +{ + if(!effect) + return; + if(effect >= 0xB0 && fileVersion < 0) + return; + + m.param = param; + + const bool isFalcon = fileVersion <= 5; + const uint16 param12bit = ((effect & 0x0F) << 8) | param; + const uint8 param4bit = std::min(param, uint8(0x0F)); + const uint8 param4bitSlide = std::min(param, uint8(0x0E)); + const uint8 param4bitDiv32 = static_cast(std::min((param + 31) / 32, 0x0E)); + const uint8 param4bitDiv128 = static_cast(std::min((param + 127) / 128, 0x0E)); + switch(effect >> 4) + { + case 0x02: // 2xxx: Set Volume + m.volcmd = VOLCMD_VOLUME; + m.vol = static_cast(std::min(param12bit / 4, 64)); + return; + + case 0x03: // 3xxx: Set Logarithmic Volume + m.volcmd = VOLCMD_VOLUME; + if(param12bit == 0) + m.vol = 0; + else + m.vol = static_cast(std::min(GT2LogToLinearVolume(param12bit) / 4, 64)); + return; + + case 0x04: // 4xxx: Panning + m.command = CMD_PANNING8; + m.param = static_cast(param12bit / 16); + return; + + case 0x05: // 5xxx: Linear global volume + m.command = CMD_GLOBALVOLUME; + m.param = static_cast((param12bit + 1) / 32); + return; + + case 0x06: // 6xxx: Logarithmic global volume + m.command = CMD_GLOBALVOLUME; + if(param12bit == 0) + m.param = 0; + else + m.param = mpt::saturate_cast(GT2LogToLinearVolume(param12bit) / 32); + return; + + case 0x07: // 7xyy: Roll (x = speed, yy = maximum number of repetitions, 0 = unlimited) + m.command = CMD_RETRIG; + m.param = effect & 0x0F; + return; + + case 0x08: + m.command = CMD_RETRIG; + if(fileVersion >= 0) + { + // GT2: 8xyz: Roll + Volume slide + Set balance + if(m.volcmd == VOLCMD_NONE) + { + m.volcmd = VOLCMD_PANNING; + m.vol = static_cast(Util::muldivr(effect & 0x0F, 64, 15)); + } + } else + { + // GTK: 8xyy: Roll + Set Linear Volume + m.param = effect & 0x0F; + m.volcmd = VOLCMD_VOLUME; + m.vol = static_cast((param + 3u) / 4u); + } + return; + + case 0x09: // 9xxx: Offset + m.command = CMD_OFFSET; + { + SmpLength fullOffset = param12bit; + if(isFalcon) + { + if(!fullOffset) + { + // 9000 didn't recall last offset param + fullOffset = 1; + } else + { + SAMPLEINDEX sample = sndFile.GetSampleIndex(lastNote, lastInstr); + if(sample != 0) + { + const ModSample &smp = sndFile.GetSample(sample); + if(smp.uFlags[CHN_16BIT]) + fullOffset /= 2; + // Offset beyond sample loop restarted from sample loop rather than cutting sample + // We could probably also use a compatibility flag for this, but this is what newer GT2 versions do + // And it avoids writing VOLCMD_OFFSET in case the parameter is very large + if(smp.uFlags[CHN_LOOP] && fullOffset * 256u > smp.nLength) + { + fullOffset = (smp.nLoopStart + 8u) / 256u; + LimitMax(fullOffset, (smp.nLength - 1u) / 256u); + } + } + } + } + m.param = static_cast(fullOffset); + if(fullOffset > 0xFF && m.volcmd == VOLCMD_NONE) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = static_cast(std::min(fullOffset >> 8, static_cast(std::size(ModSample().cues)))); + } + } + return; + } + + switch(effect) + { + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x07: + case 0x0B: + case 0x0F: + CSoundFile::ConvertModCommand(m, effect, param); + if(m.command == CMD_TEMPO) + currentTempo.Set(m.param, 0); + else if(m.command == CMD_SPEED && m.param > 0) + currentSpeed = m.param; + break; + case 0x05: // 05xx: Tone portamento + vibrato + m.command = CMD_TONEPORTAMENTO; + if(m.volcmd == VOLCMD_NONE) + { + m.volcmd = VOLCMD_VIBRATODEPTH; + m.vol = 0; + } + break; + case 0x06: // 06xx: Vibrato + tone portamento + m.command = CMD_VIBRATO; + if(m.volcmd == VOLCMD_NONE) + { + m.volcmd = VOLCMD_TONEPORTAMENTO; + m.vol = 0; + } + break; + case 0x08: // 08xy: Detune + if(!m.IsNote() || !param) + break; + m.command = CMD_FINETUNE; + m.param = 0x80 + ((param & 0xF0) >> 1) - ((param & 0x0F) << 3); + if(!sndFile.GetNumInstruments()) + { + // Need instruments for correct pitch wheel depth + sndFile.m_nInstruments = std::min(sndFile.m_nSamples, static_cast(MAX_INSTRUMENTS - 1u)); + for(SAMPLEINDEX smp = 1; smp <= sndFile.m_nInstruments; smp++) + { + if(auto ins = sndFile.AllocateInstrument(smp, smp); ins != nullptr) + { + ins->midiPWD = 2; + ins->name = sndFile.m_szNames[smp]; + ins->SetCutoff(0x7F, true); + ins->SetResonance(0, true); + } + } + } + break; + case 0x09: // 09xx: Note Delay + m.command = CMD_MODCMDEX; + m.param = 0xD0 | param4bit; + break; + case 0x0A: // 0Axx: Cut Note / Key Off + m.command = CMD_KEYOFF; + break; + case 0x0C: // 0C0x: Vibrato waveform + if(param <= 2) + { + m.command = CMD_MODCMDEX; + m.param = 0x40 | param; + } + break; + case 0x0D: // 0Dxx: Pattern break + m.command = CMD_PATTERNBREAK; + break; + case 0x0E: // 0E0x: Tremolo waveform + if(param <= 2) + { + m.command = CMD_MODCMDEX; + m.param = 0x70 | param; + } + break; + case 0x10: // 10xy: Arpeggio + m.command = CMD_ARPEGGIO; + break; + case 0x11: // 11xx: Fine portamento up + case 0x12: // 12xx: Fine portamento down + m.command = CMD_MODCMDEX; + m.param = (effect << 4) | param4bitSlide; + break; + case 0x13: // 13xy: Roll + Volume Slide + m.command = CMD_RETRIG; + break; + case 0x14: // 14xx: Linear volume slide up + m.command = CMD_VOLUMESLIDE; + m.param = param4bitSlide << 4; + break; + case 0x15: // 15xx Linear volume slide down + m.command = CMD_VOLUMESLIDE; + m.param = param4bitSlide; + break; + case 0x16: // 16xx: Logarithmic volume slide up + case 0x17: // 17xx: Logarithmic volume slide down + break; + case 0x18: // 18xx: Linear volume slide up + Tone portamento + m.command = CMD_TONEPORTAVOL; + m.param = param4bitSlide << 4; + break; + case 0x19: // 19xx: Linear volume slide down + Tone portamento + m.command = CMD_TONEPORTAVOL; + m.param = param4bitSlide; + break; + case 0x1A: // 1Axx: Logarithmic volume slide up + Tone portamento + case 0x1B: // 1Bxx: Logarithmic volume slide down + Tone portamento + break; + case 0x1C: // 1Cxx: Linear volume slide up + Vibrato + m.command = CMD_VIBRATOVOL; + m.param = param4bitSlide << 4; + break; + case 0x1D: // 1Dxx: Linear volume slide down + Vibrato + m.command = CMD_VIBRATOVOL; + m.param = param4bitSlide; + break; + case 0x1E: // 1Exx: Logarithmic volume slide up + Vibrato + case 0x1F: // 1Fxx: Logarithmic volume slide down + Vibrato + break; + case 0xA0: // A0xx: Linear master volume slide up + if(param) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = param4bitDiv32 << 4; + } + break; + case 0xA1: // A1xx: Linear master volume slide down + if(param) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = param4bitDiv32; + } + break; + case 0xA4: // A4xx: Fine linear volume slide up + m.command = CMD_VOLUMESLIDE; + m.param = (param4bitSlide << 4) | 0x0F; + break; + case 0xA5: // A5xx: Fine linear volume slide down + m.command = CMD_VOLUMESLIDE; + m.param = param4bitSlide | 0xF0; + break; + case 0xA6: // A6xx: Fine linear master volume slide up + if(param) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = (param4bitDiv32 << 4) | 0x0F; + } + break; + case 0xA7: // A7xx: Fine linear master volume slide down + if(param) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = param4bitDiv32 | 0xF0; + } + break; + case 0xA8: // A8xx: Set number of ticks + if(param) + { + m.command = CMD_SPEED; + currentSpeed = m.param; + } + break; + case 0xA9: // A9xx: Set fine tempo (fractional) + if(isFalcon && currentTempo.GetInt() > 0) + { + // GTK / GT2 Falcon version (assuming 49170 Hz sample rate, the best possible. bigbigbt.gtk and twenty five-twenty.gtk require this sample rate) + double samplesPerTick = (49170 * 2.5) / currentTempo.ToDouble(); + samplesPerTick += param * 2 - 256; + m.command = CMD_TEMPO; + m.param = mpt::saturate_round((49170 * 5) / (samplesPerTick * 2)); + } else + { + // GT2 Windows version - Add xx/256 to tempo + } + break; + case 0xAA: // AAxx: Pattern delay + m.command = CMD_MODCMDEX; + m.param = 0xE0 | param4bit; + break; + case 0xAC: // ACxx: Extra fine portamento up + m.command = CMD_XFINEPORTAUPDOWN; + m.param = 0x10 | param4bit; + break; + case 0xAD: // ADxx: Extra fine portamento down + m.command = CMD_XFINEPORTAUPDOWN; + m.param = 0x20 | param4bit; + break; + case 0xAE: // AExx: Pan slide left + m.command = CMD_PANNINGSLIDE; + m.param = (param4bitSlide / 2u) << 4; // approximation + break; + case 0xAF: // AFxx: Pan slide right + m.command = CMD_PANNINGSLIDE; + m.param = param4bitSlide / 2u; // approximation + break; + case 0xB0: // B0xy: Tremor + m.command = CMD_TREMOR; + break; + case 0xB1: // B1xx: Pattern Loop + m.command = CMD_MODCMDEX; + m.param = 0xB0 | param4bit; + break; + case 0xB2: // B2xx: Per-channel interpolation flags + case 0xB3: // B3xx: Set Volume Envelope (we have no way to use another envelope) + m.command = CMD_S3MCMDEX; + m.param = 0x77 + (param ? 1 : 0); + break; + case 0xB4: // B4xx: Set Tone Envelope (ditto) + m.command = CMD_S3MCMDEX; + m.param = 0x7B + (param ? 2 : 0); + break; + case 0xB5: // B5xx: Set Panning Envelope (ditto) + m.command = CMD_S3MCMDEX; + m.param = 0x79 + (param ? 1 : 0); + break; + case 0xB6: // B6xx: Set Cutoff Envelope (ditto) + m.command = CMD_S3MCMDEX; + m.param = 0x7B + (param ? 3 : 0); + break; + case 0xB7: // B7xx: Set Resonance Envelope (ditto) + break; + case 0xBA: // BAxx: Fine Offset + m.command = CMD_OFFSET; + m.param = (m.param + 15u) / 16u; + break; + case 0xBB: // BBxx: Very Fine Offset + m.command = CMD_OFFSET; + m.param = 1; + break; + case 0xBE: // BExx: Auto Tempo (adjusts tempo so that a C-2 played by the current sample will last exactly xx rows) + case 0xBF: // BFxx: Auto Period (adjusts note frequency so that the note will last exactly xx rows) + // Auto Tempo crashes GT2 for Windows. Differences from GT2 for Falcon are based on the source code (assuming no crash) + if(param != 0 && lastNote != NOTE_NONE && lastInstr != 0 && currentTempo.GetInt() > 0 && currentSpeed > 0) + { + SAMPLEINDEX sample = sndFile.GetSampleIndex(lastNote, lastInstr); + if(!sample) + break; + const ModSample &smp = sndFile.GetSample(sample); + SmpLength length = smp.nLength; + if(smp.uFlags[CHN_LOOP]) + { + length = smp.nLoopEnd; + if(isFalcon) + length -= smp.nLoopStart; + if(smp.uFlags[CHN_PINGPONGLOOP] && !isFalcon) + length *= 2; + } + if(isFalcon && length < 1024) + break; + if(!length || !smp.nC5Speed) + break; + + int32 transpose = 0, finetune = 0; + if(lastInstr <= sndFile.GetNumInstruments() && sndFile.Instruments[lastInstr] != nullptr) + transpose = static_cast(sndFile.Instruments[lastInstr]->NoteMap[lastNote - NOTE_MIN]) - lastNote; + if(isFalcon && effect == 0xBE) + finetune = smp.nFineTune; + + const double sampleRate = smp.nC5Speed * std::pow(2.0, finetune / (-128.0 * 12.0) + transpose / 12.0); + + if(effect == 0xBE) + { + // Note: This assumes that the middle-C frequency was doubled when converting the samples + const double tempo = 2.5 * (currentSpeed * param) * (sampleRate * 0.5) / length; + // GT2 would divide the tempo by 2 while it's greater than 999 but we cannot store tempos above 255 here anyway + m.command = CMD_TEMPO; + m.param = mpt::saturate_round(tempo); + currentTempo = TEMPO(m.param, 0); + } else + { + const double sampleDurationMiddleC = length / sampleRate; + const double wantedDuration = (param * currentSpeed * 2.5) / currentTempo.ToDouble(); + const double ratio = sampleDurationMiddleC / wantedDuration; + const double note = Clamp(double(NOTE_MIDDLEC) + mpt::log2(ratio) * 12.0, double(NOTE_MIN), double(NOTE_MAX)), frac = note - std::floor(note); + + const bool hadNote = m.IsNote(); + m.note = static_cast(note); + m.param = static_cast(0x80 + (frac * 64.0)); + if(m.param != 0x80) + m.command = CMD_FINETUNE; + + if(!hadNote) + { + if(m.volcmd == VOLCMD_NONE) + { + m.volcmd = VOLCMD_TONEPORTAMENTO; + m.vol = 9; + } else + { + m.command = CMD_TONEPORTAMENTO; + m.param = 0xFF; + } + } + } + } + break; + case 0xC0: // C0xy: Change sample direction after y ticks (x: 0 = invert current direction, 1 = forward, 2 = backward) + if(const uint8 direction = (param >> 4); direction == 1 || direction == 2) + { + m.command = CMD_S3MCMDEX; + m.param = static_cast(0x9D + direction); + } + break; + case 0xC2: // C2xx: Set linear track volume (0x10 = 0dB) + m.command = CMD_CHANNELVOLUME; + m.param *= 4; + break; + case 0xC3: // C2xx: Set logarithmic track volume (0xC0 = 0dB) + m.command = CMD_CHANNELVOLUME; + m.param = mpt::saturate_cast(GT2LogToLinearVolume(param << 4) / 64); + break; + case 0xC4: // C4xx: Linear track volume slide up + case 0xC6: // C6xx: Logarithmic track volume slide up + m.command = CMD_CHANNELVOLSLIDE; + m.param = param4bitDiv128 << 4; + break; + case 0xC5: // C5xx: Linear track volume slide down + case 0xC7: // C7xx: Logarithmic track volume slide down + m.command = CMD_CHANNELVOLSLIDE; + m.param = param4bitDiv128; + break; + case 0xC8: // C8xx: Fine logarithmic track volume slide up + m.command = CMD_CHANNELVOLSLIDE; + m.param = (param4bitSlide << 4) | 0x0F; + break; + case 0xC9: // C9xx: Fine logarithmic track volume slide down + m.command = CMD_CHANNELVOLSLIDE; + m.param = param4bitSlide | 0xF0; + break; + default: + break; + } +} + + +CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGTK(MemoryFileReader file, const uint64 *pfilesize) +{ + GTKFileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return ProbeWantMoreData; + if(!fileHeader.Validate()) + return ProbeFailure; + return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); +} + + +bool CSoundFile::ReadGTK(FileReader &file, ModLoadingFlags loadFlags) +{ + file.Rewind(); + + GTKFileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return false; + if(!fileHeader.Validate()) + return false; + if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) + return false; + if(loadFlags == onlyVerifyHeader) + return true; + + // Globals + InitializeGlobals(MOD_TYPE_MPT); + InitializeChannels(); + m_SongFlags.set(SONG_IMPORTED); + m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); + m_playBehaviour.set(kApplyOffsetWithoutNote); + m_nChannels = fileHeader.numChannels; + SetupMODPanning(true); + + m_modFormat.madeWithTracker = U_("Graoumf Tracker"); + m_modFormat.formatName = MPT_UFORMAT("Graoumf Tracker v{}")(fileHeader.fileVersion); + m_modFormat.type = U_("gtk"); + m_modFormat.charset = mpt::Charset::ISO8859_1_no_C1; + + m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); + size_t msgLength = sizeof(fileHeader.smallComment); + while(msgLength > 0 && fileHeader.smallComment[msgLength - 1] == ' ') + msgLength--; + m_songMessage.Read(mpt::byte_cast(fileHeader.smallComment), msgLength, SongMessage::leAutodetect); + + m_nSamples = fileHeader.numSamples; + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + ModSample &mptSmp = Samples[smp]; + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.Set16BitCuePoints(); + file.ReadString(m_szNames[smp], (fileHeader.fileVersion == 1) ? 32 : 28); + if(fileHeader.fileVersion >= 3) + { + file.Skip(14); // reserved + int16 defaultPan = file.ReadInt16BE(); // -1 = use track panning, 0...4095 otherwise + if(defaultPan >= 0) + { + mptSmp.uFlags.set(CHN_PANNING); + mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); + } + } + uint16 bytesPerSample = 1; + if(fileHeader.fileVersion >= 2) + { + bytesPerSample = file.ReadUint16BE(); + mptSmp.nC5Speed = file.ReadUint16BE(); + } + const auto [length, loopStart, loopLength] = file.ReadArray(); + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength; + mptSmp.uFlags.set(CHN_LOOP, mptSmp.nLoopStart > 0 || loopLength > 2); + if(bytesPerSample == 2) + { + mptSmp.uFlags.set(CHN_16BIT); + mptSmp.nLength /= 2u; + mptSmp.nLoopStart /= 2u; + mptSmp.nLoopEnd /= 2u; + } + mptSmp.nVolume = file.ReadUint16BE(); + int16 finetune = file.ReadInt16BE(); // -8...7 + if(finetune != 0) + mptSmp.Transpose(finetune / (12.0 * 8.0)); + mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command + } + + Order().SetRestartPos(fileHeader.restartPos); + FileReader orderChunk = file.ReadChunk(512); + ReadOrderFromFile(Order(), orderChunk, fileHeader.numOrders); + PATTERNINDEX numPatterns = *std::max_element(Order().begin(), Order().end()) + 1u; + + Patterns.ResizeArray(numPatterns); + const uint8 eventSize = fileHeader.fileVersion < 4 ? 4 : 5; + TEMPO currentTempo = m_nDefaultTempo; + uint32 currentSpeed = m_nDefaultSpeed; + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + if(!(loadFlags & loadPatternData) || !file.CanRead(fileHeader.numRows * GetNumChannels() * eventSize) || !Patterns.Insert(pat, fileHeader.numRows)) + continue; + + std::vector> lastNoteInstr(GetNumChannels(), {NOTE_NONE, {}}); + for(ROWINDEX row = 0; row < fileHeader.numRows; row++) + { + auto rowData = Patterns[pat].GetRow(row); + for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) + { + ModCommand &m = rowData[chn]; + uint8 data[5]{}; + file.ReadStructPartial(data, eventSize); + if(data[0] >= 24 && data[0] < 84) + { + m.note = data[0] + NOTE_MIN + 12; + lastNoteInstr[chn].first = m.note; + } + if(data[1]) + { + m.instr = data[1]; + lastNoteInstr[chn].second = m.instr; + } + TranslateGraoumfEffect(*this, m, data[2], data[3], -static_cast(fileHeader.fileVersion), lastNoteInstr[chn].first, lastNoteInstr[chn].second, currentTempo, currentSpeed); + if(data[4]) + { + m.volcmd = VOLCMD_VOLUME; + m.vol = static_cast((data[4] + uint32(1)) / 4u); + } + } + } + } + + if(!(loadFlags & loadSampleData)) + return true; + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + { + SampleIO( + Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::bigEndian, + SampleIO::signedPCM).ReadSample(Samples[smp], file); + } + + return true; +} + + +// GT2 File Header +struct GT2FileHeader +{ + char signature[3]; + uint8be fileVersion; + uint32be headerSize; + char songName[32]; + char smallComment[160]; + uint8be day; + uint8be month; + uint16be year; + char trackerName[24]; + // The following fields are only present in version 0-5. + uint16be speed; + uint16be tempo; + uint16be masterVol; + uint16be numPannedTracks; + + bool Validate() const + { + if(std::memcmp(signature, "GT2", 3) || fileVersion > 9 || year < 1980 || year > 9999) + return false; + if(fileVersion > 5) + return true; + return speed > 0 && tempo > 0 && masterVol <= 0xFFF && numPannedTracks <= 99; + } + + uint64 GetHeaderMinimumAdditionalSize() const + { + return std::max(static_cast(headerSize), sizeof(GT2FileHeader)) - sizeof(GT2FileHeader) + 20u; // 10 bytes each for required PATS and SONG chunks + } +}; + +MPT_BINARY_STRUCT(GT2FileHeader, 236) + + +// GT2 File Header +struct GT2Chunk +{ + // 32-Bit chunk identifiers + enum ChunkIdentifiers : uint32 + { + idXCOM = MagicBE("XCOM"), + idTCN1 = MagicBE("TCN1"), + idTCN2 = MagicBE("TCN2"), + idTVOL = MagicBE("TVOL"), + idMIXP = MagicBE("MIXP"), + idSONG = MagicBE("SONG"), + idPATS = MagicBE("PATS"), + idPATD = MagicBE("PATD"), + idTNAM = MagicBE("TNAM"), + idINST = MagicBE("INST"), + idVENV = MagicBE("VENV"), + idTENV = MagicBE("TENV"), + idPENV = MagicBE("PENV"), + idSAMP = MagicBE("SAMP"), + idSAM2 = MagicBE("SAM2"), + idENDC = MagicBE("ENDC"), + }; + + uint32be id; + uint32be length; + + size_t GetLength() const + { + return std::max(length.get(), uint32(8)) - 8u; + } + + ChunkIdentifiers GetID() const + { + return static_cast(id.get()); + } +}; + +MPT_BINARY_STRUCT(GT2Chunk, 8) + + +// GT2 Pattern Data +struct GT2PatternCell +{ + uint8 note; + uint8 instr; + uint8 effect; + uint8 param; + uint8 volume; +}; + +MPT_BINARY_STRUCT(GT2PatternCell, 5) + + +// GT2 Track Name +struct GT2TrackName +{ + uint16be type; + uint16be trackNumber; + char name[32]; +}; + +MPT_BINARY_STRUCT(GT2TrackName, 36) + + +// GT2 Instrument +struct GT2Instrument +{ + struct SampleInfo + { + uint8 num; + int8 transpose; + }; + + uint16be insNum; + char name[28]; + uint16be type; // 0 = sample-based + uint16be defaultVelocity; // 0...256 + int16be defaultPan; // -1 = use track panning, 0...4095 otherwise + uint16be volEnv; // 0 = no envelope + uint16be toneEnv; // 0 = no envelope + uint16be panEnv; // 0 = no envelope + uint16be cutoffEnv; // 0 = no envelope + uint16be resoEnv; // 0 = no envelope + char reserved[4]; + uint16be version; // 0...2 + SampleInfo samples[128]; +}; + +MPT_BINARY_STRUCT(GT2Instrument, 308) + + +struct GT2InstrumentExt +{ + enum FilterFlags : uint16 + { + fltEnabled = 0x01, + fltVelToCutoff = 0x02, + fltVelToReso = 0x04, + fltTypeMask = 0x18, + + fltTypeLowpass = 0x00, + fltTypeHighpass = 0x08, + fltTypeBandpass = 0x10, + fltTypeNotch = 0x18, + }; + + uint16be filterFlags; // See FilterFlags + char maxVelFreq[24]; // Cutoff frequency for the minimum velocity (256); <= 20: Multiple of the note frequency, > 20: Fixed frequency in Hz + char minVelFreq[24]; // Cutoff frequency for the maximum velocity (0); ditto + char maxVelReso[24]; // Q (resonance) value for the minimum velocity (256) + char minVelReso[24]; // Q (resonance) value for the maximum velocity (0) + uint8 pitchPanCenter; // Unused + uint8 pitchPanSep; // Unused + uint8 accent; // Unused + uint8 numEnvelopes; +}; + +MPT_BINARY_STRUCT(GT2InstrumentExt, 102) + + +struct GT2Envelope +{ + enum EnvelopeFlags : uint16 + { + envFadeOut = 0x01, + envLFO = 0x02, + envLoop = 0x10, + envSustain = 0x20, + }; + + struct EnvPoint + { + uint16be duration; + int16be value; + }; + + uint16be numPoints; + uint16be lfoDepth; + uint16be lfoSpeed; + uint16be lfoSweep; + uint16be lfoWaveform; + uint16be fadeOut; + uint16be flags; // See EnvelopeFlags + uint16be loopStart; + uint16be loopEnd; + uint16be loopRepCount; + uint16be sustainStart; + uint16be sustainEnd; + uint16be sustainRepCount; + EnvPoint data[64]; + + void ConvertToMPT(ModInstrument &mptIns, EnvelopeType type) const + { + InstrumentEnvelope &mptEnv = mptIns.GetEnvelope(type); + mptEnv.resize(std::min(numPoints.get(), static_cast(std::size(data)))); + mptEnv.nLoopStart = static_cast(loopStart); + mptEnv.nLoopEnd = static_cast(loopEnd); + mptEnv.nSustainStart = static_cast(sustainStart); + mptEnv.nSustainEnd = static_cast(sustainEnd); + mptEnv.dwFlags.set(ENV_ENABLED, !mptEnv.empty()); + mptEnv.dwFlags.set(ENV_LOOP, (flags & envLoop) != 0); + mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & envSustain) != 0); + + int16 minValue, maxValue; + switch(type) + { + case ENV_VOLUME: + default: + minValue = 0; + maxValue = 4096; + break; + case ENV_PANNING: + minValue = -128; + maxValue = 127; + break; + case ENV_PITCH: + minValue = -9999 * 16 / 99; + maxValue = 9999 * 16 / 99; + break; + } + + uint16 tick = 0; + for(uint32 i = 0; i < mptEnv.size(); i++) + { + mptEnv[i].tick = tick; + int32 value = data[i].value + minValue; + value = Util::muldivr(value, ENVELOPE_MAX, maxValue - minValue); + mptEnv[i].value = mpt::saturate_cast(value); + tick += std::max(data[i].duration.get(), uint16(1)); + } + } +}; + +MPT_BINARY_STRUCT(GT2Envelope, 282) + + +struct GT2SampleV2 +{ + uint16be smpNum; + char name[28]; + uint16be type; // 0 = memory-based, 1 = disk-based + uint16be bits; + uint16be endian; // 0 = big, 1 = little + uint16be numChannels; + int16be defaultPan; // -1 = use track panning, 0...4095 otherwise + uint16be volume; // 0...4095, 256 = 0dB + int16be finetune; // -8...7 + uint16be loopType; // 0 = no, 1 = forward, 2 = ping-pong + int16be midiNote; // 48 = default (no transpose) + uint16be sampleCoding; // 0 = PCM in module, 1 = PCM in separate file + uint16be filenameLen; + int16be yPanning; // Unused + uint32be sampleFreq; // Sample frequency of reference note + uint32be length; + uint32be loopStart; + uint32be loopLength; + uint32be loopBufLength; + uint32be dataOffset; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_IT); + mptSmp.Set16BitCuePoints(); + + mptSmp.nGlobalVol = volume / 4u; + if(defaultPan > 0) + { + mptSmp.uFlags.set(CHN_PANNING); + mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); + } + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + mptSmp.uFlags.set(CHN_LOOP, loopType != 0); + mptSmp.uFlags.set(CHN_PINGPONGLOOP, loopType & 2); + mptSmp.nC5Speed = sampleFreq * 2u; + if(finetune != 0) + mptSmp.Transpose(finetune / (12.0 * 8.0)); + mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command + } + + SampleIO GetSampleFormat() const + { + return SampleIO( + bits == 8 ? SampleIO::_8bit : SampleIO::_16bit, + numChannels == 1 ? SampleIO::mono : SampleIO::stereoInterleaved, + endian == 0 ? SampleIO::bigEndian : SampleIO::littleEndian, + SampleIO::signedPCM); + } +}; + +MPT_BINARY_STRUCT(GT2SampleV2, 78) + + +struct GT2SampleV1 +{ + enum SampleFlags : uint16 + { + smpStereo = 0x01, + smpPingPong = 0x02, + }; + + uint16be smpNum; + char name[28]; + uint16be flags; // See SampleFlags + int16be defaultPan; // -1 = use track panning, 0...4095 otherwise + uint16be bits; + uint16be sampleFreq; + uint32be length; + uint32be loopStart; + uint32be loopLength; // Loop is deactivated if loopStart = 0 and loopLength = 2 + int16be volume; // 0...255 + int16be finetune; // -8...7 + uint16be sampleCoding; // 0 + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_IT); + mptSmp.Set16BitCuePoints(); + + mptSmp.nGlobalVol = volume / 4u; + if(defaultPan > 0) + { + mptSmp.uFlags.set(CHN_PANNING); + mptSmp.nPan = static_cast(Util::muldivr_unsigned(defaultPan, 256, 4095)); + } + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + if(bits == 16) + { + mptSmp.nLength /= 2u; + mptSmp.nLoopStart /= 2u; + mptSmp.nLoopEnd /= 2u; + } + mptSmp.uFlags.set(CHN_LOOP, loopStart > 0 || loopLength > 2); + mptSmp.uFlags.set(CHN_PINGPONGLOOP, (flags & GT2SampleV1::smpPingPong) != 0); + mptSmp.nC5Speed = sampleFreq * 2u; + if(finetune != 0) + mptSmp.Transpose(finetune / (12.0 * 8.0)); + mptSmp.nFineTune = MOD2XMFineTune(finetune); // We store this because we need to undo the finetune for the auto-tempo command + } + + SampleIO GetSampleFormat() const + { + return SampleIO( + bits == 8 ? SampleIO::_8bit : SampleIO::_16bit, + (flags & GT2SampleV1::smpStereo) ? SampleIO::stereoInterleaved : SampleIO::mono, + SampleIO::bigEndian, + SampleIO::signedPCM); + } +}; + +MPT_BINARY_STRUCT(GT2SampleV1, 56) + + +struct GT2MixPreset +{ + uint16be number; + char name[32]; + uint16be trackType; + uint16be trackIndex; + uint16be numTracks; + uint16be volWet; // 0..1000..FFFF + uint16be panWet; // 0...FFF + uint16be volDry; + uint16be panDry; + uint16be version; // 0x101 + uint16be stereo; + uint32be reserved; +}; + +MPT_BINARY_STRUCT(GT2MixPreset, 56) + + +struct GT2MixPresetTrack +{ + uint8 trackType; + uint8 dryFlag; // Effects tracks: 0 = wet, 1 = dry + uint16be trackIndex; + uint16be volume; // 0..1000..FFFF + uint16be balance; // 0..800..FFF +}; + +MPT_BINARY_STRUCT(GT2MixPresetTrack, 8) + + +static EnvelopeNode::value_t ConvertGT2EnvelopeValue(const EnvelopeType envType, int32 value) +{ + if(envType == ENV_VOLUME) + value = Util::muldivr(value, ENVELOPE_MAX, 16384); + else if(envType == ENV_PANNING) + value = Util::muldivr(value, ENVELOPE_MAX, 4096); + else + value = mpt::saturate_round(mpt::log2(8192.0 / std::max(value, int32(1))) * 24.0 + (ENVELOPE_MID - 24)); + return static_cast(Clamp(value, ENVELOPE_MIN, ENVELOPE_MAX)); +} + +static void ConvertGT2Envelope(ModInstrument &mptIns, const EnvelopeType envType, const uint16 envNum, std::vector &envChunks) +{ + if(!envNum) + return; + auto &mptEnv = mptIns.GetEnvelope(envType); + for(auto &chunk : envChunks) + { + chunk.Rewind(); + if(chunk.ReadUint16BE() != envNum) + continue; + chunk.Skip(20); // Name + uint32 chunkOffset = 24; + const uint32 keyoffOffset = chunk.ReadUint16BE() + chunkOffset; + bool keyOffRequested = false, addSustainAtEnd = true; + + int16 step = 0; + uint8 speed = 1; + uint8 counter = 0; + uint32 counterOffset = 0; // Position of last encountered counter (to avoid infinite parsing loops) + int32 initValue = 16384; + if(envType == ENV_PITCH) + initValue = 4096; + else if(envType == ENV_PANNING) + initValue = 2048; + int32 value = initValue; + + std::map offsetToPoint; + mptEnv.assign(1, {0u, (envType == ENV_VOLUME) ? ENVELOPE_MAX : ENVELOPE_MID}); + while(chunk.CanRead(1)) + { + offsetToPoint[static_cast(chunk.GetPosition())] = mptEnv.size(); + const uint8 command = chunk.ReadUint8(); + if(command == 0) + { + if(keyoffOffset <= chunkOffset) + break; + keyOffRequested = true; + } + switch(command) + { + case 0x01: // 01: Unconditional Jump + if(!mptEnv.dwFlags[ENV_SUSTAIN]) + { + mptEnv.nSustainStart = static_cast(offsetToPoint[chunk.ReadUint16BE()]); + mptEnv.nSustainEnd = static_cast(mptEnv.size() - 1); + mptEnv.dwFlags.set(ENV_SUSTAIN); + } + break; + case 0x02: // 02: Wait + { + uint16 delay = std::max(chunk.ReadUint16BE(), uint16(1)); + value += step * speed * delay; + if(delay > 1) + mptEnv.emplace_back(mpt::saturate_cast(mptEnv.back().tick + delay - 1u), ConvertGT2EnvelopeValue(envType, value)); + mptEnv.emplace_back(mpt::saturate_cast(mptEnv.back().tick + 1u), ConvertGT2EnvelopeValue(envType, value)); + } + break; + case 0x03: // 03: Set Counter + counter = chunk.ReadUint8(); + counterOffset = static_cast(chunk.GetPosition()); + break; + case 0x04: // 04: Loop + if(const uint32 loopStart = chunk.ReadUint16BE() + chunkOffset; loopStart >= counterOffset && counter) + { + if(--counter) + chunk.Seek(loopStart); + } else if(counter) + { + // This is an infinite loop. + mptEnv.nLoopStart = static_cast(offsetToPoint[loopStart]); + mptEnv.nLoopEnd = static_cast(mptEnv.size() - 1); + mptEnv.dwFlags.set(ENV_LOOP); + } + break; + case 0x05: // 05: Key Off + keyOffRequested = true; + addSustainAtEnd = false; + break; + + case 0x80: // 80: Set Volume (16384 = 100%, max = 32767) + case 0xA0: // A0: Set Tone (4096 = normal period) + case 0xC0: // C0: Set Panning (2048 = normal position) + value = chunk.ReadUint16BE(); + mptEnv.back().value = ConvertGT2EnvelopeValue(envType, value); + break; + + case 0x81: // 81: Set Volume step + case 0xA1: // A1: Set Tone step + case 0xC1: // C1: Set Pan step + step = chunk.ReadInt16BE(); + break; + case 0x82: // 82: Set Volume speed + case 0xA2: // A2: Set Tone speed + case 0xC2: // C2: Set Pan speed + speed = std::max(chunk.ReadUint8(), uint8(1)); + break; + + // Various more complex features are not implemented as I couldn't find any actual GT2 modules using the envelope feature at all. + case 0x87: // 87: Tremor On + case 0x88: // 88: Tremor Off + case 0x83: // 83: Tremolo On + case 0x84: // 84: Tremolo Off + case 0xA3: // A3: Vibrato On + case 0xA4: // A4: Vibrato Off + break; + case 0x85: // 85: Set Tremolo Width + case 0x86: // 86: Set Tremolo Speed + case 0x89: // 89: Set Tremor Time 1 + case 0x8A: // 8A: Set Tremor Time 2 + case 0xA5: // A5: Set Vibrato Width + case 0xA6: // A6: Set Vibrato Speed + chunk.Skip(1); + break; + } + + if(keyOffRequested && keyoffOffset > chunkOffset) + { + // Enter key-off section, but only if we can read more than just the expected end marker byte + chunkOffset = keyoffOffset; + if(!chunk.Seek(chunkOffset) || !chunk.CanRead(2)) + break; + if(!mptEnv.dwFlags[ENV_SUSTAIN] && addSustainAtEnd) + { + mptEnv.nSustainStart = mptEnv.nSustainEnd = static_cast(mptEnv.size() - 1); + mptEnv.dwFlags.set(ENV_SUSTAIN); + } + value = initValue; + mptEnv.emplace_back(mpt::saturate_cast(mptEnv.back().tick + 1u), ConvertGT2EnvelopeValue(envType, value)); + mptEnv.nReleaseNode = mptEnv.nSustainEnd + 1; + } + } + mptEnv.dwFlags.set(ENV_ENABLED); + break; + } +} + + +CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGT2(MemoryFileReader file, const uint64 *pfilesize) +{ + GT2FileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return ProbeWantMoreData; + if(!fileHeader.Validate()) + return ProbeFailure; + return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize()); +} + + +bool CSoundFile::ReadGT2(FileReader &file, ModLoadingFlags loadFlags) +{ + file.Rewind(); + + GT2FileHeader fileHeader; + if(!file.ReadStruct(fileHeader)) + return false; + if(!fileHeader.Validate()) + return false; + if(!file.CanRead(mpt::saturate_cast(fileHeader.GetHeaderMinimumAdditionalSize()))) + return false; + if(loadFlags == onlyVerifyHeader) + return true; + + // Globals + InitializeGlobals(MOD_TYPE_MPT); + InitializeChannels(); + m_SongFlags.set(SONG_IMPORTED | SONG_EXFILTERRANGE); + m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT); + m_playBehaviour.set(kFT2ST3OffsetOutOfRange, fileHeader.fileVersion >= 6); + m_playBehaviour.set(kApplyOffsetWithoutNote); + + FileHistory mptHistory; + mptHistory.loadDate.day = Clamp(fileHeader.day, 1, 31); + mptHistory.loadDate.month = Clamp(fileHeader.month, 1, 12); + mptHistory.loadDate.year = fileHeader.year; + m_FileHistory.push_back(mptHistory); + + m_nChannels = 32; + m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.trackerName)); + m_modFormat.formatName = (fileHeader.fileVersion <= 5 ? MPT_UFORMAT("Graoumf Tracker v{}") : MPT_UFORMAT("Graoumf Tracker 2 v{}"))(fileHeader.fileVersion); + m_modFormat.type = U_("gt2"); + m_modFormat.charset = mpt::Charset::ISO8859_1_no_C1; + + m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songName); + + m_nSamplePreAmp = 256; + m_nDefaultGlobalVolume = 384 / (3 + m_nChannels); // See documentation on command 5xxx + + if(fileHeader.fileVersion <= 5) + { + m_nDefaultSpeed = std::max(fileHeader.speed.get(), uint16(1)); + m_nDefaultTempo.Set(std::max(fileHeader.tempo.get(), uint16(1))); + m_nDefaultGlobalVolume = std::min(Util::muldivr_unsigned(fileHeader.masterVol, MAX_GLOBAL_VOLUME, 4095), uint32(MAX_GLOBAL_VOLUME)); + uint16 tracks = fileHeader.numPannedTracks; + LimitMax(tracks, MAX_BASECHANNELS); + for(CHANNELINDEX chn = 0; chn < tracks; chn++) + { + ChnSettings[chn].nPan = std::min(static_cast(Util::muldivr_unsigned(file.ReadUint16BE(), 256, 4095)), uint16(256)); + } + } + file.Seek(fileHeader.headerSize); + + ChunkReader chunkFile(file); + auto chunks = chunkFile.ReadChunksUntil(1, GT2Chunk::idENDC); + + if(auto chunk = chunks.GetChunk(GT2Chunk::idPATS); chunk.CanRead(2)) + { + if(uint16 channels = chunk.ReadUint16BE(); channels >= 1 && channels <= MAX_BASECHANNELS) + m_nChannels = channels; + else + return false; + } else + { + return false; + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idSONG); chunk.CanRead(2)) + { + ORDERINDEX numOrders = chunk.ReadUint16BE(); + Order().SetRestartPos(chunk.ReadUint16BE()); + LimitMax(numOrders, mpt::saturate_cast(chunk.BytesLeft() / 2u)); + ReadOrderFromFile(Order(), chunk, numOrders); + } else + { + return false; + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idXCOM); chunk.CanRead(3)) + { + const uint16 length = chunk.ReadUint16BE(); + m_songMessage.Read(chunk, length, SongMessage::leAutodetect); + } else + { + size_t msgLength = sizeof(fileHeader.smallComment); + while(msgLength > 0 && fileHeader.smallComment[msgLength - 1] == ' ') + msgLength--; + m_songMessage.Read(mpt::byte_cast(fileHeader.smallComment), msgLength, SongMessage::leAutodetect); + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idTCN1); chunk.ReadUint8() == 0 && chunk.Seek(2648)) + { + // Only channel mute status is of interest here + uint32 muteStatus = chunk.ReadUint32BE(); + for(CHANNELINDEX i = 0; i < 32; i++) + { + ChnSettings[i].dwFlags.set(CHN_MUTE, !(muteStatus & (1u << i))); + } + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idTCN2); chunk.CanRead(12)) + { + const auto [chunkVersion, bpmInt, bpmFract, speed, timeSigNum, timeSigDenum] = chunk.ReadArray(); + m_nDefaultTempo = TEMPO(Clamp(bpmInt, 32, 999), Util::muldivr_unsigned(bpmFract, TEMPO::fractFact, 65536)); + m_nDefaultSpeed = Clamp(speed, 1, 255); + m_nDefaultRowsPerBeat = 16 / Clamp(timeSigDenum, 1, 16); + m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * Clamp(timeSigNum, 1, 16); + if(chunkVersion >= 1) + { + uint16 periodMode = chunk.ReadUint16BE(); + m_SongFlags.set(SONG_LINEARSLIDES, !periodMode); + } + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idTVOL); chunk.CanRead(2)) + { + CHANNELINDEX numChannels = std::min(static_cast(chunk.ReadUint16BE()), GetNumChannels()); + for(CHANNELINDEX chn = 0; chn < numChannels; chn++) + { + ChnSettings[chn].nVolume = static_cast(std::min(chunk.ReadUint16BE(), uint16(4096)) / 64u); + } + } + + // There can be more than one mix preset, but we only care about the first one (which appears to be the one that's always active when loading a file) + if(auto chunk = chunks.GetChunk(GT2Chunk::idMIXP); chunk.CanRead(sizeof(GT2MixPreset))) + { + GT2MixPreset mixPreset; + chunk.ReadStruct(mixPreset); + if(mixPreset.trackType == 4 && mixPreset.version == 0x101) + { + m_nDefaultGlobalVolume = Util::muldivr_unsigned(std::min(mixPreset.volWet.get(), uint16(0x4000)), MAX_GLOBAL_VOLUME, 0x1000); + for(uint16 i = 0 ; i < mixPreset.numTracks; i++) + { + GT2MixPresetTrack mixTrack; + chunk.ReadStruct(mixTrack); + if(mixTrack.trackType == 0 && mixTrack.trackIndex < GetNumChannels()) + { + auto &chnSetting = ChnSettings[mixTrack.trackIndex]; + chnSetting.nPan = static_cast(Util::muldivr_unsigned(mixTrack.balance, 256, 0xFFF)); + chnSetting.nVolume = static_cast(Util::muldivr_unsigned(mixTrack.volume, 64, 0x1000)); + } + } + } + } + + for(auto &smpChunk : chunks.GetAllChunks(GT2Chunk::idSAM2)) + { + GT2SampleV2 sample; + if(!smpChunk.ReadStruct(sample) + || !sample.smpNum + || sample.smpNum >= MAX_SAMPLES + || sample.sampleCoding > 1 + || sample.type > 1) + continue; + + if(sample.smpNum > m_nSamples) + m_nSamples = sample.smpNum; + + ModSample &mptSmp = Samples[sample.smpNum]; + sample.ConvertToMPT(mptSmp); + m_szNames[sample.smpNum] = mpt::String::ReadBuf(mpt::String::spacePadded, sample.name); + + if((loadFlags & loadSampleData) && smpChunk.Seek(sample.dataOffset - 8)) + { + if(sample.type == 0) + sample.GetSampleFormat().ReadSample(mptSmp, smpChunk); + + std::string filenameU8; + smpChunk.ReadString(filenameU8, sample.filenameLen); + mptSmp.filename = filenameU8; + + if(sample.type == 1) + { +#ifdef MPT_EXTERNAL_SAMPLES +#if MPT_OS_WINDOWS + std::transform(filenameU8.begin(), filenameU8.end(), filenameU8.begin(), [] (char c) { if(c == '/') return '\\'; else return c; }); +#endif // MPT_OS_WINDOWS + SetSamplePath(sample.smpNum, mpt::PathString::FromUTF8(filenameU8)); + mptSmp.uFlags.set(SMP_KEEPONDISK); +#else + AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(sample.smpNum, mpt::ToUnicode(mpt::Charset::UTF8, filenameU8))); +#endif // MPT_EXTERNAL_SAMPLES + } + } + +#if 0 + if(fileHeader.fileVersion >= 9) + { + if(!(loadFlags & loadSampleData)) + { + smpChunk.Seek(sample.dataOffset - 8 + sample.filenameLen); + if(sample.type == 0) + smpChunk.Skip(sample.GetSampleFormat().CalculateEncodedSize(mptSmp.nLength)); + } + if(smpChunk.Seek((smpChunk.GetPosition() + 3u) & ~3u)) + { + const uint16 version = smpChunk.ReadUint16BE(); + if(version <= 1) + { + const uint16 sampleGroup = smpChunk.ReadUint16BE(); + } + } + } +#endif + } + + for(auto &smpChunk : chunks.GetAllChunks(GT2Chunk::idSAMP)) + { + GT2SampleV1 sample; + if(!smpChunk.ReadStruct(sample) + || !sample.smpNum + || sample.smpNum >= MAX_SAMPLES + || sample.sampleCoding != 0) + continue; + + if(sample.smpNum > m_nSamples) + m_nSamples = sample.smpNum; + + ModSample &mptSmp = Samples[sample.smpNum]; + sample.ConvertToMPT(mptSmp); + m_szNames[sample.smpNum] = mpt::String::ReadBuf(mpt::String::spacePadded, sample.name); + if(loadFlags & loadSampleData) + sample.GetSampleFormat().ReadSample(mptSmp, smpChunk); + } + + auto volEnvChunks = chunks.GetAllChunks(GT2Chunk::idVENV), pitchEnvChunks = chunks.GetAllChunks(GT2Chunk::idTENV), panEnvChunks = chunks.GetAllChunks(GT2Chunk::idPENV); + for(auto &insChunk : chunks.GetAllChunks(GT2Chunk::idINST)) + { + GT2Instrument instr; + ModInstrument *mptIns; + if(!insChunk.ReadStruct(instr) + || instr.type != 0 + || (mptIns = AllocateInstrument(instr.insNum)) == nullptr) + continue; + + if(instr.insNum > m_nInstruments) + m_nInstruments = instr.insNum; + mptIns->name = mpt::String::ReadBuf(mpt::String::spacePadded, instr.name); + mptIns->midiPWD = 2; + if(instr.defaultPan > 0) + { + mptIns->dwFlags.set(INS_SETPANNING); + mptIns->nPan = Util::muldivr_unsigned(instr.defaultPan, 256, 4095); + } + for(uint8 i = 0; i < std::min(std::size(mptIns->Keyboard), std::size(instr.samples)); i++) + { + mptIns->Keyboard[i] = instr.samples[i].num; + mptIns->NoteMap[i] = static_cast(Clamp(mptIns->NoteMap[i] + instr.samples[i].transpose, NOTE_MIN, NOTE_MAX)); + } + for(SAMPLEINDEX smp : mptIns->GetSamples()) + { + if(smp > 0 && smp <= GetNumSamples()) + Samples[smp].nVolume = instr.defaultVelocity; + } + + mptIns->SetCutoff(0x7F, true); + mptIns->SetResonance(0, true); + + if(instr.version == 0) + { + // Old "envelopes" + mptIns->nFadeOut = 0; + ConvertGT2Envelope(*mptIns, ENV_VOLUME, instr.volEnv, volEnvChunks); + ConvertGT2Envelope(*mptIns, ENV_PANNING, instr.panEnv, panEnvChunks); + ConvertGT2Envelope(*mptIns, ENV_PITCH, instr.toneEnv, pitchEnvChunks); + } else + { + GT2InstrumentExt instrExt; + insChunk.ReadStructPartial(instrExt, (instr.version == 1) ? offsetof(GT2InstrumentExt, pitchPanCenter) : sizeof(GT2InstrumentExt)); + + const bool filterEnabled = (instrExt.filterFlags & GT2InstrumentExt::fltEnabled); + if(filterEnabled) + { + if(auto filterType = (instrExt.filterFlags & GT2InstrumentExt::fltTypeMask); filterType == GT2InstrumentExt::fltTypeLowpass) + mptIns->filterMode = FilterMode::LowPass; + else if(filterType == GT2InstrumentExt::fltTypeHighpass) + mptIns->filterMode = FilterMode::HighPass; + if(instrExt.filterFlags & GT2InstrumentExt::fltVelToCutoff) + { + // Note: we're missing the velocity to cutoff modulation here, and also the envelope is added on top of this in GT2, while we multiply it. + const double maxCutoff = mpt::parse(std::string{instrExt.maxVelFreq, sizeof(instrExt.maxVelFreq)}); + if(maxCutoff > 20) + mptIns->SetCutoff(FrequencyToCutOff(maxCutoff), true); + } + if(instrExt.filterFlags & GT2InstrumentExt::fltVelToReso) + { + const double maxReso = mpt::parse(std::string{instrExt.maxVelReso, sizeof(instrExt.maxVelReso)}); + mptIns->SetResonance(mpt::saturate_round(maxReso * 127.0 / 24.0), true); + } + } + + for(uint8 env = 0; env < instrExt.numEnvelopes; env++) + { + GT2Envelope envelope; + insChunk.ReadStruct(envelope); + + const EnvelopeType envType[] = {ENV_VOLUME, ENV_PITCH, ENV_PANNING, ENV_PITCH}; + const bool envEnabled[] = {instr.volEnv != 0, instr.toneEnv != 0, instr.panEnv != 0, instr.cutoffEnv != 0 && filterEnabled}; + if(env >= std::size(envType) || !envEnabled[env]) + continue; + // Only import cutoff envelope if it wouldn't overwrite pitch envelope + if(env == 3 && mptIns->PitchEnv.dwFlags[ENV_ENABLED]) + continue; + envelope.ConvertToMPT(*mptIns, envType[env]); + if(env == 3) + mptIns->PitchEnv.dwFlags.set(ENV_FILTER); + + if(envType[env] == ENV_VOLUME) + { + if(envelope.flags & GT2Envelope::envFadeOut) + mptIns->nFadeOut = envelope.fadeOut & 0x7FFF; // High bit = logarithmic flag + else + mptIns->nFadeOut = 0; + } else if(envType[env] == ENV_PITCH && (envelope.flags & GT2Envelope::envLFO)) + { + static constexpr VibratoType vibTyes[] = {VIB_SINE, VIB_SQUARE, VIB_SINE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM}; + uint8 sweep = static_cast(255 / std::max(envelope.lfoSweep.get(), uint16(1))); + uint8 depth = mpt::saturate_cast(Util::muldivr_unsigned(envelope.lfoDepth, 64, 100)); + uint8 speed = mpt::saturate_cast(256 / std::max(envelope.lfoSpeed.get(), uint16(1))); + PropagateXMAutoVibrato(instr.insNum, vibTyes[envelope.lfoWaveform < std::size(vibTyes) ? envelope.lfoWaveform : 0], sweep, depth, speed); + } + } + } + } + + auto patterns = chunks.GetAllChunks(GT2Chunk::idPATD); + Patterns.ResizeArray(static_cast(patterns.size())); + TEMPO currentTempo = m_nDefaultTempo; + uint32 currentSpeed = m_nDefaultSpeed; + for(auto &patChunk : patterns) + { + if(!(loadFlags & loadPatternData) || !patChunk.CanRead(24)) + continue; + + const uint16 patNum = patChunk.ReadUint16BE(); + char name[17]{}; + patChunk.ReadString(name, 16); + const uint16 codingVersion = patChunk.ReadUint16BE(); + const ROWINDEX numRows = patChunk.ReadUint16BE(); + const CHANNELINDEX numTracks = patChunk.ReadUint16BE(); + + if(!patChunk.CanRead(sizeof(GT2PatternCell) * numRows * numTracks)) + continue; + if(codingVersion > 1 || !Patterns.Insert(patNum, numRows)) + continue; + + Patterns[patNum].SetName(name); + std::vector> lastNoteInstr(numTracks, {NOTE_NONE, {}}); + for(ROWINDEX row = 0; row < numRows; row++) + { + auto rowBase = Patterns[patNum].GetRow(row); + for(CHANNELINDEX chn = 0; chn < numTracks; chn++) + { + ModCommand dummy; + ModCommand &m = (chn < GetNumChannels()) ? rowBase[chn] : dummy; + + GT2PatternCell data; + patChunk.ReadStruct(data); + + if(data.note > 0 && data.note <= NOTE_MAX - NOTE_MIN + 1) + lastNoteInstr[chn].first = m.note = data.note + NOTE_MIN; + if(data.instr) + lastNoteInstr[chn].second = m.instr = data.instr; + + if(data.volume) + { + m.volcmd = VOLCMD_VOLUME; + if(codingVersion == 0) + m.vol = data.volume / 4u; + else + m.vol = (data.volume - 0x10); + } + + TranslateGraoumfEffect(*this, m, data.effect, data.param, fileHeader.fileVersion, lastNoteInstr[chn].first, lastNoteInstr[chn].second, currentTempo, currentSpeed); + } + } + } + + if(auto chunk = chunks.GetChunk(GT2Chunk::idTNAM); chunk.CanRead(2 + sizeof(GT2TrackName))) + { + uint16 numNames = chunk.ReadUint16BE(); + for (uint16 i = 0; i < numNames && chunk.CanRead(sizeof(GT2TrackName)); i++) + { + GT2TrackName trackName; + chunk.ReadStruct(trackName); + if(trackName.type == 0 && trackName.trackNumber < m_nChannels) + { + ChnSettings[trackName.trackNumber].szName = mpt::String::ReadBuf(mpt::String::spacePadded, trackName.name); + } + } + } + + return true; +} + + +OPENMPT_NAMESPACE_END + diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp index aae972434..0815c1891 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_imf.cpp @@ -255,48 +255,48 @@ static constexpr EffectCommand imfEffects[] = CMD_NONE, // 0x23 Zxx Reverb - XXX }; -static void ImportIMFEffect(ModCommand &m) +static std::pair TranslateIMFEffect(uint8 command, uint8 param) { uint8 n; // fix some of them - switch(m.command) + switch(command) { case 0xE: // fine volslide // hackaround to get almost-right behavior for fine slides (i think!) - if(m.param == 0) + if(param == 0) /* nothing */; - else if(m.param == 0xF0) - m.param = 0xEF; - else if(m.param == 0x0F) - m.param = 0xFE; - else if(m.param & 0xF0) - m.param |= 0x0F; + else if(param == 0xF0) + param = 0xEF; + else if(param == 0x0F) + param = 0xFE; + else if(param & 0xF0) + param |= 0x0F; else - m.param |= 0xF0; + param |= 0xF0; break; case 0xF: // set finetune - m.param ^= 0x80; + param ^= 0x80; break; case 0x14: // fine slide up case 0x15: // fine slide down // this is about as close as we can do... - if(m.param >> 4) - m.param = 0xF0 | (m.param >> 4); + if(param >> 4) + param = 0xF0 | (param >> 4); else - m.param |= 0xE0; + param |= 0xE0; break; case 0x16: // cutoff - m.param = (0xFF - m.param) / 2u; + param = (0xFF - param) / 2u; break; case 0x17: // cutoff slide + resonance (TODO: cutoff slide is currently not handled) - m.param = 0x80 | (m.param & 0x0F); + param = 0x80 | (param & 0x0F); break; case 0x1F: // set global volume - m.param = mpt::saturate_cast(m.param * 2); + param = mpt::saturate_cast(param * 2); break; case 0x21: n = 0; - switch (m.param >> 4) + switch(param >> 4) { case 0: /* undefined, but since S0x does nothing in IT anyway, we won't care. @@ -306,7 +306,7 @@ static void ImportIMFEffect(ModCommand &m) default: // undefined case 0x1: // set filter case 0xF: // invert loop - m.command = CMD_NONE; + command = 0; break; case 0x3: // glissando n = 0x20; @@ -326,41 +326,34 @@ static void ImportIMFEffect(ModCommand &m) case 0xC: // note cut case 0xD: // note delay // Apparently, Imago Orpheus doesn't cut samples on tick 0. - if(!m.param) - m.command = CMD_NONE; + if(!param) + command = 0; break; case 0xE: // ignore envelope - switch(m.param & 0x0F) + switch(param & 0x0F) { // All envelopes // Predicament: we can only disable one envelope at a time. Volume is probably most noticeable, so let's go with that. - case 0: m.param = 0x77; break; + case 0: param = 0x77; break; // Volume - case 1: m.param = 0x77; break; + case 1: param = 0x77; break; // Panning - case 2: m.param = 0x79; break; + case 2: param = 0x79; break; // Filter - case 3: m.param = 0x7B; break; + case 3: param = 0x7B; break; } break; case 0x18: // sample offset // O00 doesn't pick up the previous value - if(!m.param) - m.command = CMD_NONE; + if(!param) + command = 0; break; } if(n) - m.param = n | (m.param & 0x0F); + param = n | (param & 0x0F); break; } - m.command = (m.command < std::size(imfEffects)) ? imfEffects[m.command] : CMD_NONE; - if(m.command == CMD_VOLUME && m.volcmd == VOLCMD_NONE) - { - m.volcmd = VOLCMD_VOLUME; - m.vol = m.param; - m.command = CMD_NONE; - m.param = 0; - } + return {(command < std::size(imfEffects)) ? imfEffects[command] : CMD_NONE, param}; } @@ -561,48 +554,19 @@ bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags) { // Read both effects and figure out what to do with them const auto [e1c, e1d, e2c, e2d] = patternChunk.ReadArray(); // Command 1, Data 1, Command 2, Data 2 - - if(e1c == 0x0C) - { - m.vol = std::min(e1d, uint8(0x40)); - m.volcmd = VOLCMD_VOLUME; - m.command = e2c; - m.param = e2d; - } else if(e2c == 0x0C) - { - m.vol = std::min(e2d, uint8(0x40)); - m.volcmd = VOLCMD_VOLUME; - m.command = e1c; - m.param = e1d; - } else if(e1c == 0x0A) - { - m.vol = e1d * 64 / 255; - m.volcmd = VOLCMD_PANNING; - m.command = e2c; - m.param = e2d; - } else if(e2c == 0x0A) - { - m.vol = e2d * 64 / 255; - m.volcmd = VOLCMD_PANNING; - m.command = e1c; - m.param = e1d; - } else - { - /* check if one of the effects is a 'global' effect - -- if so, put it in some unused channel instead. - otherwise pick the most important effect. */ - m.command = e2c; - m.param = e2d; - } + const auto [command1, param1] = TranslateIMFEffect(e1c, e1d); + const auto [command2, param2] = TranslateIMFEffect(e2c, e2d); + m.FillInTwoCommands(command1, param1, command2, param2); } else if(mask & 0xC0) { - // There's one effect, just stick it in the effect column - const auto [command, param] = patternChunk.ReadArray(); - m.command = command; - m.param = param; + // There's one effect, just stick it in the effect column (unless it's a volume command) + const auto [e1c, e1d] = patternChunk.ReadArray(); // Command 1, Data 1, Command 2, Data 2 + const auto [command, param] = TranslateIMFEffect(e1c, e1d); + if(command == CMD_VOLUME) + m.SetVolumeCommand(VOLCMD_VOLUME, param); + else + m.SetEffectCommand(command, param); } - if(m.command) - ImportIMFEffect(m); if(ignoreChannels[channel] && m.IsGlobalCommand()) m.command = CMD_NONE; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp index 734912e26..d8653ee03 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_it.cpp @@ -482,25 +482,10 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) m_dwLastSavedWithVersion = Version(mptVersion); } else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888) { - // OpenMPT 1.17.02.26 (r122) to 1.18 (raped IT format) + // OpenMPT 1.17.02.26 (r122) to 1.18 // Exact version number will be determined later. interpretModPlugMade = true; m_dwLastSavedWithVersion = MPT_V("1.17.00.00"); - } else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0) - { - if(memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != nullptr) - { - // ModPlug Tracker 1.16 (semi-raped IT format) or BeRoTracker (will be determined later) - m_dwLastSavedWithVersion = MPT_V("1.16.00.00"); - madeWithTracker = U_("ModPlug Tracker 1.09 - 1.16"); - } else - { - // OpenMPT 1.17 disguised as this in compatible mode, - // but never writes 0xFF in the pan map for unused channels (which is an invalid value). - m_dwLastSavedWithVersion = MPT_V("1.17.00.00"); - madeWithTracker = U_("OpenMPT 1.17 (compatibility export)"); - } - interpretModPlugMade = true; } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0) { // ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart @@ -708,11 +693,14 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) m_MidiCfg.ClearZxxMacros(); } + bool hasModPlugExtensions = false; + // Read pattern names: "PNAM" FileReader patNames; if(file.ReadMagic("PNAM")) { patNames = file.ReadChunk(file.ReadUint32LE()); + hasModPlugExtensions = true; } m_nChannels = 1; @@ -722,6 +710,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) FileReader chnNames = file.ReadChunk(file.ReadUint32LE()); const CHANNELINDEX readChns = std::min(MAX_BASECHANNELS, static_cast(chnNames.GetLength() / MAX_CHANNELNAME)); m_nChannels = readChns; + hasModPlugExtensions = true; for(CHANNELINDEX i = 0; i < readChns; i++) { @@ -731,7 +720,29 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) // Read mix plugins information FileReader pluginChunk = file.ReadChunk((minPtr >= file.GetPosition()) ? minPtr - file.GetPosition() : file.BytesLeft()); - const bool isBeRoTracker = LoadMixPlugins(pluginChunk); + const auto [hasPluginChunks, isBeRoTracker] = LoadMixPlugins(pluginChunk); + if(hasPluginChunks) + hasModPlugExtensions = true; + + if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0 && !isBeRoTracker) + { + if(hasModPlugExtensions + || (!Order().empty() && Order().back() == Order.GetInvalidPatIndex()) + || memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != nullptr) + { + m_dwLastSavedWithVersion = MPT_V("1.16"); + madeWithTracker = U_("ModPlug Tracker 1.09 - 1.16"); + } else + { + // OpenMPT 1.17 disguised as this in compatible mode, + // but never writes 0xFF in the pan map for unused channels (which is an invalid value). + // It also doesn't write a final "---" pattern in the order list. + // Could also be original ModPlug Tracker though if all 64 channels and no ModPlug extensions are used. + m_dwLastSavedWithVersion = MPT_V("1.17"); + madeWithTracker = U_("OpenMPT 1.17 (compatibility export)"); + } + interpretModPlugMade = true; + } // Read Song Message if((fileHeader.special & ITFileHeader::embedSongMessage) && fileHeader.msglength > 0 && file.Seek(fileHeader.msgoffset)) @@ -775,7 +786,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) // Reading Samples m_nSamples = std::min(static_cast(fileHeader.smpnum), static_cast(MAX_SAMPLES - 1)); - bool lastSampleCompressed = false; + bool lastSampleCompressed = false, anyADPCM = false; for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++) { ITSample sampleHeader; @@ -817,6 +828,9 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) // There is some XM to IT converter (don't know which one) and it identifies as IT 2.04. // The only safe way to distinguish it from an IT-saved file are the unsigned samples. possibleXMconversion = true; + } else if(sampleIO.GetEncoding() == SampleIO::ADPCM) + { + anyADPCM = true; } } else { @@ -975,14 +989,15 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) } // Load instrument and song extensions. - interpretModPlugMade |= LoadExtendedInstrumentProperties(file); + const bool hasExtendedInstrumentProperties = LoadExtendedInstrumentProperties(file); + interpretModPlugMade |= hasExtendedInstrumentProperties; if(interpretModPlugMade && !isBeRoTracker) { m_playBehaviour.reset(); m_nMixLevels = MixLevels::Original; } // Need to do this before reading the patterns because m_nChannels might be modified by LoadExtendedSongProperties. *sigh* - LoadExtendedSongProperties(file, false, &interpretModPlugMade); + const bool hasExtendedSongProperties = LoadExtendedSongProperties(file, false, &interpretModPlugMade); // Reading Patterns Patterns.ResizeArray(numPats); @@ -1014,7 +1029,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) CopyPatternName(Patterns[pat], patNames); std::vector chnMask(GetNumChannels()); - std::vector lastValue(GetNumChannels(), ModCommand::Empty()); + std::vector lastValue(GetNumChannels(), ModCommand{}); auto patData = Patterns[pat].begin(); ROWINDEX row = 0; @@ -1038,7 +1053,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) if(ch >= chnMask.size()) { chnMask.resize(ch + 1, 0); - lastValue.resize(ch + 1, ModCommand::Empty()); + lastValue.resize(ch + 1, ModCommand{}); MPT_ASSERT(chnMask.size() <= GetNumChannels()); } @@ -1048,7 +1063,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) } // Now we grab the data for this particular row/channel. - ModCommand dummy = ModCommand::Empty(); + ModCommand dummy{}; ModCommand &m = ch < m_nChannels ? patData[ch] : dummy; if(chnMask[ch] & 0x10) @@ -1128,9 +1143,7 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) if(chnMask[ch] & 8) { const auto [command, param] = patternData.ReadArray(); - m.command = command; - m.param = param; - S3MConvert(m, true); + S3MConvert(m, command, param, true); // In some IT-compatible trackers, it is possible to input a parameter without a command. // In this case, we still need to update the last value memory. OpenMPT didn't do this until v1.25.01.07. // Example: ckbounce.it @@ -1150,7 +1163,12 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) if(m_dwLastSavedWithVersion && madeWithTracker.empty()) { madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion); - if(memcmp(&fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000) + + bool isCompatExport = memcmp(&fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000; + if(m_dwLastSavedWithVersion == MPT_V("1.17.00.00")) + isCompatExport = !hasExtendedInstrumentProperties && !hasExtendedSongProperties && !hasModPlugExtensions; + + if(isCompatExport) { madeWithTracker += U_(" (compatibility export)"); } else if(m_dwLastSavedWithVersion.IsTestVersion()) @@ -1241,6 +1259,16 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) // Pitch/Pan Separation can be overridden by panning commands: Added 2021-11-01, https://github.com/schismtracker/schismtracker/commit/6e9f1207015cae0fe1b829fff7bb867e02ec6dea if(schismDateVersion < SchismVersionFromDate<2021, 11, 01>::date) m_playBehaviour.reset(kITPitchPanSeparation); + // Various fixes to multisampled instruments: Added 2022-04-30, https://github.com/schismtracker/schismtracker/commit/1b2f7d5522fcb971f134a6664182ca569f7c8008 + if(schismDateVersion < SchismVersionFromDate<2022, 04, 30>::date) + { + m_playBehaviour.reset(kITEmptyNoteMapSlot); + m_playBehaviour.reset(kITPortamentoSwapResetsPos); + m_playBehaviour.reset(kITMultiSampleInstrumentNumber); + } + // Initial note memory for channel is C-0: Added 2023-03-09, https://github.com/schismtracker/schismtracker/commit/73e9d60676c2b48c8e94e582373e29517105b2b1 + if(schismDateVersion < SchismVersionFromDate<2023, 03, 9>::date) + m_playBehaviour.reset(kITInitialNoteMemory); break; case 4: madeWithTracker = MPT_UFORMAT("pyIT {}.{}")((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF)); @@ -1260,6 +1288,9 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) } } + if(anyADPCM) + madeWithTracker += U_(" (ADPCM packed)"); + if(GetType() == MOD_TYPE_MPT) { // START - mpt specific: @@ -1273,6 +1304,19 @@ bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags) m_modFormat.type = (GetType() == MOD_TYPE_MPT) ? U_("mptm") : U_("it"); m_modFormat.madeWithTracker = std::move(madeWithTracker); m_modFormat.charset = m_dwLastSavedWithVersion ? mpt::Charset::Windows1252 : mpt::Charset::CP437; +#if MPT_TIME_UTC_ON_DISK +#ifdef MODPLUG_TRACKER + m_modFormat.timezone = (m_dwLastSavedWithVersion && (m_dwLastSavedWithVersion >= MPT_TIME_UTC_ON_DISK_VERSION)) ? mpt::Date::LogicalTimezone::UTC : mpt::Date::LogicalTimezone::Local; +#else + m_modFormat.timezone = (m_dwLastSavedWithVersion && (m_dwLastSavedWithVersion >= MPT_TIME_UTC_ON_DISK_VERSION)) ? mpt::Date::LogicalTimezone::UTC : mpt::Date::LogicalTimezone::Unspecified; +#endif +#else +#ifdef MODPLUG_TRACKER + m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; +#else + m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; +#endif +#endif return true; } @@ -1296,7 +1340,7 @@ void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv) mpt::Charset sequenceDefaultCharset = GetCharsetInternal(); ssb.ReadItem(Order, FileIdSequences, [sequenceDefaultCharset](std::istream &iStrm, ModSequenceSet &seq, std::size_t nSize){ return ReadModSequences(iStrm, seq, nSize, sequenceDefaultCharset); }); - if(ssb.GetStatus() & srlztn::SNT_FAILURE) + if(ssb.HasFailed()) { AddToLog(LogError, U_("Unknown error occurred while deserializing file.")); } @@ -1354,17 +1398,19 @@ static uint32 SaveITEditHistory(const CSoundFile &sndFile, std::ostream *file) } else if(pModDoc != nullptr) { // Current ("new") timestamp - const time_t creationTime = pModDoc->GetCreationTime(); - - MemsetZero(mptHistory.loadDate); - //localtime_s(&loadDate, &creationTime); - const tm* const p = localtime(&creationTime); - if (p != nullptr) - mptHistory.loadDate = *p; - else - sndFile.AddToLog(LogError, U_("Unable to retrieve current time.")); - - mptHistory.openTime = (uint32)(difftime(time(nullptr), creationTime) * HISTORY_TIMER_PRECISION); + const mpt::Date::Unix creationTime = pModDoc->GetCreationTime(); + if(sndFile.GetTimezoneInternal() == mpt::Date::LogicalTimezone::UTC) + { + mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(creationTime)); + } else if(sndFile.GetTimezoneInternal() == mpt::Date::LogicalTimezone::Local) + { + mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(creationTime)); + } else + { + // assume UTC + mptHistory.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(creationTime)); + } + mptHistory.openTime = static_cast(mpt::round((mpt::Date::UnixAsSeconds(mpt::Date::UnixNow()) - mpt::Date::UnixAsSeconds(creationTime)) * HISTORY_TIMER_PRECISION)); #endif // MODPLUG_TRACKER } @@ -1650,7 +1696,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c mpt::IO::Write(f, patinfo); dwPos += 8; - struct ChnState { ModCommand lastCmd; uint8 mask = 0xFF; }; + struct ChnState { uint8 note = 0, instr = 0, vol = 0, command = 0, param = 0, valid = 0, mask = 0xFF; }; const CHANNELINDEX maxChannels = std::min(specs.channelsMax, GetNumChannels()); std::vector chnStates(maxChannels); // Maximum 7 bytes per cell, plus end of row marker, so this buffer is always large enough to cover one row. @@ -1672,8 +1718,6 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c auto &chnState = chnStates[ch]; uint8 b = 0; - uint8 command = m->command; - uint8 param = m->param; uint8 vol = 0xFF; uint8 note = m->note; if (note != NOTE_NONE) b |= 1; @@ -1695,18 +1739,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c case VOLCMD_TONEPORTAMENTO: vol += 193; break; case VOLCMD_PORTADOWN: vol += 105; break; case VOLCMD_PORTAUP: vol += 115; break; - case VOLCMD_VIBRATOSPEED: - if(command == CMD_NONE) - { - // Move unsupported command if possible - command = CMD_VIBRATO; - param = std::min(m->vol, uint8(15)) << 4; - vol = 0xFF; - } else - { - vol = 203; - } - break; + case VOLCMD_VIBRATOSPEED: vol = 203; break; case VOLCMD_OFFSET: if(!compatibilityExport) vol += 223; @@ -1717,9 +1750,14 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c } } if (vol != 0xFF) b |= 4; - if (command != CMD_NONE) + uint8 command = 0, param = 0; + if(m->command == CMD_VOLUME && vol == 0xFF) { - S3MSaveConvert(command, param, true, compatibilityExport); + vol = std::min(m->param, ModCommand::PARAM(64)); + b |= 4; + } else if(m->command != CMD_NONE) + { + S3MSaveConvert(*m, command, param, true, compatibilityExport); if (command) b |= 8; } // Packing information @@ -1728,54 +1766,54 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c // Same note ? if (b & 1) { - if ((note == chnState.lastCmd.note) && (chnState.lastCmd.volcmd & 1)) + if ((note == chnState.note) && (chnState.valid & 1)) { b &= ~1; b |= 0x10; } else { - chnState.lastCmd.note = note; - chnState.lastCmd.volcmd |= 1; + chnState.note = note; + chnState.valid |= 1; } } // Same instrument ? if (b & 2) { - if ((m->instr == chnState.lastCmd.instr) && (chnState.lastCmd.volcmd & 2)) + if ((m->instr == chnState.instr) && (chnState.valid & 2)) { b &= ~2; b |= 0x20; } else { - chnState.lastCmd.instr = m->instr; - chnState.lastCmd.volcmd |= 2; + chnState.instr = m->instr; + chnState.valid |= 2; } } // Same volume column byte ? if (b & 4) { - if ((vol == chnState.lastCmd.vol) && (chnState.lastCmd.volcmd & 4)) + if ((vol == chnState.vol) && (chnState.valid & 4)) { b &= ~4; b |= 0x40; } else { - chnState.lastCmd.vol = vol; - chnState.lastCmd.volcmd |= 4; + chnState.vol = vol; + chnState.valid |= 4; } } // Same command / param ? if (b & 8) { - if ((command == chnState.lastCmd.command) && (param == chnState.lastCmd.param) && (chnState.lastCmd.volcmd & 8)) + if ((command == chnState.command) && (param == chnState.param) && (chnState.valid & 8)) { b &= ~8; b |= 0x80; } else { - chnState.lastCmd.command = command; - chnState.lastCmd.param = param; - chnState.lastCmd.volcmd |= 8; + chnState.command = command; + chnState.param = param; + chnState.valid |= 8; } } if (b != chnState.mask) @@ -1861,7 +1899,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c } else { #ifdef MPT_EXTERNAL_SAMPLES - const std::string filenameU8 = GetSamplePath(smp).AbsolutePathToRelative(filename.GetPath()).ToUTF8(); + const std::string filenameU8 = mpt::AbsolutePathToRelative(GetSamplePath(smp), filename.GetDirectoryWithDrive()).ToUTF8(); const size_t strSize = filenameU8.size(); size_t intBytes = 0; if(mpt::IO::WriteVarInt(f, strSize, &intBytes)) @@ -1922,7 +1960,7 @@ bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool c ssb.FinishWrite(); - if(ssb.GetStatus() & srlztn::SNT_FAILURE) + if(ssb.HasFailed()) { AddToLog(LogError, U_("Error occurred in writing MPTM extensions.")); } @@ -2046,9 +2084,9 @@ uint32 CSoundFile::SaveMixPlugins(std::ostream *file, bool updatePlugData) #endif // MODPLUG_NO_FILESAVE -bool CSoundFile::LoadMixPlugins(FileReader &file) +std::pair CSoundFile::LoadMixPlugins(FileReader &file) { - bool isBeRoTracker = false; + bool hasPluginChunks = false, isBeRoTracker = false; while(file.CanRead(9)) { char code[4]; @@ -2061,7 +2099,7 @@ bool CSoundFile::LoadMixPlugins(FileReader &file) || !file.CanRead(chunkSize)) { file.SkipBack(8); - return isBeRoTracker; + return std::make_pair(hasPluginChunks, isBeRoTracker); } FileReader chunk = file.ReadChunk(chunkSize); @@ -2072,6 +2110,7 @@ bool CSoundFile::LoadMixPlugins(FileReader &file) { chn.nMixPlugin = static_cast(chunk.ReadUint32LE()); } + hasPluginChunks = true; #ifndef NO_PLUGINS } // Plugin Data FX00, ... FX99, F100, ... F255 @@ -2086,6 +2125,7 @@ bool CSoundFile::LoadMixPlugins(FileReader &file) { ReadMixPluginChunk(chunk, m_MixPlugins[plug]); } + hasPluginChunks = true; #endif // NO_PLUGINS } else if(!memcmp(code, "MODU", 4)) { @@ -2093,7 +2133,7 @@ bool CSoundFile::LoadMixPlugins(FileReader &file) m_dwLastSavedWithVersion = Version(); // Reset MPT detection for old files that have a similar fingerprint } } - return isBeRoTracker; + return std::make_pair(hasPluginChunks, isBeRoTracker); } @@ -2131,9 +2171,7 @@ void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin) if(!memcmp(code, "DWRT", 4)) { - plugin.fDryRatio = std::clamp(dataChunk.ReadFloatLE(), 0.0f, 1.0f); - if(!std::isnormal(plugin.fDryRatio)) - plugin.fDryRatio = 0.0f; + plugin.fDryRatio = mpt::safe_clamp(dataChunk.ReadFloatLE(), 0.0f, 1.0f); } else if(!memcmp(code, "PROG", 4)) { plugin.defaultProgram = dataChunk.ReadUint32LE(); @@ -2339,7 +2377,6 @@ void CSoundFile::SaveExtendedSongProperties(std::ostream &f) const #undef WRITEMODULAR #undef WRITEMODULARHEADER - return; } #endif // MODPLUG_NO_FILESAVE @@ -2360,11 +2397,11 @@ void ReadFieldCast(FileReader &chunk, std::size_t size, T &field) } -void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool *pInterpretMptMade) +bool CSoundFile::LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool *pInterpretMptMade) { if(!file.ReadMagic("STPM")) // 'MPTS' { - return; + return false; } // Found MPTS, interpret the file MPT made. @@ -2525,6 +2562,8 @@ void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool ignoreChannel //m_ModFlags LimitMax(m_nDefaultRowsPerBeat, MAX_ROWS_PER_BEAT); LimitMax(m_nDefaultRowsPerMeasure, MAX_ROWS_PER_BEAT); + + return true; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp index e6555f686..fe131fe58 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_itp.cpp @@ -22,6 +22,8 @@ #include "../mptrack/Moddoc.h" #endif // MODPLUG_TRACKER #ifdef MPT_EXTERNAL_SAMPLES +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #endif // MPT_EXTERNAL_SAMPLES @@ -250,7 +252,7 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) #ifdef MODPLUG_TRACKER if(version <= 0x102) { - instrPaths[ins] = mpt::PathString::FromLocaleSilent(path); + instrPaths[ins] = mpt::PathString::FromLocale(path); } else #endif // MODPLUG_TRACKER { @@ -259,10 +261,10 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) #ifdef MODPLUG_TRACKER if(const auto fileName = file.GetOptionalFileName(); fileName.has_value()) { - instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(fileName->GetPath()); + instrPaths[ins] = mpt::AbsolutePathToRelative(instrPaths[ins], fileName->GetDirectoryWithDrive()); } else if(GetpModDoc() != nullptr) { - instrPaths[ins] = instrPaths[ins].RelativePathToAbsolute(GetpModDoc()->GetPathNameMpt().GetPath()); + instrPaths[ins] = mpt::RelativePathToAbsolute(instrPaths[ins], GetpModDoc()->GetPathNameMpt().GetDirectoryWithDrive()); } #endif // MODPLUG_TRACKER } @@ -361,7 +363,7 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags) continue; #ifdef MPT_EXTERNAL_SAMPLES - InputFile f(instrPaths[ins], SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(instrPaths[ins], SettingCacheCompleteFileBeforeLoading()); FileReader instrFile = GetFileReader(f); if(!ReadInstrumentFromFile(ins + 1, instrFile, true)) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mdl.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mdl.cpp index 243756201..0338c5d14 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mdl.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mdl.cpp @@ -155,7 +155,7 @@ enum static constexpr VibratoType MDLVibratoType[] = { VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_SINE }; -static constexpr ModCommand::COMMAND MDLEffTrans[] = +static constexpr EffectCommand MDLEffTrans[] = { /* 0 */ CMD_NONE, /* 1st column only */ @@ -186,15 +186,13 @@ static constexpr ModCommand::COMMAND MDLEffTrans[] = // receive an MDL effect, give back a 'normal' one. -static void ConvertMDLCommand(uint8 &cmd, uint8 ¶m) +static std::pair ConvertMDLCommand(const uint8 command, uint8 param) { - if(cmd >= std::size(MDLEffTrans)) - return; + if(command >= std::size(MDLEffTrans)) + return {CMD_NONE, uint8(0)}; - uint8 origCmd = cmd; - cmd = MDLEffTrans[cmd]; - - switch(origCmd) + EffectCommand cmd = MDLEffTrans[command]; + switch(command) { #ifdef MODPLUG_TRACKER case 0x07: // Tempo @@ -298,18 +296,19 @@ static void ConvertMDLCommand(uint8 &cmd, uint8 ¶m) } break; } + return {cmd, param}; } // Returns true if command was lost -static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint8 p1, uint8 p2) +static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 cmd1, uint8 cmd2, uint8 param1, uint8 param2) { // Map second effect values 1-6 to effects G-L - if(e2 >= 1 && e2 <= 6) - e2 += 15; + if(cmd2 >= 1 && cmd2 <= 6) + cmd2 += 15; - ConvertMDLCommand(e1, p1); - ConvertMDLCommand(e2, p2); + auto [e1, p1] = ConvertMDLCommand(cmd1, param1); + auto [e2, p2] = ConvertMDLCommand(cmd2, param2); /* From the Digitrakker documentation: * EFx -xx - Set Sample Offset This is a double-command. It starts the @@ -325,7 +324,7 @@ static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint What's more is, if there's another effect in the second column, it's ALSO processed in addition to the offset, and the second data byte is shared between the two effects. */ uint32 offset = uint32_max; - uint8 otherCmd = CMD_NONE; + EffectCommand otherCmd = CMD_NONE; if(e1 == CMD_OFFSET) { // EFy -xx => offset yxx00 @@ -345,10 +344,8 @@ static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint if(offset != uint32_max && offset > 0xFF && ModCommand::GetEffectWeight(otherCmd) < ModCommand::GetEffectWeight(CMD_OFFSET)) { - m.command = CMD_OFFSET; - m.param = static_cast(offset & 0xFF); - m.volcmd = VOLCMD_OFFSET; - m.vol = static_cast(offset >> 8); + m.SetEffectCommand(CMD_OFFSET, static_cast(offset & 0xFF)); + m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return otherCmd != CMD_NONE || vol != 0; } @@ -361,38 +358,28 @@ static bool ImportMDLCommands(ModCommand &m, uint8 vol, uint8 e1, uint8 e2, uint // If we have Dxx + G00, or Dxx + H00, combine them into Lxx/Kxx. ModCommand::CombineEffects(e1, p1, e2, p2); - bool lostCommand = false; - // Try to fit the "best" effect into e2. - if(e1 == CMD_NONE) - { - // Easy - } else if(e2 == CMD_NONE) - { - // Almost as easy - e2 = e1; - p2 = p1; - } else if(e1 == e2 && e1 != CMD_S3MCMDEX) + // Try to preserve the "best" effect. + if(e1 == CMD_NONE || (e1 == e2 && e1 != CMD_S3MCMDEX)) { // Digitrakker processes the effects left-to-right, so if both effects are the same, the // second essentially overrides the first. + m.SetEffectCommand(e2, p2); + return false; + } else if(e2 == CMD_NONE) + { + m.SetEffectCommand(e1, p1); + return false; } else if(!vol) { - lostCommand |= (ModCommand::TwoRegularCommandsToMPT(e1, p1, e2, p2).first != CMD_NONE); - m.volcmd = e1; - m.vol = p1; + return m.FillInTwoCommands(e1, p1, e2, p2).first != CMD_NONE; } else { - if(ModCommand::GetEffectWeight((ModCommand::COMMAND)e1) > ModCommand::GetEffectWeight((ModCommand::COMMAND)e2)) - { - std::swap(e1, e2); - std::swap(p1, p2); - } - lostCommand = true; + if(ModCommand::GetEffectWeight(e1) > ModCommand::GetEffectWeight(e2)) + m.SetEffectCommand(e1, p1); + else + m.SetEffectCommand(e2, p2); + return true; } - - m.command = e2; - m.param = p2; - return lostCommand; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp index 1c4a30d89..25a70648a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_med.cpp @@ -392,9 +392,10 @@ static TEMPO MMDTempoToBPM(uint32 tempo, bool is8Ch, bool bpmMode, uint8 rowsPer } -static void ConvertMEDEffect(ModCommand &m, bool is8ch, bool bpmMode, uint8 rowsPerBeat, bool volHex) +static std::pair ConvertMEDEffect(ModCommand &m, const uint8 command, const bool is8ch, const bool bpmMode, const uint8 rowsPerBeat, const bool volHex) { - switch(m.command) + m.command = CMD_NONE; + switch(command) { case 0x04: // Vibrato (twice as deep as in ProTracker) m.command = CMD_VIBRATO; @@ -431,15 +432,27 @@ static void ConvertMEDEffect(ModCommand &m, bool is8ch, bool bpmMode, uint8 rows } else if(m.param <= 0xF0) { m.command = CMD_TEMPO; - if(m.param < 0x03) // This appears to be a bug in OctaMED which is not emulated in MED Soundstudio on Windows. + if(m.param < 0x03) + { + // This appears to be a bug in OctaMED which is not emulated in MED Soundstudio on Windows. m.param = 0x70; - else - m.param = mpt::saturate_round(MMDTempoToBPM(m.param, is8ch, bpmMode, rowsPerBeat).ToDouble()); + } else + { + uint16 tempo = mpt::saturate_round(MMDTempoToBPM(m.param, is8ch, bpmMode, rowsPerBeat).ToDouble()); + if(tempo <= Util::MaxValueOfType(m.param)) + { + m.param = static_cast(tempo); + } else + { + m.param = static_cast(tempo >> 8); + return {CMD_XPARAM, static_cast(tempo & 0xFF)}; + } + } #ifdef MODPLUG_TRACKER if(m.param < 0x20) m.param = 0x20; #endif // MODPLUG_TRACKER - } else switch(m.command) + } else switch(command) { case 0xF1: // Play note twice m.command = CMD_MODCMDEX; @@ -580,12 +593,13 @@ static void ConvertMEDEffect(ModCommand &m, bool is8ch, bool bpmMode, uint8 rows } break; default: - if(m.command < 0x10) - CSoundFile::ConvertModCommand(m); + if(command < 0x10) + CSoundFile::ConvertModCommand(m, command, m.param); else m.command = CMD_NONE; break; } + return std::make_pair(CMD_NONE, ModCommand::PARAM(0)); } #ifdef MPT_WITH_VST @@ -977,6 +991,11 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) ins.VolEnv.dwFlags.set(ENV_ENABLED); needInstruments = true; } + if(size > offsetof(MMDInstrExt, defaultPitch) && instrExt.defaultPitch != 0) + { + ins.NoteMap[24] = instrExt.defaultPitch + NOTE_MIN + 23; + needInstruments = true; + } if(size > offsetof(MMDInstrExt, volume)) ins.nGlobalVol = (instrExt.volume + 1u) / 2u; if(size > offsetof(MMDInstrExt, midiBank)) @@ -1068,7 +1087,7 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) uint32 preamp = 32; if(version < 2) { - if(songHeader.songLength > 256 || m_nChannels > 16) + if(songHeader.songLength > 256) return false; ReadOrderFromArray(order, songHeader.GetMMD0Song().sequence, songHeader.songLength); for(auto &ord : order) @@ -1077,7 +1096,9 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) } SetupMODPanning(true); - for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + // With MED SoundStudio 1.03 it's possible to create MMD1 files with more than 16 channels. + const CHANNELINDEX numChannelVols = std::min(m_nChannels, CHANNELINDEX(16)); + for(CHANNELINDEX chn = 0; chn < numChannelVols; chn++) { ChnSettings[chn].nVolume = std::min(songHeader.trackVol[chn], 64); } @@ -1294,19 +1315,19 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) CHANNELINDEX numTracks; ROWINDEX numRows; std::string patName; - int transpose; + int transpose = NOTE_MIN + 47 + songHeader.playTranspose; FileReader cmdExt; if(version < 1) { - transpose = NOTE_MIN + 47; MMD0PatternHeader patHeader; file.ReadStruct(patHeader); numTracks = patHeader.numTracks; numRows = patHeader.numRows + 1; } else { - transpose = NOTE_MIN + (version <= 2 ? 47 : 23) + songHeader.playTranspose; + if(version > 2) + transpose -= 24; MMD1PatternHeader patHeader; file.ReadStruct(patHeader); numTracks = patHeader.numTracks; @@ -1345,7 +1366,9 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) ModCommand *m = pattern.GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < numTracks; chn++, m++) { + const auto oldCmd = std::make_pair(m->command, m->param); int note = NOTE_NONE; + uint8 cmd = 0; if(version < 1) { const auto [noteInstr, instrCmd, param] = file.ReadArray(); @@ -1355,7 +1378,7 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) m->instr = (instrCmd >> 4) | ((noteInstr & 0x80) >> 3) | ((noteInstr & 0x40) >> 1); - m->command = instrCmd & 0x0F; + cmd = instrCmd & 0x0F; m->param = param; } else { @@ -1368,7 +1391,7 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) m->note = NOTE_NOTECUT; m->instr = instr & 0x3F; - m->command = command; + cmd = command; m->param = param1; } // Octave wrapping for 4-channel modules (TODO: this should not be set because of synth instruments) @@ -1377,7 +1400,23 @@ bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags) if(note >= NOTE_MIN && note <= NOTE_MAX) m->note = static_cast(note); - ConvertMEDEffect(*m, is8Ch, bpmMode, rowsPerBeat, volHex); + const auto extraCmd = ConvertMEDEffect(*m, cmd, is8Ch, bpmMode, rowsPerBeat, volHex); + + if(oldCmd.first == CMD_XPARAM) + { + // Restore X-Param if it was overwritten by an empty effect, or restrict to 8-bit value if this cell was overwritten with a "useful" effect + if(m->command == CMD_NONE) + m->SetEffectCommand(oldCmd); + else if(row > 0) + pattern.GetpModCommand(row - 1, chn)->param = Util::MaxValueOfType(m->param); + } + if(extraCmd.first != CMD_NONE) + { + if(row < (numRows - 1)) + pattern.GetpModCommand(row + 1, chn)->SetEffectCommand(extraCmd); + else + m->param = Util::MaxValueOfType(m->param); // No space :( + } } } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp index 48baa20f8..4bc875f9c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mid.cpp @@ -16,7 +16,10 @@ #include "../mptrack/TrackerSettings.h" #include "../mptrack/Moddoc.h" #include "../mptrack/Mptrack.h" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" +#include "mpt/fs/fs.hpp" #endif // MODPLUG_TRACKER OPENMPT_NAMESPACE_BEGIN @@ -445,7 +448,7 @@ struct MidiChannelState }; -static CHANNELINDEX FindUnusedChannel(uint8 midiCh, ModCommand::NOTE note, const std::vector &channels, bool monoMode, PatternRow patRow) +static CHANNELINDEX FindUnusedChannel(uint8 midiCh, ModCommand::NOTE note, const std::vector &channels, bool monoMode, mpt::span patRow) { for(size_t i = 0; i < channels.size(); i++) { @@ -503,7 +506,7 @@ static CHANNELINDEX FindUnusedChannel(uint8 midiCh, ModCommand::NOTE note, const } -static void MIDINoteOff(MidiChannelState &midiChn, std::vector &modChnStatus, uint8 note, uint8 delay, PatternRow patRow, std::bitset<16> drumChns) +static void MIDINoteOff(MidiChannelState &midiChn, std::vector &modChnStatus, uint8 note, uint8 delay, mpt::span patRow, std::bitset<16> drumChns) { CHANNELINDEX chn = midiChn.noteOn[note]; if(chn == CHANNELINDEX_INVALID) @@ -766,7 +769,7 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) } PATTERNINDEX pat = Order()[ord]; - PatternRow patRow = Patterns[pat].GetRow(row); + auto patRow = Patterns[pat].GetRow(row); uint8 data1 = track.ReadUint8(); if(data1 == 0xFF) @@ -1193,7 +1196,7 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) } } - m.command = static_cast(diff < 0 ? CMD_PORTAMENTODOWN : CMD_PORTAMENTOUP); + m.command = (diff < 0) ? CMD_PORTAMENTODOWN : CMD_PORTAMENTOUP; int32 absDiff = std::abs(diff); int32 realDiff = 0; if(absDiff < 16) @@ -1312,8 +1315,8 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) // Soundfont with same name as MIDI file for(const auto &ext : { P_(".sf2"), P_(".sf3"), P_(".sf4"), P_(".sbk"), P_(".dls") }) { - mpt::PathString filename = file.GetOptionalFileName().value_or(P_("")).ReplaceExt(ext); - if(filename.IsFile()) + mpt::PathString filename = file.GetOptionalFileName().value_or(P_("")).ReplaceExtension(ext); + if(mpt::native_fs{}.is_file(filename)) { embeddedBank = std::make_unique(); if(embeddedBank->Open(filename)) @@ -1346,7 +1349,7 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) if(CDLSBank::IsDLSBank(midiMapName)) { CDLSBank *dlsBank = nullptr; - if(cachedBank != nullptr && !mpt::PathString::CompareNoCase(cachedBankName, midiMapName)) + if(cachedBank != nullptr && !mpt::PathCompareNoCase(cachedBankName, midiMapName)) { dlsBank = cachedBank.get(); } else @@ -1362,13 +1365,13 @@ bool CSoundFile::ReadMID(FileReader &file, ModLoadingFlags loadFlags) } else { // Load from Instrument or Sample file - InputFile f(midiMapName, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(midiMapName, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { FileReader insFile = GetFileReader(f); if(ReadInstrumentFromFile(ins, insFile, false)) { - mpt::PathString filename = midiMapName.GetFullFileName(); + mpt::PathString filename = midiMapName.GetFilename(); pIns = Instruments[ins]; if(!pIns->filename[0]) pIns->filename = filename.ToLocale(); if(!pIns->name[0]) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp index 3b6c7407e..9fc5ad60e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mo3.cpp @@ -128,7 +128,7 @@ struct MO3Envelope int16le points[25][2]; // Convert MO3 envelope data into OpenMPT's internal envelope format - void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envShift) const + void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envShift, MODTYPE type) const { if(flags & envEnabled) mptEnv.dwFlags.set(ENV_ENABLED); if(flags & envSustain) mptEnv.dwFlags.set(ENV_SUSTAIN); @@ -137,7 +137,7 @@ struct MO3Envelope if(flags & envCarry) mptEnv.dwFlags.set(ENV_CARRY); mptEnv.resize(std::min(numNodes.get(), uint8(25))); mptEnv.nSustainStart = sustainStart; - mptEnv.nSustainEnd = sustainEnd; + mptEnv.nSustainEnd = (type == MOD_TYPE_XM) ? sustainStart : sustainEnd; mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; for(uint32 ev = 0; ev < mptEnv.size(); ev++) @@ -207,9 +207,9 @@ struct MO3Instrument mptIns.Keyboard[i] = sampleMap[i][1] + 1; } } - volEnv.ConvertToMPT(mptIns.VolEnv, 0); - panEnv.ConvertToMPT(mptIns.PanEnv, 0); - pitchEnv.ConvertToMPT(mptIns.PitchEnv, 5); + volEnv.ConvertToMPT(mptIns.VolEnv, 0, type); + panEnv.ConvertToMPT(mptIns.PanEnv, 0, type); + pitchEnv.ConvertToMPT(mptIns.PitchEnv, 5, type); mptIns.nFadeOut = fadeOut; if(midiChannel >= 128) @@ -656,13 +656,13 @@ static void UnpackMO3DeltaPredictionSample(FileReader &file, typename Properties static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: @@ -712,7 +712,7 @@ static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int wh static long VorbisfileFilereaderTell(void *datasource) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); FileReader::off_t result = file.GetPosition(); if(!mpt::in_range(result)) { @@ -1000,22 +1000,22 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) L= 06 00 22 x */ - static constexpr ModCommand::COMMAND effTrans[] = + static constexpr EffectCommand effTrans[] = { CMD_NONE, CMD_NONE, CMD_NONE, CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, CMD_TREMOR, - VOLCMD_VOLSLIDEUP, VOLCMD_FINEVOLUP, CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, - CMD_KEYOFF, CMD_SETENVPOSITION, CMD_PANNINGSLIDE, VOLCMD_PANSLIDELEFT, - CMD_RETRIG, CMD_XFINEPORTAUPDOWN, CMD_XFINEPORTAUPDOWN, VOLCMD_VIBRATOSPEED, - VOLCMD_VIBRATODEPTH, CMD_SPEED, CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN, + CMD_NONE,/*VolSlideUp*/ CMD_NONE,/*VolSlideDn*/ CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, + CMD_KEYOFF, CMD_SETENVPOSITION, CMD_PANNINGSLIDE, CMD_NONE,/*PanSlide*/ + CMD_RETRIG, CMD_XFINEPORTAUPDOWN, CMD_XFINEPORTAUPDOWN, CMD_NONE,/*VibSpeed*/ + CMD_NONE,/*VibDepth*/ CMD_SPEED, CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN, CMD_PORTAMENTOUP, CMD_TREMOR, CMD_RETRIG, CMD_FINEVIBRATO, CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_S3MCMDEX, CMD_TEMPO, CMD_GLOBALVOLSLIDE, CMD_PANBRELLO, CMD_MIDI, - VOLCMD_FINEVOLUP, VOLCMD_PORTADOWN, VOLCMD_PORTAUP, CMD_NONE, - VOLCMD_OFFSET, CMD_XPARAM, CMD_SMOOTHMIDI, CMD_DELAYCUT, + CMD_NONE,/*FineVolSld*/ CMD_NONE,/*PortaDown*/ CMD_NONE, /*PortaUp*/ CMD_NONE, + CMD_NONE,/*ITVolCol*/ CMD_XPARAM, CMD_SMOOTHMIDI, CMD_DELAYCUT, CMD_FINETUNE, CMD_FINETUNE_SMOOTH, }; @@ -1050,11 +1050,10 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) break; const uint8 numCommands = (b & 0x0F), rep = (b >> 4); - ModCommand m = ModCommand::Empty(); + ModCommand m; for(uint8 c = 0; c < numCommands; c++) { - uint8 cmd[2]; - track.ReadArray(cmd); + const auto cmd = track.ReadArray(); // Import pattern commands switch(cmd[0]) @@ -1081,8 +1080,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) // Tone portamento if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F)) { - m.volcmd = VOLCMD_TONEPORTAMENTO; - m.vol = cmd[1] >> 4; + m.SetVolumeCommand(VOLCMD_TONEPORTAMENTO, cmd[1] >> 4); break; } else if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_IT) { @@ -1090,27 +1088,23 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) { if(ImpulseTrackerPortaVolCmd[i] == cmd[1]) { - m.volcmd = VOLCMD_TONEPORTAMENTO; - m.vol = i; + m.SetVolumeCommand(VOLCMD_TONEPORTAMENTO, i); break; } } if(m.volcmd != VOLCMD_NONE) break; } - m.command = CMD_TONEPORTAMENTO; - m.param = cmd[1]; + m.SetEffectCommand(CMD_TONEPORTAMENTO, cmd[1]); break; case 0x07: // Vibrato if(m.volcmd == VOLCMD_NONE && cmd[1] < 10 && m_nType == MOD_TYPE_IT) { - m.volcmd = VOLCMD_VIBRATODEPTH; - m.vol = cmd[1]; + m.SetVolumeCommand(VOLCMD_VIBRATODEPTH, cmd[1]); } else { - m.command = CMD_VIBRATO; - m.param = cmd[1]; + m.SetEffectCommand(CMD_VIBRATO, cmd[1]); } break; case 0x0B: @@ -1119,88 +1113,65 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) { if(m_nType == MOD_TYPE_IT && cmd[1] == 0xFF) { - m.volcmd = VOLCMD_PANNING; - m.vol = 64; + m.SetVolumeCommand(VOLCMD_PANNING, 64); break; } if((m_nType == MOD_TYPE_IT && !(cmd[1] & 0x03)) || (m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F))) { - m.volcmd = VOLCMD_PANNING; - m.vol = cmd[1] / 4; + m.SetVolumeCommand(VOLCMD_PANNING, cmd[1] / 4); break; } } - m.command = CMD_PANNING8; - m.param = cmd[1]; + m.SetEffectCommand(CMD_PANNING8, cmd[1]); break; case 0x0F: // Volume if(m_nType != MOD_TYPE_MOD && m.volcmd == VOLCMD_NONE && cmd[1] <= 64) - { - m.volcmd = VOLCMD_VOLUME; - m.vol = cmd[1]; - } else - { - m.command = CMD_VOLUME; - m.param = cmd[1]; - } + m.SetVolumeCommand(VOLCMD_VOLUME, cmd[1]); + else + m.SetEffectCommand(CMD_VOLUME, cmd[1]); break; case 0x10: // Pattern break - m.command = CMD_PATTERNBREAK; - m.param = cmd[1]; + m.SetEffectCommand(CMD_PATTERNBREAK, cmd[1]); if(m_nType != MOD_TYPE_IT) m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; case 0x12: // Combined Tempo / Speed command - m.param = cmd[1]; - if(m.param < 0x20) - m.command = CMD_SPEED; - else - m.command = CMD_TEMPO; + m.SetEffectCommand((cmd[1] < 0x20) ? CMD_SPEED : CMD_TEMPO, cmd[1]); break; case 0x14: case 0x15: // XM volume column volume slides if(cmd[1] & 0xF0) { - m.volcmd = static_cast((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEUP : VOLCMD_FINEVOLUP); - m.vol = cmd[1] >> 4; + m.SetVolumeCommand((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEUP : VOLCMD_FINEVOLUP, cmd[1] >> 4); } else { - m.volcmd = static_cast((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEDOWN : VOLCMD_FINEVOLDOWN); - m.vol = cmd[1] & 0x0F; + m.SetVolumeCommand((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEDOWN : VOLCMD_FINEVOLDOWN, cmd[1] & 0x0F); } break; case 0x1B: // XM volume column panning slides if(cmd[1] & 0xF0) - { - m.volcmd = VOLCMD_PANSLIDERIGHT; - m.vol = cmd[1] >> 4; - } else - { - m.volcmd = VOLCMD_PANSLIDELEFT; - m.vol = cmd[1] & 0x0F; - } + m.SetVolumeCommand(VOLCMD_PANSLIDERIGHT, cmd[1] >> 4); + else + m.SetVolumeCommand(VOLCMD_PANSLIDELEFT, cmd[1] & 0x0F); break; case 0x1D: // XM extra fine porta up - m.command = CMD_XFINEPORTAUPDOWN; - m.param = 0x10 | cmd[1]; + m.SetEffectCommand(CMD_XFINEPORTAUPDOWN, 0x10 | cmd[1]); break; case 0x1E: // XM extra fine porta down - m.command = CMD_XFINEPORTAUPDOWN; - m.param = 0x20 | cmd[1]; + m.SetEffectCommand(CMD_XFINEPORTAUPDOWN, 0x20 | cmd[1]); break; case 0x1F: case 0x20: // XM volume column vibrato - m.volcmd = effTrans[cmd[0]]; - m.vol = cmd[1]; + m.SetVolumeCommand((cmd[0] == 0x1F) ? VOLCMD_VIBRATOSPEED: VOLCMD_VIBRATODEPTH, cmd[1]); break; case 0x22: // IT / S3M volume slide @@ -1227,23 +1198,16 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) case 0x31: case 0x32: // IT volume column portamento - m.volcmd = effTrans[cmd[0]]; - m.vol = cmd[1]; + m.SetVolumeCommand((cmd[0] == 0x31) ? VOLCMD_PORTADOWN: VOLCMD_PORTAUP, cmd[1]); break; case 0x34: // Any unrecognized IT volume command if(cmd[1] >= 223 && cmd[1] <= 232) - { - m.volcmd = VOLCMD_OFFSET; - m.vol = cmd[1] - 223; - } + m.SetVolumeCommand(VOLCMD_OFFSET, cmd[1] - 223); break; default: if(cmd[0] < std::size(effTrans)) - { - m.command = effTrans[cmd[0]]; - m.param = cmd[1]; - } + m.SetEffectCommand(effTrans[cmd[0]], cmd[1]); break; } } @@ -1636,7 +1600,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags) &VorbisfileFilereaderTell}; OggVorbis_File vf; MemsetZero(vf); - if(ov_open_callbacks(&sampleData, &vf, nullptr, 0, callbacks) == 0) + if(ov_open_callbacks(mpt::void_ptr(&sampleData), &vf, nullptr, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp index 39e6af966..d294f2a54 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mod.cpp @@ -21,30 +21,34 @@ #endif #ifdef MPT_EXTERNAL_SAMPLES // For loading external data in Startrekker files +#include "mpt/fs/fs.hpp" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptPathString.h" #endif // MPT_EXTERNAL_SAMPLES OPENMPT_NAMESPACE_BEGIN -void CSoundFile::ConvertModCommand(ModCommand &m) +void CSoundFile::ConvertModCommand(ModCommand &m, const uint8 command, const uint8 param) { - switch(m.command) + m.param = param; + switch(command) { - case 0x00: if(m.param) m.command = CMD_ARPEGGIO; break; - case 0x01: m.command = CMD_PORTAMENTOUP; break; - case 0x02: m.command = CMD_PORTAMENTODOWN; break; - case 0x03: m.command = CMD_TONEPORTAMENTO; break; - case 0x04: m.command = CMD_VIBRATO; break; - case 0x05: m.command = CMD_TONEPORTAVOL; break; - case 0x06: m.command = CMD_VIBRATOVOL; break; - case 0x07: m.command = CMD_TREMOLO; break; - case 0x08: m.command = CMD_PANNING8; break; - case 0x09: m.command = CMD_OFFSET; break; - case 0x0A: m.command = CMD_VOLUMESLIDE; break; - case 0x0B: m.command = CMD_POSITIONJUMP; break; - case 0x0C: m.command = CMD_VOLUME; break; - case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; - case 0x0E: m.command = CMD_MODCMDEX; break; + case 0x00: m.command = m.param ? CMD_ARPEGGIO : CMD_NONE; break; + case 0x01: m.command = CMD_PORTAMENTOUP; break; + case 0x02: m.command = CMD_PORTAMENTODOWN; break; + case 0x03: m.command = CMD_TONEPORTAMENTO; break; + case 0x04: m.command = CMD_VIBRATO; break; + case 0x05: m.command = CMD_TONEPORTAVOL; break; + case 0x06: m.command = CMD_VIBRATOVOL; break; + case 0x07: m.command = CMD_TREMOLO; break; + case 0x08: m.command = CMD_PANNING8; break; + case 0x09: m.command = CMD_OFFSET; break; + case 0x0A: m.command = CMD_VOLUMESLIDE; break; + case 0x0B: m.command = CMD_POSITIONJUMP; break; + case 0x0C: m.command = CMD_VOLUME; break; + case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; + case 0x0E: m.command = CMD_MODCMDEX; break; case 0x0F: // For a very long time, this code imported 0x20 as CMD_SPEED for MOD files, but this seems to contradict // pretty much the majority of other MOD player out there. @@ -57,29 +61,31 @@ void CSoundFile::ConvertModCommand(ModCommand &m) break; // Extension for XM extended effects - case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16 - case 'H' - 55: m.command = CMD_GLOBALVOLSLIDE; break; - case 'K' - 55: m.command = CMD_KEYOFF; break; - case 'L' - 55: m.command = CMD_SETENVPOSITION; break; - case 'P' - 55: m.command = CMD_PANNINGSLIDE; break; - case 'R' - 55: m.command = CMD_RETRIG; break; - case 'T' - 55: m.command = CMD_TREMOR; break; - case 'W' - 55: m.command = CMD_DUMMY; break; - case 'X' - 55: m.command = CMD_XFINEPORTAUPDOWN; break; - case 'Y' - 55: m.command = CMD_PANBRELLO; break; // 34 - case 'Z' - 55: m.command = CMD_MIDI; break; // 35 - case '\\' - 56: m.command = CMD_SMOOTHMIDI; break; // 36 - note: this is actually displayed as "-" in FT2, but seems to be doing nothing. - case 37: m.command = CMD_SMOOTHMIDI; break; // BeRoTracker uses this for smooth MIDI macros for some reason; in old OpenMPT versions this was reserved for the unimplemented "velocity" command - case '#' + 3: m.command = CMD_XPARAM; break; // 38 - default: m.command = CMD_NONE; + case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16 + case 'H' - 55: m.command = CMD_GLOBALVOLSLIDE; break; + case 'K' - 55: m.command = CMD_KEYOFF; break; + case 'L' - 55: m.command = CMD_SETENVPOSITION; break; + case 'P' - 55: m.command = CMD_PANNINGSLIDE; break; + case 'R' - 55: m.command = CMD_RETRIG; break; + case 'T' - 55: m.command = CMD_TREMOR; break; + case 'W' - 55: m.command = CMD_DUMMY; break; + case 'X' - 55: m.command = CMD_XFINEPORTAUPDOWN; break; + case 'Y' - 55: m.command = CMD_PANBRELLO; break; // 34 + case 'Z' - 55: m.command = CMD_MIDI; break; // 35 + case '\\' - 56: m.command = CMD_SMOOTHMIDI; break; // 36 - note: this is actually displayed as "-" in FT2, but seems to be doing nothing. + case 37: m.command = CMD_SMOOTHMIDI; break; // BeRoTracker uses this for smooth MIDI macros for some reason; in old OpenMPT versions this was reserved for the unimplemented "velocity" command + case '#' + 3: m.command = CMD_XPARAM; break; // 38 + default: m.command = CMD_NONE; } } #ifndef MODPLUG_NO_FILESAVE -void CSoundFile::ModSaveCommand(uint8 &command, uint8 ¶m, bool toXM, bool compatibilityExport) const +void CSoundFile::ModSaveCommand(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport) const { - switch(command) + command = 0; + param = source.param; + switch(source.command) { case CMD_NONE: command = param = 0; break; case CMD_ARPEGGIO: command = 0; break; @@ -171,25 +177,17 @@ void CSoundFile::ModSaveCommand(uint8 &command, uint8 ¶m, bool toXM, bool co command = '#' + 3; break; case CMD_S3MCMDEX: - switch(param & 0xF0) { - case 0x10: command = 0x0E; param = (param & 0x0F) | 0x30; break; - case 0x20: command = 0x0E; param = (param & 0x0F) | 0x50; break; - case 0x30: command = 0x0E; param = (param & 0x0F) | 0x40; break; - case 0x40: command = 0x0E; param = (param & 0x0F) | 0x70; break; - case 0x90: - if(compatibilityExport) - command = param = 0; - else - command = 'X' - 55; - break; - case 0xB0: command = 0x0E; param = (param & 0x0F) | 0x60; break; - case 0xA0: - case 0x50: - case 0x70: - case 0x60: command = param = 0; break; - default: command = 0x0E; break; + ModCommand mConv; + mConv.command = CMD_S3MCMDEX; + mConv.param = param; + mConv.ExtendedS3MtoMODEffect(); + ModSaveCommand(mConv, command, param, toXM, compatibilityExport); } + return; + case CMD_VOLUME8: + command = 0x0C; + param = static_cast((param + 3u) / 4u); break; default: command = param = 0; @@ -503,17 +501,33 @@ MPT_BINARY_STRUCT(PT36InfoChunk, 64) // Check if header magic equals a given string. -static bool IsMagic(const char *magic1, const char (&magic2)[5]) +static bool IsMagic(const char *magic1, const char (&magic2)[5]) noexcept { return std::memcmp(magic1, magic2, 4) == 0; } -static uint32 ReadSample(FileReader &file, MODSampleHeader &sampleHeader, ModSample &sample, mpt::charbuf &sampleName, bool is4Chn) +// For .DTM files from Apocalypse Abyss, where the first 2108 bytes are swapped +template +static T ReadAndSwap(TFileReader &file, const bool swapBytes) { - file.ReadStruct(sampleHeader); - sampleHeader.ConvertToMPT(sample, is4Chn); + T value; + if(file.Read(value) && swapBytes) + { + static_assert(sizeof(value) % 2u == 0); + auto byteView = mpt::as_raw_memory(value); + for(size_t i = 0; i < sizeof(T); i += 2) + { + std::swap(byteView[i], byteView[i + 1]); + } + } + return value; +} + +static uint32 ReadSample(const MODSampleHeader &sampleHeader, ModSample &sample, mpt::charbuf &sampleName, bool is4Chn) +{ + sampleHeader.ConvertToMPT(sample, is4Chn); sampleName = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name); // Get rid of weird characters in sample names. for(auto &c : sampleName.buf) @@ -642,13 +656,13 @@ static PATTERNINDEX GetNumPatterns(FileReader &file, ModSequence &Order, ORDERIN } -void CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m) +std::pair CSoundFile::ReadMODPatternEntry(FileReader &file, ModCommand &m) { - ReadMODPatternEntry(file.ReadArray(), m); + return ReadMODPatternEntry(file.ReadArray(), m); } -void CSoundFile::ReadMODPatternEntry(const std::array data, ModCommand &m) +std::pair CSoundFile::ReadMODPatternEntry(const std::array data, ModCommand &m) { // Read Period uint16 period = (((static_cast(data[0]) & 0x0F) << 8) | data[1]); @@ -679,8 +693,9 @@ void CSoundFile::ReadMODPatternEntry(const std::array data, ModCommand // Read Instrument m.instr = (data[2] >> 4) | (data[0] & 0x10); // Read Effect - m.command = data[2] & 0x0F; - m.param = data[3]; + m.command = CMD_NONE; + uint8 command = data[2] & 0x0F, param = data[3]; + return {command, param}; } @@ -694,6 +709,7 @@ struct MODMagicResult bool isStartrekker = false; bool isGenericMultiChannel = false; bool setMODVBlankTiming = false; + bool swapBytes = false; }; @@ -713,6 +729,7 @@ static bool CheckMODMagic(const char magic[4], MODMagicResult &result) { result.madeWithTracker = UL_("NoiseTracker"); result.isNoiseTracker = true; + result.setMODVBlankTiming = true; result.numChannels = 4; } else if(IsMagic(magic, "OKTA") || IsMagic(magic, "OCTA")) @@ -764,6 +781,11 @@ static bool CheckMODMagic(const char magic[4], MODMagicResult &result) // TDZx - TakeTracker (only TDZ1-TDZ3 should exist, but historically this code only supported 4-9 channels, so we keep those for the unlikely case that they were actually used for something) result.madeWithTracker = UL_("TakeTracker"); result.numChannels = magic[3] - '0'; + } else if(IsMagic(magic, ".M.K")) + { + // Hacked .DMF files from the game "Apocalypse Abyss" + result.numChannels = 4; + result.swapBytes = true; } else { return false; @@ -791,8 +813,7 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, co uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { - MODSampleHeader sampleHeader; - file.ReadStruct(sampleHeader); + MODSampleHeader sampleHeader = ReadAndSwap(file, modMagicResult.swapBytes); invalidBytes += sampleHeader.GetInvalidByteScore(); } if(invalidBytes > modMagicResult.invalidByteThreshold) @@ -813,8 +834,6 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) return false; } - InitializeGlobals(MOD_TYPE_MOD); - MODMagicResult modMagicResult; if(!CheckMODMagic(magic, modMagicResult) || modMagicResult.numChannels < 1 @@ -828,6 +847,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) return true; } + InitializeGlobals(MOD_TYPE_MOD); m_nChannels = modMagicResult.numChannels; bool isNoiseTracker = modMagicResult.isNoiseTracker; @@ -845,7 +865,6 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) // Startrekker 8 channel mod (needs special treatment, see below) const bool isFLT8 = isStartrekker && m_nChannels == 8; - // Only apply VBlank tests to M.K. (ProTracker) modules. const bool isMdKd = IsMagic(magic, "M.K."); // Adjust finetune values for modules saved with "His Master's Noisetracker" const bool isHMNT = IsMagic(magic, "M&K!") || IsMagic(magic, "FEST"); @@ -853,7 +872,8 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) // Reading song title file.Seek(0); - file.ReadString(m_songName, 20); + const auto songTitle = ReadAndSwap>(file, modMagicResult.swapBytes); + m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, songTitle); // Load Sample Headers SmpLength totalSampleLen = 0, wowSampleLen = 0; @@ -861,8 +881,8 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) uint32 invalidBytes = 0; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { - MODSampleHeader sampleHeader; - invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], m_nChannels == 4); + MODSampleHeader sampleHeader = ReadAndSwap(file, modMagicResult.swapBytes); + invalidBytes += ReadSample(sampleHeader, Samples[smp], m_szNames[smp], m_nChannels == 4); totalSampleLen += Samples[smp].nLength; if(isHMNT) @@ -893,8 +913,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) } // Read order information - MODFileHeader fileHeader; - file.ReadStruct(fileHeader); + const MODFileHeader fileHeader = ReadAndSwap(file, modMagicResult.swapBytes); file.Seek(modMagicResult.patternDataOffset); @@ -987,28 +1006,31 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) for(uint32 i = 0; i < 256; i++) { ModCommand m; - ReadMODPatternEntry(file, m); + const auto data = ReadAndSwap>(file, modMagicResult.swapBytes && pat == 0); + const auto [command, param] = ReadMODPatternEntry(data, m); if(!m.IsAmigaNote()) { isNoiseTracker = onlyAmigaNotes = false; } - if((m.command > 0x06 && m.command < 0x0A) - || (m.command == 0x0E && m.param > 0x01) - || (m.command == 0x0F && m.param > 0x1F) - || (m.command == 0x0D && ++patternBreaks > 1)) + if((command > 0x06 && command < 0x0A) + || (command == 0x0E && param > 0x01) + || (command == 0x0F && param > 0x1F) + || (command == 0x0D && ++patternBreaks > 1)) { isNoiseTracker = false; } - if(m.command == 0x08) + if(command == 0x08) { - maxPanning = std::max(maxPanning, m.param); - if(m.param < 0x80) + // Note: commands 880...88F are not considered for determining the panning style, as some modules use 7-bit panning but slightly overshoot: + // LOOKATME.MOD (MD5: dedcec1a2a135aeb1a311841cea2c60c, SHA1: 42bf92bf824ef9fb904704b8ee7e3a30df60038d) has an 88A command as its rightmost panning. + maxPanning = std::max(maxPanning, param); + if(param < 0x80) leftPanning = true; - else if(m.param > 0x8F && m.param != 0xA4) + else if(param > 0x8F && param != 0xA4) extendedPanning = true; - } else if(m.command == 0x0E && (m.param & 0xF0) == 0x80) + } else if(command == 0x0E && (param & 0xF0) == 0x80) { - maxPanning = std::max(maxPanning, static_cast((m.param & 0x0F) << 4)); + maxPanning = std::max(maxPanning, static_cast((param & 0x0F) << 4)); } } } @@ -1065,21 +1087,21 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { ModCommand &m = rowBase[chn]; - ReadMODPatternEntry(file, m); + const auto data = ReadAndSwap>(file, modMagicResult.swapBytes && pat == 0); + auto [command, param] = ReadMODPatternEntry(data, m); - if(m.command || m.param) + if(command || param) { - if(isStartrekker && m.command == 0x0E) + if(isStartrekker && command == 0x0E) { // No support for Startrekker assembly macros - m.command = CMD_NONE; - m.param = 0; - } else if(isStartrekker && m.command == 0x0F && m.param > 0x1F) + command = param = 0; + } else if(isStartrekker && command == 0x0F && param > 0x1F) { // Startrekker caps speed at 31 ticks per row - m.param = 0x1F; + param = 0x1F; } - ConvertModCommand(m); + ConvertModCommand(m, command, param); } // Perform some checks for our heuristics... @@ -1178,6 +1200,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) } // Reading samples + bool anyADPCM = false; if(loadFlags & loadSampleData) { file.Seek(modMagicResult.patternDataOffset + (readChannels * 64 * 4) * numPatterns); @@ -1188,9 +1211,13 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) { SampleIO::Encoding encoding = SampleIO::signedPCM; if(isInconexia) + { encoding = SampleIO::deltaPCM; - else if(file.ReadMagic("ADPCM")) + } else if(file.ReadMagic("ADPCM")) + { encoding = SampleIO::ADPCM; + anyADPCM = true; + } SampleIO sampleIO( SampleIO::_8bit, @@ -1221,7 +1248,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) if((loadFlags & loadSampleData) && isStartrekker) { #ifdef MPT_EXTERNAL_SAMPLES - std::optional amFile; + std::optional amFile; FileReader amData; if(file.GetOptionalFileName()) { @@ -1232,7 +1259,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) { mpt::PathString infoName = filename + ext; char stMagic[16]; - if(infoName.IsFile()) + if(mpt::native_fs{}.is_file(infoName)) { amFile.emplace(infoName, SettingCacheCompleteFileBeforeLoading()); if(amFile->IsValid() && (amData = GetFileReader(*amFile)).IsValid() && amData.ReadArray(stMagic)) @@ -1295,7 +1322,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) // In the pattern loader above, a second condition is used: Only tempo commands // below 100 BPM are taken into account. Furthermore, only M.K. (ProTracker) // modules are checked. - if(isMdKd && hasTempoCommands && !definitelyCIA) + if((isMdKd || IsMagic(magic, "M!K!")) && hasTempoCommands && !definitelyCIA) { const double songTime = GetLength(eNoAdjust).front().duration; if(songTime >= 480.0) @@ -1320,6 +1347,9 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags) m_modFormat.madeWithTracker = modMagicResult.madeWithTracker; m_modFormat.charset = mpt::Charset::Amiga_no_C1; + if(anyADPCM) + m_modFormat.madeWithTracker += U_(" (ADPCM packed)"); + return true; } @@ -1499,7 +1529,8 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { MODSampleHeader sampleHeader; - ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true); + file.ReadStruct(sampleHeader); + ReadSample(sampleHeader, Samples[smp], m_szNames[smp], true); totalSampleLen += Samples[smp].nLength; @@ -1697,17 +1728,17 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) uint8 autoSlide[4] = {0, 0, 0, 0}; for(ROWINDEX row = 0; row < 64; row++) { - PatternRow rowBase = Patterns[pat].GetpModCommand(row, 0); + auto rowBase = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; - ReadMODPatternEntry(patternData[row][chn], m); + auto [command, param] = ReadMODPatternEntry(patternData[row][chn], m); - if(!m.param || m.command == 0x0E) + if(!param || command == 0x0E) { autoSlide[chn] = 0; } - if(m.command || m.param) + if(command || param) { if(autoSlide[chn] != 0) { @@ -1721,39 +1752,40 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) m.vol = autoSlide[chn] & 0x0F; } } - if(m.command == 0x0D) + if(command == 0x0D) { if(minVersion != ST2_00) { // Dxy is volume slide in some Soundtracker versions, D00 is a pattern break in the latest versions. - m.command = 0x0A; + command = 0x0A; } else { - m.param = 0; + param = 0; } - } else if(m.command == 0x0C) + } else if(command == 0x0C) { // Volume is sent as-is to the chip, which ignores the highest bit. - m.param &= 0x7F; - } else if(m.command == 0x0E && (m.param > 0x01 || minVersion < ST_IX)) + param &= 0x7F; + } else if(command == 0x0E && (param > 0x01 || minVersion < ST_IX)) { // Import auto-slides as normal slides and fake them using volume column slides. - m.command = 0x0A; - autoSlide[chn] = m.param; - } else if(m.command == 0x0F) + command = 0x0A; + autoSlide[chn] = param; + } else if(command == 0x0F) { // Only the low nibble is evaluated in Soundtracker. - m.param &= 0x0F; + param &= 0x0F; } if(minVersion <= UST1_80) { // UST effects - switch(m.command) + m.param = param; + switch(command) { case 0: // jackdance.mod by Karsten Obarski has 0xy arpeggios... - if(m.param < 0x03) + if(param < 0x03) { m.command = CMD_NONE; } else @@ -1781,7 +1813,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) } } else { - ConvertModCommand(m); + ConvertModCommand(m, command, param); } } else { @@ -1931,7 +1963,8 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags) for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; - invalidBytes += ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true); + file.ReadStruct(sampleHeader); + invalidBytes += ReadSample(sampleHeader, Samples[smp], m_szNames[smp], true); } if(invalidBytes > MODSampleHeader::INVALID_BYTE_THRESHOLD) { @@ -1989,13 +2022,13 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags) for(ROWINDEX row = 0; row < 64; row++, m += 4) { - ReadMODPatternEntry(file, *m); + const auto [command, param] = ReadMODPatternEntry(file, *m); - if((m->command || m->param) - && !(m->command == 0x0E && m->param >= 0x10) // Exx only sets filter - && !(m->command >= 0x05 && m->command <= 0x09)) // These don't exist in ST2.6 + if((command || param) + && !(command == 0x0E && param >= 0x10) // Exx only sets filter + && !(command >= 0x05 && command <= 0x09)) // These don't exist in ST2.6 { - ConvertModCommand(*m); + ConvertModCommand(*m, command, param); } else { m->command = CMD_NONE; @@ -2188,13 +2221,18 @@ bool CSoundFile::ReadPT36(FileReader &file, ModLoadingFlags loadFlags) if(mpt::is_in_range(info.dateMonth, 1, 12) && mpt::is_in_range(info.dateDay, 1, 31) && mpt::is_in_range(info.dateHour, 0, 23) && mpt::is_in_range(info.dateMinute, 0, 59) && mpt::is_in_range(info.dateSecond, 0, 59)) { +#ifdef MODPLUG_TRACKER + m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; +#else + m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; +#endif FileHistory mptHistory; - mptHistory.loadDate.tm_year = info.dateYear; - mptHistory.loadDate.tm_mon = info.dateMonth - 1; - mptHistory.loadDate.tm_mday = info.dateDay; - mptHistory.loadDate.tm_hour = info.dateHour; - mptHistory.loadDate.tm_min = info.dateMinute; - mptHistory.loadDate.tm_sec = info.dateSecond; + mptHistory.loadDate.year = info.dateYear + 1900; + mptHistory.loadDate.month = info.dateMonth; + mptHistory.loadDate.day = info.dateDay; + mptHistory.loadDate.hours = info.dateHour; + mptHistory.loadDate.minutes = info.dateMinute; + mptHistory.loadDate.seconds = info.dateSecond; m_FileHistory.push_back(mptHistory); } } @@ -2343,15 +2381,15 @@ bool CSoundFile::SaveMod(std::ostream &f) const mpt::IO::Write(f, events); continue; } - PatternRow rowBase = Patterns[pat].GetRow(row); + const auto rowBase = Patterns[pat].GetRow(row); events.resize(writeChannels * 4); size_t eventByte = 0; for(CHANNELINDEX chn = 0; chn < writeChannels; chn++, eventByte += 4) { const ModCommand &m = rowBase[chn]; - uint8 command = m.command, param = m.param; - ModSaveCommand(command, param, false, true); + uint8 command = 0, param = 0; + ModSaveCommand(m, command, param, false, true); if(m.volcmd == VOLCMD_VOLUME && !command && !param) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mt2.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mt2.cpp index 6be8a513b..f4580713b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mt2.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mt2.cpp @@ -240,9 +240,7 @@ static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p) switch(p.fxcmd) { case 0x00: // FastTracker effect - m.command = p.fxparam2; - m.param = p.fxparam1; - CSoundFile::ConvertModCommand(m); + CSoundFile::ConvertModCommand(m, p.fxparam2, p.fxparam1); #ifdef MODPLUG_TRACKER m.Convert(MOD_TYPE_XM, MOD_TYPE_IT, *that); #else @@ -303,9 +301,7 @@ static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p) break; case 0x10: // Impulse Tracker effect - m.command = p.fxparam2; - m.param = p.fxparam1; - CSoundFile::S3MConvert(m, true); + CSoundFile::S3MConvert(m, p.fxparam2, p.fxparam1, true); if(m.command == CMD_TEMPO || m.command == CMD_SPEED) hasLegacyTempo = true; break; @@ -851,7 +847,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags) ModCommand *m = Patterns[writePat].GetpModCommand(row, m_nChannels - 8); for(CHANNELINDEX chn = 0; chn < 8; chn++, m++) { - *m = ModCommand::Empty(); + *m = ModCommand{}; if(row >= numRows) continue; @@ -1153,14 +1149,7 @@ bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags) mptSmp.filename = filename; #if defined(MPT_EXTERNAL_SAMPLES) - if(filename.length() >= 2 - && filename[0] != '\\' // Relative path on same drive - && filename[1] != ':') // Absolute path - { - // Relative path in same folder or sub folder - filename = ".\\" + filename; - } - SetSamplePath(i + 1, mpt::PathString::FromLocaleSilent(filename)); + SetSamplePath(i + 1, mpt::PathString::FromLocale(filename)); #elif !defined(LIBOPENMPT_BUILD_TEST) AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(i + 1, mpt::ToUnicode(GetCharsetFile(), filename))); #endif // MPT_EXTERNAL_SAMPLES diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mtm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mtm.cpp index dffadb9ba..55d408d17 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mtm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_mtm.cpp @@ -226,9 +226,7 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags) } if(cmd != 0 || param != 0) { - m->command = cmd; - m->param = param; - ConvertModCommand(*m); + ConvertModCommand(*m, cmd, param); #ifdef MODPLUG_TRACKER m->Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this); #endif @@ -254,13 +252,12 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags) { for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { - const auto rowBase = pattern.GetRow(row); bool hasSpeedOnRow = false, hasTempoOnRow = false; - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) + for(const ModCommand &m : pattern.GetRow(row)) { - if(rowBase[chn].command == CMD_SPEED) + if(m.command == CMD_SPEED) hasSpeedOnRow = true; - else if(rowBase[chn].command == CMD_TEMPO) + else if(m.command == CMD_TEMPO) hasTempoOnRow = true; } if(hasSpeedOnRow && hasTempoOnRow) @@ -279,12 +276,11 @@ bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags) { for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++) { - const auto rowBase = pattern.GetRow(row); - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++) + for(const ModCommand &m : pattern.GetRow(row)) { - if(rowBase[chn].command == CMD_SPEED || rowBase[chn].command == CMD_TEMPO) + if(m.command == CMD_SPEED || m.command == CMD_TEMPO) { - const bool writeTempo = rowBase[chn].command == CMD_SPEED; + const bool writeTempo = m.command == CMD_SPEED; pattern.WriteEffect(EffectWriter(writeTempo ? CMD_TEMPO : CMD_SPEED, writeTempo ? 125 : 6).Row(row)); break; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp index e0b33ee60..3db57f37b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_okt.cpp @@ -270,13 +270,11 @@ static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndF { ModCommand &other = rowCmd[chn + pairedChn[chn]]; // Try to preserve effect if there already was one - if(other.ConvertVolEffect(other.command, other.param, true)) + if(auto volCmd = other.ConvertToVolCommand(other.command, other.param, true); volCmd.first != VOLCMD_NONE) { - other.volcmd = other.command; - other.vol = other.param; + other.SetVolumeCommand(volCmd); } - other.command = m.command; - other.param = m.param; + other.SetEffectCommand(m); } break; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_plm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_plm.cpp index 62f5e0152..402022abf 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_plm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_plm.cpp @@ -230,7 +230,7 @@ bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags) const ROWINDEX rowsPerPat = 64; uint32 maxPos = 0; - static constexpr ModCommand::COMMAND effTrans[] = + static constexpr EffectCommand effTrans[] = { CMD_NONE, CMD_PORTAMENTOUP, diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_psm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_psm.cpp index 724b2e0d5..1b3a28258 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_psm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_psm.cpp @@ -2,7 +2,7 @@ * Load_psm.cpp * ------------ * Purpose: PSM16 and new PSM (ProTracker Studio / Epic MegaGames MASI) module loader - * Notes : This is partly based on http://www.shikadi.net/moddingwiki/ProTracker_Studio_Module + * Notes : This is partly based on https://moddingwiki.shikadi.net/wiki/ProTracker_Studio_Module * and partly reverse-engineered. Also thanks to the author of foo_dumb, the source code gave me a few clues. :) * Authors: Johannes Schultz * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. @@ -12,6 +12,8 @@ #include "stdafx.h" #include "Loaders.h" +#include "mpt/parse/parse.hpp" + #ifdef LIBOPENMPT_BUILD #define MPT_PSM_USE_REAL_SUBSONGS #endif @@ -173,6 +175,34 @@ struct PSMSubSong // For internal use (pattern conversion) , channelVolume(MAX_BASECHANNELS, 64) , channelSurround(MAX_BASECHANNELS, false) { } + + void SetPanning(CHANNELINDEX chn, uint8 type, int16 pan, bool &subsongPanningDiffers, std::vector &subsongs) + { + if(chn >= channelPanning.size()) + return; + switch(type) + { + case 0: // use panning + if(pan >= 0) + channelPanning[chn] = static_cast(pan ^ 128); + channelSurround[chn] = false; + break; + case 2: // surround + channelPanning[chn] = 128; + channelSurround[chn] = true; + break; + case 4: // center + channelPanning[chn] = 128; + channelSurround[chn] = false; + break; + } + if(!subsongPanningDiffers && !subsongs.empty()) + { + if(subsongs.back().channelPanning[chn] != channelPanning[chn] + || subsongs.back().channelSurround[chn] != channelSurround[chn]) + subsongPanningDiffers = true; + } + } }; @@ -200,7 +230,7 @@ static PATTERNINDEX ReadPSMPatternIndex(FileReader &file, bool &sinariaFormat) sinariaFormat = true; offset = 0; } - return ConvertStrTo(&patternID[offset]); + return mpt::parse(&patternID[offset]); } @@ -355,7 +385,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) { char cversion[7]; subChunk.ReadString(cversion, 6); - uint32 version = ConvertStrTo(cversion); + uint32 version = mpt::parse(cversion); // Sinaria song dates (just to go sure...) if(version == 800211 || version == 940902 || version == 940903 || version == 940906 || version == 940914 || version == 941213) @@ -388,7 +418,6 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) // In theory, a tempo item inbetween two order items should modify the // tempo when switching patterns. No module uses this feature in practice // though, so we can keep our loader simple. - // Unimplemented opcodes do nothing or freeze MASI. switch(opcode) { case 0x01: // Play order list item @@ -408,20 +437,32 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) } break; - // 0x02: Play Range - // 0x03: Jump Loop + case 0x02: // Play Range (xx from line yy to line zz). Three 16-bit parameters but it seems like the next opcode is parsed at the same position as the third parameter. + subChunk.Skip(4); + break; - case 0x04: // Jump Line (Restart position) + case 0x03: // Jump Loop (like Jump Line, but with a third, unknown byte following - nope, it does not appear to be a loop count) + case 0x04: // Jump Line (Restart position) { uint16 restartChunk = subChunk.ReadUint16LE(); if(restartChunk >= firstOrderChunk) - subsong.restartPos = static_cast(restartChunk - firstOrderChunk); // Close enough - we assume that order list is continuous (like in any real-world PSM) + subsong.restartPos = static_cast(restartChunk - firstOrderChunk); // Close enough - we assume that order list is continuous (like in any real-world PSM) Order().SetRestartPos(subsong.restartPos); + if(opcode == 0x03) + subChunk.Skip(1); } break; - // 0x05: Channel Flip - // 0x06: Transpose + case 0x05: // Channel Flip (changes channel type without changing pan position) + { + const auto [chn, type] = subChunk.ReadArray(); + subsong.SetPanning(chn, type, -1, subsongPanningDiffers, subsongs); + } + break; + + case 0x06: // Transpose (appears to be a no-op in MASI) + subChunk.Skip(1); + break; case 0x07: // Default Speed subsong.defaultSpeed = subChunk.ReadUint8(); @@ -452,33 +493,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) case 0x0D: // Channel panning table - can be set using CONVERT.EXE /E { const auto [chn, pan, type] = subChunk.ReadArray(); - if(chn < subsong.channelPanning.size()) - { - switch(type) - { - case 0: // use panning - subsong.channelPanning[chn] = pan ^ 128; - subsong.channelSurround[chn] = false; - break; - - case 2: // surround - subsong.channelPanning[chn] = 128; - subsong.channelSurround[chn] = true; - break; - - case 4: // center - subsong.channelPanning[chn] = 128; - subsong.channelSurround[chn] = false; - break; - - } - if(subsongPanningDiffers == false && subsongs.size() > 0) - { - if(subsongs.back().channelPanning[chn] != subsong.channelPanning[chn] - || subsongs.back().channelSurround[chn] != subsong.channelSurround[chn]) - subsongPanningDiffers = true; - } - } + subsong.SetPanning(chn, type, pan, subsongPanningDiffers, subsongs); } break; @@ -493,7 +508,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) break; default: - // Should never happen in "real" PSM files. But in this case, we have to quit as we don't know how big the chunk really is. + // Non-existent opcode, MASI would just freeze in this case. return false; } @@ -511,26 +526,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) break; const auto [type, pan] = subChunk.ReadArray(); - switch(type) - { - case 0: // use panning - subsong.channelPanning[chn] = pan ^ 128; - subsong.channelSurround[chn] = false; - break; - - case 2: // surround - subsong.channelPanning[chn] = 128; - subsong.channelSurround[chn] = true; - break; - - case 4: // center - subsong.channelPanning[chn] = 128; - subsong.channelSurround[chn] = false; - break; - - default: - break; - } + subsong.SetPanning(chn, type, pan, subsongPanningDiffers, subsongs); } break; @@ -663,7 +659,7 @@ bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags) // Read pattern. for(ROWINDEX row = 0; row < numRows; row++) { - PatternRow rowBase = Patterns[pat].GetRow(row); + auto rowBase = Patterns[pat].GetRow(row); uint16 rowSize = chunk.ReadUint16LE(); if(rowSize <= 2) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp index 0b4acfac9..2c7c2ebbe 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ptm.cpp @@ -249,17 +249,16 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags) if(b & 0x40) { const auto [command, param] = file.ReadArray(); - m.command = command; m.param = param; static constexpr EffectCommand effTrans[] = { CMD_GLOBALVOLUME, CMD_RETRIG, CMD_FINEVIBRATO, CMD_NOTESLIDEUP, CMD_NOTESLIDEDOWN, CMD_NOTESLIDEUPRETRIG, CMD_NOTESLIDEDOWNRETRIG, CMD_REVERSEOFFSET }; - if(m.command < 0x10) + if(command < 0x10) { // Beware: Effect letters are as in MOD, but portamento and volume slides behave like in S3M (i.e. fine slides share the same effect letters) - ConvertModCommand(m); - } else if(m.command < 0x10 + std::size(effTrans)) + ConvertModCommand(m, command, param); + } else if(command < 0x10 + std::size(effTrans)) { - m.command = effTrans[m.command - 0x10]; + m.command = effTrans[command - 0x10]; } else { m.command = CMD_NONE; @@ -274,6 +273,8 @@ bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags) case CMD_GLOBALVOLUME: m.param = std::min(m.param, uint8(0x40)) * 2u; break; + default: + break; } } if(b & 0x80) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp index 7186bad83..b2947afc8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_s3m.cpp @@ -27,9 +27,10 @@ OPENMPT_NAMESPACE_BEGIN -void CSoundFile::S3MConvert(ModCommand &m, bool fromIT) +void CSoundFile::S3MConvert(ModCommand &m, const uint8 command, const uint8 param, const bool fromIT) { - switch(m.command | 0x40) + m.param = param; + switch(command | 0x40) { case '@': m.command = (m.param ? CMD_DUMMY : CMD_NONE); break; case 'A': m.command = CMD_SPEED; break; @@ -73,10 +74,12 @@ void CSoundFile::S3MConvert(ModCommand &m, bool fromIT) #ifndef MODPLUG_NO_FILESAVE -void CSoundFile::S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool compatibilityExport) const +void CSoundFile::S3MSaveConvert(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toIT, const bool compatibilityExport) const { + command = 0; + param = source.param; const bool extendedIT = !compatibilityExport && toIT; - switch(command) + switch(source.command) { case CMD_DUMMY: command = (param ? '@' : 0); break; case CMD_SPEED: command = 'A'; break; @@ -135,13 +138,11 @@ void CSoundFile::S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool co break; case CMD_MODCMDEX: { - ModCommand m; - m.command = CMD_MODCMDEX; - m.param = param; - m.ExtendedMODtoS3MEffect(); - command = m.command; - param = m.param; - S3MSaveConvert(command, param, toIT, compatibilityExport); + ModCommand mConv; + mConv.command = CMD_MODCMDEX; + mConv.param = param; + mConv.ExtendedMODtoS3MEffect(); + S3MSaveConvert(mConv, command, param, toIT, compatibilityExport); } return; // Chars under 0x40 don't save properly, so map : to ] and # to [. @@ -321,6 +322,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) m_playBehaviour.set(kPeriodsAreHertz); if(schismDateVersion >= SchismVersionFromDate<2016, 05, 13>::date) m_playBehaviour.set(kITShortSampleRetrig); + m_playBehaviour.reset(kST3TonePortaWithAdlibNote); } nonCompatTracker = true; break; @@ -369,6 +371,11 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) m_playBehaviour.reset(kST3OffsetWithoutInstrument); m_playBehaviour.reset(kApplyUpperPeriodLimit); } + if (fileHeader.cwtv <= S3MFileHeader::trkST3_01) + { + // This broken behaviour is not present in ST3.01 + m_playBehaviour.reset(kST3TonePortaWithAdlibNote); + } if((fileHeader.cwtv & S3MFileHeader::trackerMask) > S3MFileHeader::trkScreamTracker) { @@ -497,7 +504,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) // Reading sample headers m_nSamples = std::min(static_cast(fileHeader.smpNum), static_cast(MAX_SAMPLES - 1)); - bool anySamples = false; + bool anySamples = false, anyADPCM = false; uint16 gusAddresses = 0; for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++) { @@ -516,19 +523,23 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) const uint32 sampleOffset = sampleHeader.GetSampleOffset(); if((loadFlags & loadSampleData) && sampleHeader.length != 0 && file.Seek(sampleOffset)) { - sampleHeader.GetSampleFormat((fileHeader.formatVersion == S3MFileHeader::oldVersion)).ReadSample(Samples[smp + 1], file); + SampleIO sampleIO = sampleHeader.GetSampleFormat((fileHeader.formatVersion == S3MFileHeader::oldVersion)); + sampleIO.ReadSample(Samples[smp + 1], file); anySamples = true; + if(sampleIO.GetEncoding() == SampleIO::ADPCM) + anyADPCM = true; } gusAddresses |= sampleHeader.gusAddress; } } + const bool useGUS = gusAddresses > 1; if(isST3 && anySamples && !gusAddresses && fileHeader.cwtv != S3MFileHeader::trkST3_00) { // All Scream Tracker versions except for some probably early revisions of Scream Tracker 3.00 write GUS addresses. GUS support might not have existed at that point (1992). // Hence if a file claims to be written with ST3 (but not ST3.00), but has no GUS addresses, we deduce that it must be written by some other software (e.g. some PSM -> S3M conversions) isST3 = false; - MPT_UNUSED(isST3); + MPT_UNUSED(isST3); m_modFormat.madeWithTracker = U_("Unknown"); } else if(isST3) { @@ -536,7 +547,6 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) // Re-saving that file in ST3 with the SoundBlaster driver loaded will reset the GUS address for all samples to 0 (unused) or 1 (used). // The first used sample will also have an address of 1 with the GUS driver. // So this is a safe way of telling if the file was last saved with the GUS driver loaded or not if there's more than one sample. - const bool useGUS = gusAddresses > 1; m_playBehaviour.set(kST3PortaSampleChange, useGUS); m_playBehaviour.set(kST3SampleSwap, !useGUS); m_playBehaviour.set(kITShortSampleRetrig, !useGUS); // Only half the truth but close enough for now @@ -546,6 +556,9 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) m_nSamplePreAmp = 48; } + if(anyADPCM) + m_modFormat.madeWithTracker += U_(" (ADPCM packed)"); + // Try to find out if Zxx commands are supposed to be panning commands (PixPlay). // Actually I am only aware of one module that uses this panning style, namely "Crawling Despair" by $volkraq // and I have no idea what PixPlay is, so this code is solely based on the sample text of that module. @@ -580,7 +593,7 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) // Read pattern data ROWINDEX row = 0; - PatternRow rowBase = Patterns[pat].GetRow(0); + auto rowBase = Patterns[pat].GetRow(0); while(row < 64) { @@ -629,14 +642,22 @@ bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags) if(info & s3mEffectPresent) { const auto [command, param] = file.ReadArray(); - m.command = command; - m.param = param; - S3MConvert(m, false); + S3MConvert(m, command, param, false); if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xA0 && fileHeader.cwtv < S3MFileHeader::trkST3_20) { - // Convert old SAx panning to S8x (should only be found in PANIC.S3M by Purple Motion) - m.param = 0x80 | ((m.param & 0x0F) ^ 8); + // Convert the old messy SoundBlaster stereo control command (or an approximation of it, anyway) + const uint8 ctype = fileHeader.channels[channel] & 0x7F; + if(useGUS || ctype >= 0x10) + m.command = CMD_DUMMY; + else if(m.param == 0xA0 || m.param == 0xA2) // Normal panning + m.param = (ctype & 8) ? 0x8C : 0x83; + else if(m.param == 0xA1 || m.param == 0xA3) // Swap left / right channel + m.param = (ctype & 8) ? 0x83 : 0x8C; + else if(m.param <= 0xA7) // Center + m.param = 0x88; + else + m.command = CMD_DUMMY; } else if(m.command == CMD_MIDI) { // PixPlay panning test @@ -853,7 +874,7 @@ bool CSoundFile::SaveS3M(std::ostream &f) const continue; } - const PatternRow rowBase = Patterns[pat].GetRow(row); + const auto rowBase = Patterns[pat].GetRow(row); CHANNELINDEX writeChannels = std::min(CHANNELINDEX(32), GetNumChannels()); for(CHANNELINDEX chn = 0; chn < writeChannels; chn++) @@ -862,10 +883,6 @@ bool CSoundFile::SaveS3M(std::ostream &f) const uint8 info = static_cast(chn); uint8 note = m.note; - ModCommand::VOLCMD volcmd = m.volcmd; - uint8 vol = m.vol; - uint8 command = m.command; - uint8 param = m.param; if(note != NOTE_NONE || m.instr != 0) { @@ -898,25 +915,24 @@ bool CSoundFile::SaveS3M(std::ostream &f) const } } - if(command == CMD_VOLUME) - { - command = CMD_NONE; - volcmd = VOLCMD_VOLUME; - vol = std::min(param, uint8(64)); - } - - if(volcmd == VOLCMD_VOLUME) + uint8 vol = std::min(m.vol, ModCommand::VOL(64)); + if(m.volcmd == VOLCMD_VOLUME) { info |= s3mVolumePresent; - } else if(volcmd == VOLCMD_PANNING) + } else if(m.volcmd == VOLCMD_PANNING) { info |= s3mVolumePresent; vol |= 0x80; + } else if(m.command == CMD_VOLUME) + { + info |= s3mVolumePresent; + vol = std::min(m.param, ModCommand::PARAM(64)); } - if(command != CMD_NONE) + uint8 command = 0, param = 0; + if(m.command != CMD_NONE && m.command != CMD_VOLUME) { - S3MSaveConvert(command, param, false, true); + S3MSaveConvert(m, command, param, false, true); if(command || param) { info |= s3mEffectPresent; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp index 8afe67787..bd4c8b12f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_sfx.cpp @@ -17,18 +17,44 @@ OPENMPT_NAMESPACE_BEGIN // File Header struct SFXFileHeader { - uint8be numOrders; - uint8be restartPos; - uint8be orderList[128]; + char magic[4]; + uint16be speed; + char unknown[14]; // Just NUL bytes most of the time, sometimes appears to contain leftovers from other data structures + + bool IsValid(const uint8 expectedNumSamples) const noexcept + { + if(expectedNumSamples == 15 && memcmp(magic, "SONG", 4)) + return false; + if(expectedNumSamples == 31 && memcmp(magic, "SO31", 4)) + return false; + return speed >= 178; + } }; -MPT_BINARY_STRUCT(SFXFileHeader, 130) +MPT_BINARY_STRUCT(SFXFileHeader, 20) + + +// Order List +struct SFXOrderHeader +{ + uint8 numOrders; + uint8 restartPos; + uint8 orderList[128]; + + bool IsValid() const noexcept + { + return numOrders <= 128; + } +}; + +MPT_BINARY_STRUCT(SFXOrderHeader, 130) + // Sample Header struct SFXSampleHeader { char name[22]; - char dummy[2]; // Supposedly sample length, but almost always incorrect + char dummy[2]; // Supposedly sample length, but almost always incorrect uint8be finetune; uint8be volume; uint16be loopStart; @@ -96,79 +122,42 @@ static uint8 ClampSlideParam(uint8 value, uint8 lowNote, uint8 highNote) } -static bool ValidateHeader(const SFXFileHeader &fileHeader) -{ - if(fileHeader.numOrders > 128) - { - return false; - } - return true; -} - - CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize) { SAMPLEINDEX numSamples = 0; - if(numSamples == 0) + SFXFileHeader fileHeader; + + if(!file.LengthIsAtLeast(0x3C + sizeof(SFXFileHeader))) + return ProbeWantMoreData; + if(file.Seek(0x3C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(15)) { - file.Rewind(); - if(!file.CanRead(0x40)) - { - return ProbeWantMoreData; - } - if(file.Seek(0x3c) && file.ReadMagic("SONG")) - { - numSamples = 15; - } - } - if(numSamples == 0) + numSamples = 15; + } else { - file.Rewind(); - if(!file.CanRead(0x80)) - { + if(!file.LengthIsAtLeast(0x7C + sizeof(SFXFileHeader))) return ProbeWantMoreData; - } - if(file.Seek(0x7C) && file.ReadMagic("SO31")) - { + if(file.Seek(0x7C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(31)) numSamples = 31; - } - } - if(numSamples == 0) - { - return ProbeFailure; + else + return ProbeFailure; } + file.Rewind(); for(SAMPLEINDEX smp = 0; smp < numSamples; smp++) { if(file.ReadUint32BE() > 131072) - { return ProbeFailure; - } } - file.Skip(4); - if(!file.CanRead(2)) - { + + if(!file.Skip(sizeof(SFXFileHeader) + sizeof(SFXSampleHeader) * numSamples)) return ProbeWantMoreData; - } - uint16 speed = file.ReadUint16BE(); - if(speed < 178) - { + + SFXOrderHeader orderHeader; + if(!file.ReadStruct(orderHeader)) + return ProbeWantMoreData; + if(!orderHeader.IsValid()) return ProbeFailure; - } - if(!file.CanRead(sizeof(SFXSampleHeader) * numSamples)) - { - return ProbeWantMoreData; - } - file.Skip(sizeof(SFXSampleHeader) * numSamples); - SFXFileHeader fileHeader; - if(!file.ReadStruct(fileHeader)) - { - return ProbeWantMoreData; - } - if(!ValidateHeader(fileHeader)) - { - return ProbeFailure; - } + MPT_UNREFERENCED_PARAMETER(pfilesize); return ProbeSuccess; } @@ -176,11 +165,12 @@ CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, co bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) { - if(file.Seek(0x3C), file.ReadMagic("SONG")) + SFXFileHeader fileHeader; + if(file.Seek(0x3C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(15)) { InitializeGlobals(MOD_TYPE_SFX); m_nSamples = 15; - } else if(file.Seek(0x7C), file.ReadMagic("SO31")) + } else if(file.Seek(0x7C) && file.ReadStruct(fileHeader) && fileHeader.IsValid(31)) { InitializeGlobals(MOD_TYPE_SFX); m_nSamples = 31; @@ -198,9 +188,11 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) if(sampleLen[smp] > 131072) return false; } + file.Skip(sizeof(SFXFileHeader)); m_nChannels = 4; m_nInstruments = 0; + m_nDefaultTempo = TEMPO((14565.0 * 122.0) / fileHeader.speed); m_nDefaultSpeed = 6; m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; @@ -209,14 +201,6 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) // Setup channel pan positions and volume SetupMODPanning(true); - file.Skip(4); - uint16 speed = file.ReadUint16BE(); - if(speed < 178) - return false; - m_nDefaultTempo = TEMPO((14565.0 * 122.0) / speed); - - file.Skip(14); - uint32 invalidChars = 0; for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) { @@ -244,32 +228,24 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) // but it should not do that for FFFE (STP) notes - as a consequence, they turn into pattern breaks (FFFC). const bool fixPatternBreaks = (m_szNames[1] == "BASSE2.AMI") || (m_szNames[1] == "PRA1.AMI"); - SFXFileHeader fileHeader; - if(!file.ReadStruct(fileHeader)) - { + SFXOrderHeader orderHeader; + if(!file.ReadStruct(orderHeader) || !orderHeader.IsValid()) return false; - } - if(!ValidateHeader(fileHeader)) - { - return false; - } - if(loadFlags == onlyVerifyHeader) - { + else if(loadFlags == onlyVerifyHeader) return true; - } PATTERNINDEX numPatterns = 0; - for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++) + for(ORDERINDEX ord = 0; ord < orderHeader.numOrders; ord++) { - numPatterns = std::max(numPatterns, static_cast(fileHeader.orderList[ord] + 1)); + numPatterns = std::max(numPatterns, static_cast(orderHeader.orderList[ord] + 1)); } - if(fileHeader.restartPos < fileHeader.numOrders) - Order().SetRestartPos(fileHeader.restartPos); + if(orderHeader.restartPos < orderHeader.numOrders) + Order().SetRestartPos(orderHeader.restartPos); else Order().SetRestartPos(0); - ReadOrderFromArray(Order(), fileHeader.orderList, fileHeader.numOrders); + ReadOrderFromArray(Order(), orderHeader.orderList, orderHeader.numOrders); // SFX v2 / MMS modules have 4 extra bytes here for some reason if(m_nSamples == 31) @@ -293,7 +269,7 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) for(ROWINDEX row = 0; row < 64; row++) { - PatternRow rowBase = Patterns[pat].GetpModCommand(row, 0); + auto rowBase = Patterns[pat].GetRow(row); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; @@ -320,7 +296,7 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) } } - ReadMODPatternEntry(data, m); + const auto [command, param] = ReadMODPatternEntry(data, m); if(m.note != NOTE_NONE) { lastNote[chn] = m.note; @@ -331,9 +307,10 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) } } - if(m.command || m.param) + if(command || param) { - switch(m.command) + m.param = param; + switch(command) { case 0x1: // Arpeggio m.command = CMD_ARPEGGIO; @@ -350,7 +327,7 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) m.param &= 0x0F; } else { - m.command = m.param = 0; + m.command = CMD_NONE; } break; @@ -358,41 +335,37 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) // Give precedence to 7xy/8xy slides if(slideRate[chn]) { - m.command = m.param = 0; + m.command = CMD_NONE; break; } - m.command = CMD_MODCMDEX; - m.param = 0; + m.SetEffectCommand(CMD_MODCMDEX, 0x00); break; case 0x4: // Disable LED filter // Give precedence to 7xy/8xy slides if(slideRate[chn]) { - m.command = m.param = 0; + m.command = CMD_NONE; break; } - m.command = CMD_MODCMDEX; - m.param = 1; + m.SetEffectCommand(CMD_MODCMDEX, 0x01); break; case 0x5: // Increase volume if(m.instr) { - m.command = CMD_VOLUME; - m.param = std::min(ModCommand::PARAM(0x3F), static_cast((Samples[m.instr].nVolume / 4u) + m.param)); + m.SetEffectCommand(CMD_VOLUME, std::min(ModCommand::PARAM(0x3F), static_cast((Samples[m.instr].nVolume / 4u) + m.param))); // Give precedence to 7xy/8xy slides (and move this to the volume column) if(slideRate[chn]) { - m.volcmd = VOLCMD_VOLUME; - m.vol = m.param; - m.command = m.param = 0; + m.SetVolumeCommand(VOLCMD_VOLUME, m.param); + m.command = CMD_NONE; break; } } else { - m.command = m.param = 0; + m.command = CMD_NONE; } break; @@ -408,31 +381,28 @@ bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags) // Give precedence to 7xy/8xy slides (and move this to the volume column) if(slideRate[chn]) { - m.volcmd = VOLCMD_VOLUME; - m.vol = m.param; - m.command = m.param = 0; + m.SetVolumeCommand(VOLCMD_VOLUME, m.param); + m.command = CMD_NONE; break; } } else { - m.command = m.param = 0; + m.command = CMD_NONE; } break; case 0x7: // 7xy: Slide down x semitones at speed y slideTo[chn] = lastNote[chn] - (m.param >> 4); - m.command = CMD_PORTAMENTODOWN; slideRate[chn] = m.param & 0xF; - m.param = ClampSlideParam(slideRate[chn], slideTo[chn], lastNote[chn]); + m.SetEffectCommand(CMD_PORTAMENTODOWN, ClampSlideParam(slideRate[chn], slideTo[chn], lastNote[chn])); break; case 0x8: // 8xy: Slide up x semitones at speed y slideTo[chn] = lastNote[chn] + (m.param >> 4); - m.command = CMD_PORTAMENTOUP; slideRate[chn] = m.param & 0xF; - m.param = ClampSlideParam(slideRate[chn], lastNote[chn], slideTo[chn]); + m.SetEffectCommand(CMD_PORTAMENTOUP, ClampSlideParam(slideRate[chn], lastNote[chn], slideTo[chn])); break; case 0x9: // 9xy: Auto slide diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp index 0c040da85..da2cee9c5 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stm.cpp @@ -121,7 +121,7 @@ static bool ValidateSTMOrderList(ModSequence &order) } -static void ConvertSTMCommand(ModCommand &m, const ROWINDEX row, const uint8 fileVerMinor, uint8 &newTempo, ORDERINDEX &breakPos, ROWINDEX &breakRow) +static void ConvertSTMCommand(ModCommand &m, const uint8 command, const ROWINDEX row, const uint8 fileVerMinor, uint8 &newTempo, ORDERINDEX &breakPos, ROWINDEX &breakRow) { static constexpr EffectCommand stmEffects[] = { @@ -132,7 +132,7 @@ static void ConvertSTMCommand(ModCommand &m, const ROWINDEX row, const uint8 fil // KLMNO can be entered in the editor but don't do anything }; - m.command = stmEffects[m.command & 0x0F]; + m.command = stmEffects[command & 0x0F]; switch(m.command) { @@ -191,7 +191,7 @@ static void ConvertSTMCommand(ModCommand &m, const ROWINDEX row, const uint8 fil newTempo = m.param; m.param >>= 4; #else - MPT_UNUSED_VARIABLE(newTempo); + MPT_UNREFERENCED_PARAMETER(newTempo); #endif // MODPLUG_TRACKER break; @@ -346,9 +346,8 @@ bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags) m->vol = vol; } - m->command = volCmd & 0x0F; m->param = cmdInf; - ConvertSTMCommand(*m, row, fileHeader.verMinor, newTempo, breakPos, breakRow); + ConvertSTMCommand(*m, volCmd & 0x0F, row, fileHeader.verMinor, newTempo, breakPos, breakRow); } if(newTempo != 0) { @@ -594,9 +593,8 @@ bool CSoundFile::ReadSTX(FileReader &file, ModLoadingFlags loadFlags) if(info & s3mEffectPresent) { const auto [command, param] = file.ReadArray(); - m.command = command; m.param = param; - ConvertSTMCommand(m, row, 0xFF, newTempo, breakPos, breakRow); + ConvertSTMCommand(m, command, row, 0xFF, newTempo, breakPos, breakRow); } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stp.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stp.cpp index 61c3886e5..c9ee22569 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stp.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_stp.cpp @@ -96,7 +96,7 @@ struct STPLoopInfo SAMPLEINDEX nonLooped; }; -typedef std::vector STPLoopList; +using STPLoopList = std::vector; static TEMPO ConvertTempo(uint16 ciaSpeed) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp index 25084acf2..00a541b87 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_symmod.cpp @@ -846,7 +846,7 @@ static std::vector DecodeSymChunk(FileReader &file) // When using a fuzzer, we should not care if the decompressed buffer has the correct size. // This makes finding new interesting test cases much easier. if(remain) - std::vector{}.swap(data); + mpt::reconstruct(data); #endif } else { @@ -1135,7 +1135,7 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) chunk = FileReader(mpt::as_span(unpackedSample)); } - if(!ReadIFFSample(sample, chunk) + if(!ReadIFFSample(sample, chunk, false) && !ReadWAVSample(sample, chunk) && !ReadAIFFSample(sample, chunk) && !ReadRawSymSample(Samples[sample], chunk)) @@ -1233,7 +1233,7 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) auto filename = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, symInst.GetName())); if(file.GetOptionalFileName()) - filename = file.GetOptionalFileName()->GetPath() + filename.GetFullFileName(); + filename = file.GetOptionalFileName()->GetDirectoryWithDrive() + filename.GetFilename(); if(!LoadExternalSample(sample, filename)) AddToLog(LogError, MPT_UFORMAT("Unable to load sample {}: {}")(sample, filename)); @@ -1576,7 +1576,7 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) break; case SymEvent::AddVolume: - m.command = m.param = 0; + m.command = CMD_NONE; break; case SymEvent::Tremolo: { @@ -1616,7 +1616,7 @@ bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags) break; case SymEvent::AddPitch: // "The range (-128...127) is about 4 half notes." - m.command = m.param = 0; + m.command = CMD_NONE; break; case SymEvent::Vibrato: { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_uax.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_uax.cpp index 758eda91a..43f6d2060 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_uax.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_uax.cpp @@ -72,7 +72,7 @@ bool CSoundFile::ReadUAX(FileReader &file, ModLoadingFlags loadFlags) { InitializeChannels(); SetType(MOD_TYPE_MPT); - m_ContainerType = MOD_CONTAINERTYPE_UAX; + m_ContainerType = ModContainerType::UAX; m_nChannels = 4; Patterns.Insert(0, 64); Order().assign(1, 0); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp index f40ae6a56..0681631c0 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_ult.cpp @@ -95,10 +95,10 @@ much anywhere for that matter. I don't even think Ultra Tracker tries to convert them. */ -static void TranslateULTCommands(uint8 &effect, uint8 ¶m, uint8 version) +static std::pair TranslateULTCommands(const uint8 e, uint8 param, uint8 version) { - static constexpr uint8 ultEffTrans[] = + static constexpr EffectCommand ultEffTrans[] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, @@ -112,17 +112,15 @@ static void TranslateULTCommands(uint8 &effect, uint8 ¶m, uint8 version) CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PANNING8, - CMD_VOLUME, + CMD_VOLUME8, CMD_PATTERNBREAK, - CMD_NONE, // extended effects, processed separately + CMD_NONE, // extended effects, processed separately CMD_SPEED, }; + EffectCommand effect = ultEffTrans[e & 0x0F]; - uint8 e = effect & 0x0F; - effect = ultEffTrans[e]; - - switch(e) + switch(e & 0x0F) { case 0x00: if(!param || version < '3') @@ -152,9 +150,6 @@ static void TranslateULTCommands(uint8 &effect, uint8 ¶m, uint8 version) case 0x0B: param = (param & 0x0F) * 0x11; break; - case 0x0C: // volume - param /= 4u; - break; case 0x0D: // pattern break param = 10 * (param >> 4) + (param & 0x0F); break; @@ -198,6 +193,7 @@ static void TranslateULTCommands(uint8 &effect, uint8 ¶m, uint8 version) effect = CMD_TEMPO; break; } + return {effect, param}; } @@ -216,47 +212,35 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) const auto [instr, cmd, para1, para2] = file.ReadArray(); m.instr = instr; - uint8 cmd1 = cmd & 0x0F; - uint8 cmd2 = cmd >> 4; - uint8 param1 = para1; - uint8 param2 = para2; - TranslateULTCommands(cmd1, param1, version); - TranslateULTCommands(cmd2, param2, version); + auto [cmd1, param1] = TranslateULTCommands(cmd & 0x0F, para1, version); + auto [cmd2, param2]= TranslateULTCommands(cmd >> 4, para2, version); // sample offset -- this is even more special than digitrakker's if(cmd1 == CMD_OFFSET && cmd2 == CMD_OFFSET) { uint32 offset = ((param2 << 8) | param1) >> 6; - m.command = CMD_OFFSET; - m.param = static_cast(offset); + m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); if(offset > 0xFF) - { - m.volcmd = VOLCMD_OFFSET; - m.vol = static_cast(offset >> 8); - } + m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return repeat; } else if(cmd1 == CMD_OFFSET) { uint32 offset = param1 * 4; param1 = mpt::saturate_cast(offset); - if(offset > 0xFF && ModCommand::GetEffectWeight(cmd2) < ModCommand::GetEffectType(CMD_OFFSET)) + if(offset > 0xFF && ModCommand::GetEffectWeight(cmd2) < ModCommand::GetEffectWeight(CMD_OFFSET)) { - m.command = CMD_OFFSET; - m.param = static_cast(offset); - m.volcmd = VOLCMD_OFFSET; - m.vol = static_cast(offset >> 8); + m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); + m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return repeat; } } else if(cmd2 == CMD_OFFSET) { uint32 offset = param2 * 4; param2 = mpt::saturate_cast(offset); - if(offset > 0xFF && ModCommand::GetEffectWeight(cmd1) < ModCommand::GetEffectType(CMD_OFFSET)) + if(offset > 0xFF && ModCommand::GetEffectWeight(cmd1) < ModCommand::GetEffectWeight(CMD_OFFSET)) { - m.command = CMD_OFFSET; - m.param = static_cast(offset); - m.volcmd = VOLCMD_OFFSET; - m.vol = static_cast(offset >> 8); + m.SetEffectCommand(CMD_OFFSET, static_cast(offset)); + m.SetVolumeCommand(VOLCMD_OFFSET, static_cast(offset >> 8)); return repeat; } } else if(cmd1 == cmd2) @@ -273,12 +257,7 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) // Combine slide commands, if possible ModCommand::CombineEffects(cmd2, param2, cmd1, param1); - ModCommand::TwoRegularCommandsToMPT(cmd1, param1, cmd2, param2); - - m.volcmd = cmd1; - m.vol = param1; - m.command = cmd2; - m.param = param2; + m.FillInTwoCommands(cmd1, param1, cmd2, param2); return repeat; } @@ -287,12 +266,9 @@ static int ReadULTEvent(ModCommand &m, FileReader &file, uint8 version) // Functor for postfixing ULT patterns (this is easier than just remembering everything WHILE we're reading the pattern events) struct PostFixUltCommands { - PostFixUltCommands(CHANNELINDEX numChannels) + PostFixUltCommands(CHANNELINDEX channels) : numChannels{channels} { - this->numChannels = numChannels; - curChannel = 0; - writeT125 = false; - isPortaActive.resize(numChannels, false); + isPortaActive.resize(channels, false); } void operator()(ModCommand &m) @@ -344,21 +320,22 @@ struct PostFixUltCommands { writeT125 = false; } - curChannel = (curChannel + 1) % numChannels; + curChannel++; + if(curChannel >= numChannels) + curChannel = 0; } std::vector isPortaActive; - CHANNELINDEX numChannels, curChannel; - bool writeT125; + const CHANNELINDEX numChannels; + CHANNELINDEX curChannel = 0; + bool writeT125 = false; }; static bool ValidateHeader(const UltFileHeader &fileHeader) { - if(fileHeader.version < '1' - || fileHeader.version > '4' - || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature)) - ) + if(fileHeader.version < '1' || fileHeader.version > '4' + || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))) { return false; } @@ -482,7 +459,8 @@ bool CSoundFile::ReadULT(FileReader &file, ModLoadingFlags loadFlags) int repeat = ReadULTEvent(evnote, file, fileHeader.version); if(repeat + row > 64) repeat = 64 - row; - if(repeat == 0) break; + if(repeat == 0) + break; while(repeat--) { *note = evnote; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp index aeb5c3863..f84c44d93 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_wav.cpp @@ -37,8 +37,8 @@ static bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t cha return false; } - const std::byte *inBuf = file.GetRawData().data(); - CopySample(reinterpret_cast(sample.samplev()), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels, conv); + FileReader::PinnedView inData = file.GetPinnedView(file.BytesLeft()); + CopySample(sample.template sample(), sample.nLength, 1, inData.data() + offset, inData.size() - offset, numChannels, conv); return true; } @@ -80,7 +80,7 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) } InitializeGlobals(MOD_TYPE_MPT); - m_ContainerType = MOD_CONTAINERTYPE_WAV; + m_ContainerType = ModContainerType::WAV; m_nChannels = std::max(wavFile.GetNumChannels(), uint16(2)); Patterns.ResizeArray(2); if(!Patterns.Insert(0, 64) || !Patterns.Insert(1, 64)) @@ -122,17 +122,17 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) } // Setting up pattern - PatternRow pattern = Patterns[0].GetRow(0); - pattern[0].note = pattern[1].note = NOTE_MIDDLEC; - pattern[0].instr = pattern[1].instr = 1; + auto row = Patterns[0].GetRow(0); + row[0].note = row[1].note = NOTE_MIDDLEC; + row[0].instr = row[1].instr = 1; const FileReader sampleChunk = wavFile.GetSampleData(); // Read every channel into its own sample lot. for(SAMPLEINDEX channel = 0; channel < GetNumSamples(); channel++) { - pattern[channel].note = pattern[0].note; - pattern[channel].instr = static_cast(channel + 1); + row[channel].note = row[0].note; + row[channel].instr = static_cast(channel + 1); ModSample &sample = Samples[channel + 1]; sample.Initialize(); @@ -155,13 +155,13 @@ bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags) break; case 2: sample.nPan = (wavFile.GetNumChannels() == 3 ? 128u : 64u); - pattern[channel].command = CMD_S3MCMDEX; - pattern[channel].param = 0x91; + row[channel].command = CMD_S3MCMDEX; + row[channel].param = 0x91; break; case 3: sample.nPan = 192; - pattern[channel].command = CMD_S3MCMDEX; - pattern[channel].param = 0x91; + row[channel].command = CMD_S3MCMDEX; + row[channel].param = 0x91; break; default: sample.nPan = 128; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp index 06ab4e1c3..4afa17819 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xm.cpp @@ -68,13 +68,13 @@ OPENMPT_NAMESPACE_BEGIN static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: @@ -129,7 +129,7 @@ static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int wh static long VorbisfileFilereaderTell(void *datasource) { - FileReader &file = *reinterpret_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); FileReader::off_t result = file.GetPosition(); if(!mpt::in_range(result)) { @@ -289,7 +289,7 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo { uint8 info = patternChunk.ReadUint8(); - uint8 vol = 0; + uint8 vol = 0, command = 0; if(info & isPackByte) { // Interpret byte as flag set. @@ -303,7 +303,7 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo if(info & instrPresent) m.instr = patternChunk.ReadUint8(); if(info & volPresent) vol = patternChunk.ReadUint8(); - if(info & commandPresent) m.command = patternChunk.ReadUint8(); + if(info & commandPresent) command = patternChunk.ReadUint8(); if(info & paramPresent) m.param = patternChunk.ReadUint8(); if(m.note == 97) @@ -317,9 +317,9 @@ static void ReadXMPatterns(FileReader &file, const XMFileHeader &fileHeader, CSo m.note = NOTE_NONE; } - if(m.command | m.param) + if(command | m.param) { - CSoundFile::ConvertModCommand(m); + CSoundFile::ConvertModCommand(m, command, m.param); } else { m.command = CMD_NONE; @@ -453,7 +453,7 @@ static bool ReadSampleData(ModSample &sample, SampleIO sampleFlags, FileReader & }; OggVorbis_File vf; MemsetZero(vf); - if(ov_open_callbacks(&sampleData, &vf, nullptr, 0, callbacks) == 0) + if(ov_open_callbacks(mpt::void_ptr(&sampleData), &vf, nullptr, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples @@ -698,6 +698,7 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) uint8 sampleReserved = 0; int instrType = -1; bool unsupportedSamples = false; + bool anyADPCM = false; // Reading instruments for(INSTRUMENTINDEX instr = 1; instr <= m_nInstruments; instr++) @@ -824,6 +825,8 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) madeWith.set(verModPlug1_09); } } + if(sampleFlags.back().GetEncoding() == SampleIO::ADPCM) + anyADPCM = true; } // Read samples @@ -1038,6 +1041,9 @@ bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags) m_modFormat.type = U_("xm"); } + if(anyADPCM) + m_modFormat.madeWithTracker += U_(" (ADPCM packed)"); + return true; } @@ -1160,9 +1166,8 @@ bool CSoundFile::SaveXM(std::ostream &f, bool compatibilityExport) // Don't write more than 32 channels if(compatibilityExport && m_nChannels - ((j - 1) % m_nChannels) > 32) continue; - uint8 note = p->note; - uint8 command = p->command, param = p->param; - ModSaveCommand(command, param, true, compatibilityExport); + uint8 note = p->note, command = 0, param = 0; + ModSaveCommand(*p, command, param, true, compatibilityExport); if (note >= NOTE_MIN_SPECIAL) note = 97; else if ((note <= 12) || (note > 96+12)) note = 0; else @@ -1183,6 +1188,7 @@ bool CSoundFile::SaveXM(std::ostream &f, bool compatibilityExport) case VOLCMD_PANSLIDELEFT: vol = 0xD0 + (p->vol & 0x0F); break; case VOLCMD_PANSLIDERIGHT: vol = 0xE0 + (p->vol & 0x0F); break; case VOLCMD_TONEPORTAMENTO: vol = 0xF0 + (p->vol & 0x0F); break; + default: break; } // Those values are ignored in FT2. Don't save them, also to avoid possible problems with other trackers (or MPT itself) if(compatibilityExport && p->vol == 0) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xmf.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xmf.cpp new file mode 100644 index 000000000..b3a025565 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Load_xmf.cpp @@ -0,0 +1,224 @@ +/* + * Load_xmf.cpp + * ------------ + * Purpose: Module loader for music files from the DOS game "Imperium Galactica" + * Notes : This format has nothing to do with the XMF format by the MIDI foundation. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Loaders.h" +#include "mpt/endian/int24.hpp" + +OPENMPT_NAMESPACE_BEGIN + +struct XMFSampleHeader +{ + using uint24le = mpt::uint24le; + + enum SampleFlags : uint8 + { + smp16Bit = 0x04, + smpEnableLoop = 0x08, + smpBidiLoop = 0x10, + }; + + uint24le loopStart; + uint24le loopEnd; + uint24le dataStart; + uint24le dataEnd; + uint8 defaultVolume; + uint8 flags; + uint16le sampleRate; + + bool IsValid() const noexcept + { + if(flags & ~(smp16Bit | smpEnableLoop | smpBidiLoop)) + return false; + if((flags & (smpEnableLoop | smpBidiLoop)) == smpBidiLoop) + return false; + if(dataStart.get() > dataEnd.get()) + return false; + const uint32 length = dataEnd.get() - dataStart.get(); + if(length > 0 && sampleRate < 100) + return false; + if((flags & smp16Bit) && (length % 2u)) + return false; + if((flags & smpEnableLoop) && !loopEnd.get()) + return false; + if(loopEnd.get() != 0 && (loopEnd.get() > length || loopStart.get() >= loopEnd.get())) + return false; + return true; + } + + bool HasSampleData() const noexcept + { + return dataEnd.get() > dataStart.get(); + } + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = dataEnd.get() - dataStart.get(); + mptSmp.nLoopStart = loopStart.get(); + mptSmp.nLoopEnd = loopEnd.get(); + mptSmp.uFlags.set(CHN_LOOP, flags & smpEnableLoop); + mptSmp.uFlags.set(CHN_PINGPONGLOOP, flags & smpBidiLoop); + if(flags & smp16Bit) + { + mptSmp.uFlags.set(CHN_16BIT); + mptSmp.nLength /= 2; + } + mptSmp.nVolume = defaultVolume; + mptSmp.nC5Speed = sampleRate; + mptSmp.FrequencyToTranspose(); + } +}; + +MPT_BINARY_STRUCT(XMFSampleHeader, 16) + + +static bool TranslateXMFEffect(ModCommand &m, uint8 command, uint8 param) +{ + if(command == 0x0B && param < 0xFF) + { + param++; + } else if(command == 0x10) + { + command = 0x0E; + param = 0x80 | (param & 0x0F); + } else if(command > 0x10) + { + return false; + } + CSoundFile::ConvertModCommand(m, command, param); + if(m.command == CMD_VOLUME) + m.command = CMD_VOLUME8; + return true; +} + + +CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXMF(MemoryFileReader file, const uint64 *pfilesize) +{ + if(!file.CanRead(1)) + return ProbeWantMoreData; + if(file.ReadUint8() != 0x03) + return ProbeFailure; + + constexpr size_t probeHeaders = std::min(size_t(256), (ProbeRecommendedSize - 1) / sizeof(XMFSampleHeader)); + for(size_t sample = 0; sample < probeHeaders; sample++) + { + XMFSampleHeader sampleHeader; + if(!file.ReadStruct(sampleHeader)) + return ProbeWantMoreData; + if(!sampleHeader.IsValid()) + return ProbeFailure; + } + + MPT_UNREFERENCED_PARAMETER(pfilesize); + return ProbeSuccess; +} + + +bool CSoundFile::ReadXMF(FileReader &file, ModLoadingFlags loadFlags) +{ + file.Rewind(); + if(file.ReadUint8() != 0x03) + return false; + if(!file.CanRead(256 * sizeof(XMFSampleHeader) + 256 + 3)) + return false; + static_assert(MAX_SAMPLES > 256); + SAMPLEINDEX numSamples = 0; + for(SAMPLEINDEX smp = 1; smp <= 256; smp++) + { + XMFSampleHeader sampleHeader; + file.ReadStruct(sampleHeader); + if(!sampleHeader.IsValid()) + return false; + if(sampleHeader.HasSampleData()) + numSamples = smp; + } + if(!numSamples) + return false; + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_MOD); + m_SongFlags.set(SONG_IMPORTED); + m_nSamples = numSamples; + m_nSamplePreAmp = 192; + + file.Seek(1); + for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++) + { + XMFSampleHeader sampleHeader; + file.ReadStruct(sampleHeader); + sampleHeader.ConvertToMPT(Samples[smp]); + m_szNames[smp] = ""; + } + + file.Seek(1 + 256 * sizeof(XMFSampleHeader)); + ReadOrderFromFile(Order(), file, 256, 0xFF); + + const uint8 lastChannel = file.ReadUint8(); + if(lastChannel > 31) + return false; + m_nChannels = lastChannel + 1u; + const PATTERNINDEX numPatterns = file.ReadUint8() + 1u; + + if(!file.CanRead(m_nChannels + numPatterns * m_nChannels * 64 * 6)) + return false; + + for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++) + { + ChnSettings[chn].Reset(); + ChnSettings[chn].nPan = file.ReadUint8() * 0x11; + } + + Patterns.ResizeArray(numPatterns); + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64)) + { + file.Skip(m_nChannels * 64 * 6); + continue; + } + ModCommand dummy; + for(ROWINDEX row = 0; row < 64; row++) + { + for(ModCommand &m : Patterns[pat].GetRow(row)) + { + const auto data = file.ReadArray(); + if(data[0] > 0 && data[0] <= 77) + m.note = NOTE_MIN + 35 + data[0]; + m.instr = data[1]; + if(!TranslateXMFEffect(m, data[2], data[5]) || !TranslateXMFEffect(dummy, data[3], data[4])) + return false; + m.FillInTwoCommands(m.command, m.param, dummy.command, dummy.param); + } + } + } + + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= numSamples; smp++) + { + SampleIO(Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM).ReadSample(Samples[smp], file); + } + } + + m_modFormat.formatName = UL_("Imperium Galactica XMF"); + m_modFormat.type = UL_("xmf"); + m_modFormat.madeWithTracker.clear(); + m_modFormat.charset = mpt::Charset::CP437; // No strings in this format... + + return true; +} + + +OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MIDIMacros.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/MIDIMacros.cpp index 150e1416a..fd20760d7 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MIDIMacros.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MIDIMacros.cpp @@ -341,7 +341,11 @@ void MIDIMacroConfig::Sanitize() // Fix old-format (not conforming to IT's MIDI macro definitions) MIDI config strings. void MIDIMacroConfig::UpgradeMacros() { - for(auto ¯o : *this) + for(auto ¯o : SFx) + { + macro.UpgradeLegacyMacro(); + } + for(auto ¯o : Zxx) { macro.UpgradeLegacyMacro(); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.cpp index 16547539b..6a2e9181a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.cpp @@ -10,6 +10,7 @@ #include "stdafx.h" #include "MPEGFrame.h" +#include "mpt/io_read/filereader.hpp" #include "../common/FileReader.h" OPENMPT_NAMESPACE_BEGIN @@ -68,17 +69,19 @@ bool MPEGFrame::IsMPEGHeader(const uint8 (&header)[3]) } -MPEGFrame::MPEGFrame(FileReader &file) +MPEGFrame::MPEGFrame(FileCursor &file) : frameSize(0) , numSamples(0) , isValid(false) , isLAME(false) { - uint8 header[4]; - file.ReadArray(header); + uint8 header[4] = {}; + mpt::FR::ReadArray(file, header); if(!IsMPEGHeader(reinterpret_cast(header))) + { return; + } uint8 version = (header[1] & 0x18) >> 3; uint8 mpeg1 = (version == 3) ? 0 : 1; @@ -89,25 +92,32 @@ MPEGFrame::MPEGFrame(FileReader &file) bool stereo = ((header[3] & 0xC0) >> 6) != 3; isValid = true; - frameSize = (((mpegCoefficients[mpeg1][layer] * (bitRates[mpeg1][layer][bitRate] * 1000) / samplingRates[version][sampleRate]) + padding)) * (layer == 0 ? 4 : 1); + frameSize = static_cast((((mpegCoefficients[mpeg1][layer] * (bitRates[mpeg1][layer][bitRate] * 1000) / samplingRates[version][sampleRate]) + padding)) * (layer == 0 ? uint16(4u) : uint16(1u))); numSamples = samplesPerFrame[mpeg1][layer]; - if(stereo) numSamples *= 2u; + if(stereo) + { + numSamples *= 2u; + } uint32 lameOffset = sideInfoSize[mpeg1][stereo ? 1 : 0]; if(frameSize < lameOffset + 8) + { return; + } - uint8 frame[36]; - file.ReadStructPartial(frame, lameOffset + 4); + uint8 frame[36] = {}; + mpt::FR::ReadStructPartial(file, frame, lameOffset + 4); // Don't check first two bytes, might be CRC for(uint32 i = 2; i < lameOffset; i++) { if(frame[i] != 0) + { return; + } } // This is all we really need to know for our purposes in the MO3 decoder. - isLAME = !memcmp(frame + lameOffset, "Info", 4) || !memcmp(frame + lameOffset, "Xing", 4); + isLAME = !std::memcmp(frame + lameOffset, "Info", 4) || !std::memcmp(frame + lameOffset, "Xing", 4); } OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.h b/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.h index 25c57b0ea..2f0b309ea 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MPEGFrame.h @@ -24,7 +24,7 @@ public: bool isValid; // Is a valid frame at all bool isLAME; // Has Xing/LAME header - MPEGFrame(FileReader &file); + MPEGFrame(FileCursor &file); static bool IsMPEGHeader(const uint8 (&header)[3]); }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Message.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Message.cpp index c06607327..a0f8e8456 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Message.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Message.cpp @@ -16,6 +16,7 @@ #include "stdafx.h" #include "Message.h" #include "../common/FileReader.h" +#include "mpt/string/utility.hpp" OPENMPT_NAMESPACE_BEGIN diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Message.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Message.h index 76c98db0f..ec2a42695 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Message.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Message.h @@ -66,6 +66,8 @@ public: // Sets the song message. Expects the provided string to already use the internal line ending character. void SetRaw(std::string message) noexcept { assign(std::move(message)); } + + std::string GetString() const { return *this; } }; OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerInterface.h b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerInterface.h index 43d2f6777..fd6b3d374 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerInterface.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerInterface.h @@ -25,11 +25,11 @@ class CResampler; template struct MixerTraits { - enum : int { numChannelsIn = channelsIn }; // Number of channels in sample - enum : int { numChannelsOut = channelsOut }; // Number of mixer output channels - typedef out output_t; // Output buffer sample type - typedef in input_t; // Input buffer sample type - typedef out outbuf_t[channelsOut]; // Output buffer sampling point type + static constexpr int numChannelsIn = channelsIn; // Number of channels in sample + static constexpr int numChannelsOut = channelsOut; // Number of mixer output channels + using output_t = out; // Output buffer sample type + using input_t = in; // Input buffer sample type + using outbuf_t = out[channelsOut]; // Output buffer sampling point type // To perform sample conversion, add a function with the following signature to your derived classes: // static MPT_CONSTEXPRINLINE output_t Convert(const input_t x) }; @@ -41,7 +41,20 @@ struct MixerTraits template struct NoInterpolation { - MPT_FORCEINLINE NoInterpolation(const ModChannel &, const CResampler &, unsigned int) { } + ModChannel &channel; + + MPT_FORCEINLINE NoInterpolation(ModChannel &c, const CResampler &, unsigned int) + : channel{c} + { + // Adding 0.5 to the sample position before the interpolation loop starts + // effectively gives us nearest-neighbour with rounding instead of truncation. + // This gives us more consistent behaviour between forward and reverse playing of a sample. + c.position += SamplePosition::Ratio(1, 2); + } + MPT_FORCEINLINE ~NoInterpolation() + { + channel.position -= SamplePosition::Ratio(1, 2); + } MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const inBuffer, const int32) { @@ -76,8 +89,8 @@ static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Tr MixFunc mix{c}; unsigned int samples = numSamples; - SamplePosition smpPos = c.position; // Fixed-point sample position - const SamplePosition increment = c.increment; // Fixed-point sample increment + SamplePosition smpPos = c.position; // Fixed-point sample position + const SamplePosition increment = c.increment; // Fixed-point sample increment while(samples--) { @@ -94,6 +107,6 @@ static void SampleLoop(ModChannel &chn, const CResampler &resampler, typename Tr } // Type of the SampleLoop function above -typedef void (*MixFuncInterface)(ModChannel &, const CResampler &, mixsample_t *, unsigned int); +using MixFuncInterface = void (*)(ModChannel &, const CResampler &, mixsample_t *, unsigned int); OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp index e0dc098a5..70422b80f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.cpp @@ -23,8 +23,8 @@ void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 { for(uint32 i=0; i(*pIn1++ * _f2ic); + *pOut++ = static_cast(*pIn2++ * _f2ic); } } @@ -33,26 +33,8 @@ void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCou { for(uint32 i=0; i(*pSrc++) * _i2fc; + *pOut2++ = static_cast(*pSrc++) * _i2fc; } } @@ -159,6 +141,8 @@ void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples) +#ifndef MPT_INTMIXER + void InterleaveStereo(const mixsample_t * MPT_RESTRICT inputL, const mixsample_t * MPT_RESTRICT inputR, mixsample_t * MPT_RESTRICT output, size_t numSamples) { while(numSamples--) @@ -178,6 +162,8 @@ void DeinterleaveStereo(const mixsample_t * MPT_RESTRICT input, mixsample_t * MP } } +#endif + OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.h b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.h index 350997465..2765c6474 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/MixerLoops.h @@ -20,15 +20,15 @@ struct ModChannel; void StereoMixToFloat(const int32 *pSrc, float *pOut1, float *pOut2, uint32 nCount, const float _i2fc); void FloatToStereoMix(const float *pIn1, const float *pIn2, int32 *pOut, uint32 uint32, const float _f2ic); -void MonoMixToFloat(const int32 *pSrc, float *pOut, uint32 uint32, const float _i2fc); -void FloatToMonoMix(const float *pIn, int32 *pOut, uint32 uint32, const float _f2ic); void InitMixBuffer(mixsample_t *pBuffer, uint32 nSamples); void InterleaveFrontRear(mixsample_t *pFrontBuf, mixsample_t *pRearBuf, uint32 nFrames); void MonoFromStereo(mixsample_t *pMixBuf, uint32 nSamples); -void InterleaveStereo(const mixsample_t *inputL, const mixsample_t *inputR, mixsample_t *output, size_t numSamples); -void DeinterleaveStereo(const mixsample_t *input, mixsample_t *outputL, mixsample_t *outputR, size_t numSamples); +#ifndef MPT_INTMIXER +void InterleaveStereo(const mixsample_t * MPT_RESTRICT inputL, const mixsample_t * MPT_RESTRICT inputR, mixsample_t * MPT_RESTRICT output, size_t numSamples); +void DeinterleaveStereo(const mixsample_t * MPT_RESTRICT input, mixsample_t * MPT_RESTRICT outputL, mixsample_t * MPT_RESTRICT outputR, size_t numSamples); +#endif void EndChannelOfs(ModChannel &chn, mixsample_t *pBuffer, uint32 nSamples); void StereoFill(mixsample_t *pBuffer, uint32 nSamples, mixsample_t &rofs, mixsample_t &lofs); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.cpp index 4d6550a4f..740f13902 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.cpp @@ -19,7 +19,10 @@ void ModChannel::Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELI { if(resetMask & resetSetPosBasic) { - nNote = nNewNote = NOTE_NONE; + // IT compatibility: Initial "last note memory" of channel is C-0 (so a lonely instrument number without note will play that note). + // Test case: InitialNoteMemory.it + nNote = nNewNote = (sndFile.m_playBehaviour[kITInitialNoteMemory] ? NOTE_MIN : NOTE_NONE); + nArpeggioLastNote = lastMidiNoteWithoutArp = NOTE_NONE; nNewIns = nOldIns = 0; pModSample = nullptr; pModInstrument = nullptr; @@ -124,9 +127,9 @@ void ModChannel::UpdateInstrumentVolume(const ModSample *smp, const ModInstrumen } -ModCommand::NOTE ModChannel::GetPluginNote(bool realNoteMapping) const +ModCommand::NOTE ModChannel::GetPluginNote(bool realNoteMapping, bool ignoreArpeggio) const { - if(nArpeggioLastNote != NOTE_NONE) + if(nArpeggioLastNote != NOTE_NONE && !ignoreArpeggio) { // If an arpeggio is playing, this definitely the last playing note, which may be different from the arpeggio base note stored in nNote. return nArpeggioLastNote; @@ -187,7 +190,7 @@ void ModChannel::RecalcTuningFreq(Tuning::RATIOTYPE vibratoFactor, Tuning::NOTEI if(sndFile.m_playBehaviour[kITRealNoteMapping] && note >= NOTE_MIN && note <= NOTE_MAX) note = pModInstrument->NoteMap[note - NOTE_MIN]; - nPeriod = mpt::saturate_round(nC5Speed * vibratoFactor * pModInstrument->pTuning->GetRatio(note - NOTE_MIDDLEC + arpeggioSteps, nFineTune + m_PortamentoFineSteps) * (1 << FREQ_FRACBITS)); + nPeriod = mpt::saturate_round(static_cast(nC5Speed) * vibratoFactor * pModInstrument->pTuning->GetRatio(static_cast(note - NOTE_MIDDLEC + arpeggioSteps), nFineTune + m_PortamentoFineSteps) * (1 << FREQ_FRACBITS)); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.h index b82939591..a491f8f24 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModChannel.h @@ -97,7 +97,7 @@ struct ModChannel uint8 nNote; NewNoteAction nNNA; uint8 nLastNote; // Last note, ignoring note offs and cuts - for MIDI macros - uint8 nArpeggioLastNote, nArpeggioBaseNote; // For plugin arpeggio + uint8 nArpeggioLastNote, lastMidiNoteWithoutArp; // For plugin arpeggio and NNA handling uint8 nNewNote, nNewIns, nOldIns, nCommand, nArpeggio; uint8 nRetrigParam, nRetrigCount; uint8 nOldVolumeSlide, nOldFineVolUpDown; @@ -187,7 +187,7 @@ struct ModChannel uint32 GetVSTVolume() const noexcept { return (pModInstrument) ? pModInstrument->nGlobalVol * 4 : nVolume; } - ModCommand::NOTE GetPluginNote(bool realNoteMapping) const; + ModCommand::NOTE GetPluginNote(bool realNoteMapping, bool ignoreArpeggio = false) const; // Check if the channel has a valid MIDI output. A return value of true implies that pModInstrument != nullptr. bool HasMIDIOutput() const noexcept { return pModInstrument != nullptr && pModInstrument->HasValidMIDIChannel(); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp index f55aaa150..e508e4b7b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModInstrument.cpp @@ -48,7 +48,7 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType) if(at(nLoopEnd).tick - 1 > at(nLoopEnd - 1).tick) { // Insert an interpolated point just before the loop point. - EnvelopeNode::tick_t tick = at(nLoopEnd).tick - 1u; + EnvelopeNode::tick_t tick = static_cast(at(nLoopEnd).tick - 1u); auto interpolatedValue = static_cast(GetValueFromPosition(tick, 64)); insert(begin() + nLoopEnd, EnvelopeNode(tick, interpolatedValue)); } else @@ -70,6 +70,9 @@ void InstrumentEnvelope::Convert(MODTYPE fromType, MODTYPE toType) // returns value in range [0, rangeOut]. int32 InstrumentEnvelope::GetValueFromPosition(int position, int32 rangeOut, int32 rangeIn) const { + if(empty()) + return 0; + uint32 pt = size() - 1u; const int32 ENV_PRECISION = 1 << 16; @@ -126,13 +129,20 @@ void InstrumentEnvelope::Sanitize(uint8 maxValue) it->tick = std::max(it->tick, (it - 1)->tick); LimitMax(it->value, maxValue); } + LimitMax(nLoopEnd, static_cast(size() - 1)); + LimitMax(nLoopStart, nLoopEnd); + LimitMax(nSustainEnd, static_cast(size() - 1)); + LimitMax(nSustainStart, nSustainEnd); + if(nReleaseNode != ENV_RELEASE_NODE_UNSET) + LimitMax(nReleaseNode, static_cast(size() - 1)); + } else + { + nLoopStart = 0; + nLoopEnd = 0; + nSustainStart = 0; + nSustainEnd = 0; + nReleaseNode = ENV_RELEASE_NODE_UNSET; } - LimitMax(nLoopEnd, static_cast(size() - 1)); - LimitMax(nLoopStart, nLoopEnd); - LimitMax(nSustainEnd, static_cast(size() - 1)); - LimitMax(nSustainStart, nSustainEnd); - if(nReleaseNode != ENV_RELEASE_NODE_UNSET) - LimitMax(nReleaseNode, static_cast(size() - 1)); } @@ -285,7 +295,7 @@ void ModInstrument::Sanitize(MODTYPE modType) MPT_UNREFERENCED_PARAMETER(modType); const uint8 range = ENVELOPE_MAX; #else - const uint8 range = modType == MOD_TYPE_AMS ? uint8_max : ENVELOPE_MAX; + const uint8 range = modType == MOD_TYPE_AMS ? uint8_max : uint8(ENVELOPE_MAX); #endif VolEnv.Sanitize(); PanEnv.Sanitize(); @@ -312,7 +322,7 @@ std::map ModInstrument::CanConvertToDefaultNoteMap() const { if(Keyboard[i] == 0) continue; - if(!NoteMap[i] || NoteMap[i] == (i + 1)) + if(NoteMap[i] == NOTE_NONE) continue; const int8 relativeNote = static_cast(NoteMap[i] - (i + NOTE_MIN)); @@ -320,6 +330,16 @@ std::map ModInstrument::CanConvertToDefaultNoteMap() const return {}; transposeMap[Keyboard[i]] = relativeNote; } + // Remove all samples that wouldn't be transposed. + // They were previously inserted into the map to catch the case where a specific sample's + // map would start with a transpose value of 0 but end with a different value. + for(auto it = transposeMap.begin(); it != transposeMap.end();) + { + if(it->second == 0) + it = transposeMap.erase(it); + else + it++; + } return transposeMap; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.cpp index 4630d0f9b..8ebce2890 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.cpp @@ -525,7 +525,8 @@ bool ModSample::HasCustomCuePoints() const return false; for(SmpLength i = 0; i < std::size(cues); i++) { - if(cues[i] != (i + 1) << 11) + const SmpLength defaultValue = (i + 1) << 11; + if(cues[i] != defaultValue && (cues[i] < nLength || defaultValue < nLength)) return true; } return false; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h index 07a2e1f4a..c250038ba 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSample.h @@ -99,6 +99,10 @@ struct ModSample MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); return pData.pSample16; } + template + MPT_FORCEINLINE const Tsample *sample() const noexcept = delete; + template + MPT_FORCEINLINE Tsample *sample() noexcept = delete; // Return the size of one (elementary) sample in bytes. uint8 GetElementarySampleSize() const noexcept { return (uFlags & CHN_16BIT) ? 2 : 1; } @@ -172,4 +176,29 @@ struct ModSample void SetAdlib(bool enable, OPLPatch patch = OPLPatch{{}}); }; +template <> +MPT_FORCEINLINE const int8 *ModSample::sample() const noexcept +{ + MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); + return pData.pSample8; +} +template <> +MPT_FORCEINLINE int8 *ModSample::sample() noexcept +{ + MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); + return pData.pSample8; +} +template <> +MPT_FORCEINLINE const int16 *ModSample::sample() const noexcept +{ + MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); + return pData.pSample16; +} +template <> +MPT_FORCEINLINE int16 *ModSample::sample() noexcept +{ + MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); + return pData.pSample16; +} + OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp index b37eac134..afaab9702 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.cpp @@ -28,7 +28,6 @@ ModSequence::ModSequence(CSoundFile &sndFile) ModSequence& ModSequence::operator=(const ModSequence &other) { - MPT_ASSERT(&other.m_sndFile == &m_sndFile); if(&other == this) return *this; std::vector::assign(other.begin(), other.end()); @@ -38,7 +37,7 @@ ModSequence& ModSequence::operator=(const ModSequence &other) } -bool ModSequence::operator== (const ModSequence &other) const +bool ModSequence::operator== (const ModSequence &other) const noexcept { return static_cast &>(*this) == other && m_name == other.m_name @@ -46,7 +45,7 @@ bool ModSequence::operator== (const ModSequence &other) const } -bool ModSequence::NeedsExtraDatafield() const +bool ModSequence::NeedsExtraDatafield() const noexcept { return (m_sndFile.GetType() == MOD_TYPE_MPT && m_sndFile.Patterns.GetNumPatterns() > 0xFD); } @@ -87,7 +86,7 @@ void ModSequence::AdjustToNewModType(const MODTYPE oldtype) } -ORDERINDEX ModSequence::GetLengthTailTrimmed() const +ORDERINDEX ModSequence::GetLengthTailTrimmed() const noexcept { if(empty()) return 0; @@ -96,34 +95,37 @@ ORDERINDEX ModSequence::GetLengthTailTrimmed() const } -ORDERINDEX ModSequence::GetLengthFirstEmpty() const +ORDERINDEX ModSequence::GetLengthFirstEmpty() const noexcept { return static_cast(std::distance(begin(), std::find(begin(), end(), GetInvalidPatIndex()))); } -ORDERINDEX ModSequence::GetNextOrderIgnoringSkips(const ORDERINDEX start) const +ORDERINDEX ModSequence::GetNextOrderIgnoringSkips(const ORDERINDEX start) const noexcept { if(empty()) return 0; auto length = GetLength(); ORDERINDEX next = std::min(ORDERINDEX(length - 1), ORDERINDEX(start + 1)); - while(next + 1 < length && at(next) == GetIgnoreIndex()) next++; + while(next + 1 < length && (*this)[next] == GetIgnoreIndex()) + next++; return next; } -ORDERINDEX ModSequence::GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const +ORDERINDEX ModSequence::GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const noexcept { const ORDERINDEX last = GetLastIndex(); - if(start == 0 || last == 0) return 0; + if(start == 0 || last == 0) + return 0; ORDERINDEX prev = std::min(ORDERINDEX(start - 1), last); - while(prev > 0 && at(prev) == GetIgnoreIndex()) prev--; + while(prev > 0 && (*this)[prev] == GetIgnoreIndex()) + prev--; return prev; } -void ModSequence::Remove(ORDERINDEX posBegin, ORDERINDEX posEnd) +void ModSequence::Remove(ORDERINDEX posBegin, ORDERINDEX posEnd) noexcept { if(posEnd < posBegin || posEnd >= size()) return; @@ -141,7 +143,7 @@ void ModSequence::RemovePattern(PATTERNINDEX pat) for(ORDERINDEX i = 0; i < orderLength; i++) { newPosition[i] = i - maxJump; - if(at(i) == pat) + if((*this)[i] == pat) { maxJump++; } @@ -154,8 +156,11 @@ void ModSequence::RemovePattern(PATTERNINDEX pat) erase(std::remove(begin(), end(), pat), end()); // Only apply to patterns actually found in this sequence - for(auto p : *this) if(m_sndFile.Patterns.IsValidPat(p)) + for(auto p : *this) { + if(!m_sndFile.Patterns.IsValidPat(p)) + continue; + for(auto &m : m_sndFile.Patterns[p]) { if(m.command == CMD_POSITIONJUMP && m.param < newPosition.size()) @@ -197,23 +202,23 @@ ORDERINDEX ModSequence::insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fi } -bool ModSequence::IsValidPat(ORDERINDEX ord) const +bool ModSequence::IsValidPat(ORDERINDEX ord) const noexcept { if(ord < size()) - return m_sndFile.Patterns.IsValidPat(at(ord)); + return m_sndFile.Patterns.IsValidPat((*this)[ord]); return false; } -CPattern *ModSequence::PatternAt(ORDERINDEX ord) const +CPattern *ModSequence::PatternAt(ORDERINDEX ord) const noexcept { if(!IsValidPat(ord)) return nullptr; - return &m_sndFile.Patterns[at(ord)]; + return &m_sndFile.Patterns[(*this)[ord]]; } -ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bool searchForward) const +ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bool searchForward) const noexcept { const ORDERINDEX length = GetLength(); if(startSearchAt >= length) @@ -221,7 +226,7 @@ ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bo ORDERINDEX ord = startSearchAt; for(ORDERINDEX p = 0; p < length; p++) { - if(at(ord) == pat) + if((*this)[ord] == pat) { return ord; } @@ -241,7 +246,9 @@ ORDERINDEX ModSequence::FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt, bo PATTERNINDEX ModSequence::EnsureUnique(ORDERINDEX ord) { - PATTERNINDEX pat = at(ord); + if(ord >= size()) + return PATTERNINDEX_INVALID; + PATTERNINDEX pat = (*this)[ord]; if(!IsValidPat(ord)) return pat; @@ -256,7 +263,7 @@ PATTERNINDEX ModSequence::EnsureUnique(ORDERINDEX ord) PATTERNINDEX newPat = m_sndFile.Patterns.Duplicate(pat); if(newPat != PATTERNINDEX_INVALID) { - at(ord) = newPat; + (*this)[ord] = newPat; return newPat; } } @@ -278,6 +285,19 @@ ModSequenceSet::ModSequenceSet(CSoundFile &sndFile) } +ModSequenceSet& ModSequenceSet::operator=(const ModSequenceSet &other) +{ + if(&other == this) + return *this; + m_Sequences = other.m_Sequences; + if(m_Sequences.size() > m_sndFile.GetModSpecifications().sequencesMax) + m_Sequences.resize(m_sndFile.GetModSpecifications().sequencesMax, ModSequence{m_sndFile}); + if(m_currentSeq >= m_Sequences.size()) + m_currentSeq = 0; + return *this; +} + + void ModSequenceSet::Initialize() { m_currentSeq = 0; @@ -285,7 +305,7 @@ void ModSequenceSet::Initialize() } -void ModSequenceSet::SetSequence(SEQUENCEINDEX n) +void ModSequenceSet::SetSequence(SEQUENCEINDEX n) noexcept { if(n < m_Sequences.size()) m_currentSeq = n; @@ -345,7 +365,7 @@ void ModSequenceSet::OnModTypeChanged(MODTYPE oldType) } -bool ModSequenceSet::CanSplitSubsongs() const +bool ModSequenceSet::CanSplitSubsongs() const noexcept { return GetNumSequences() == 1 && m_sndFile.GetModSpecifications().sequencesMax > 1 && m_Sequences[0].HasSubsongs(); } @@ -507,14 +527,14 @@ bool ModSequenceSet::MergeSequences() // Check if a playback position is currently locked (inaccessible) -bool ModSequence::IsPositionLocked(ORDERINDEX position) const +bool ModSequence::IsPositionLocked(ORDERINDEX position) const noexcept { return(m_sndFile.m_lockOrderStart != ORDERINDEX_INVALID && (position < m_sndFile.m_lockOrderStart || position > m_sndFile.m_lockOrderEnd)); } -bool ModSequence::HasSubsongs() const +bool ModSequence::HasSubsongs() const noexcept { const auto endPat = begin() + GetLengthTailTrimmed(); return std::find_if(begin(), endPat, @@ -535,7 +555,7 @@ size_t ModSequence::WriteAsByte(std::ostream &f, const ORDERINDEX count, uint8 s for(size_t i = 0; i < limit; i++) { - const PATTERNINDEX pat = at(i); + const PATTERNINDEX pat = (*this)[i]; uint8 temp = static_cast(pat); if(pat == GetInvalidPatIndex()) temp = stopIndex; @@ -606,8 +626,10 @@ void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t, mpt::C { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdSequence, Version::Current().GetRawVersion()); - if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) + if(ssb.HasFailed()) + { return; + } int8 useUTF8 = 0; ssb.ReadItem(useUTF8, "u"); std::string str; @@ -619,8 +641,10 @@ void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t, mpt::C ssb.ReadItem(seq, "a", srlztn::VectorReader(nSize)); ORDERINDEX restartPos = ORDERINDEX_INVALID; - if(ssb.ReadItem(restartPos, "r") != srlztn::SsbRead::EntryNotFound && restartPos < nSize) + if(ssb.ReadItem(restartPos, "r") && restartPos < nSize) + { seq.SetRestartPos(restartPos); + } } @@ -646,8 +670,10 @@ void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t, mp { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdSequences, Version::Current().GetRawVersion()); - if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) + if(ssb.HasFailed()) + { return; + } SEQUENCEINDEX seqs = 0; uint8 currentSeq = 0; ssb.ReadItem(seqs, "n"); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.h b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.h index 12d1952d0..aeacac79a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/ModSequence.h @@ -38,16 +38,16 @@ public: ModSequence(const ModSequence &) = default; ModSequence& operator=(const ModSequence &other); - bool operator==(const ModSequence &other) const; - bool operator!=(const ModSequence &other) const { return !(*this == other); } + bool operator==(const ModSequence &other) const noexcept; + bool operator!=(const ModSequence &other) const noexcept { return !(*this == other); } - ORDERINDEX GetLength() const { return mpt::saturate_cast(size()); } + ORDERINDEX GetLength() const noexcept { return mpt::saturate_cast(size()); } // Returns last accessible index, i.e. GetLength() - 1, or 0 if the order list is empty. - ORDERINDEX GetLastIndex() const { return std::max(ORDERINDEX(1), GetLength()) - 1u; } + ORDERINDEX GetLastIndex() const noexcept { return static_cast(std::max(ORDERINDEX(1), GetLength()) - 1u); } // Returns length of sequence without counting trailing '---' items. - ORDERINDEX GetLengthTailTrimmed() const; + ORDERINDEX GetLengthTailTrimmed() const noexcept; // Returns length of sequence stopping counting on first '---' (or at the end of sequence). - ORDERINDEX GetLengthFirstEmpty() const; + ORDERINDEX GetLengthFirstEmpty() const noexcept; // Replaces order list with 'newSize' copies of 'pat'. void assign(ORDERINDEX newSize, PATTERNINDEX pat); @@ -65,37 +65,37 @@ public: void resize(ORDERINDEX newSize, PATTERNINDEX pat) { std::vector::resize(std::min(MAX_ORDERS, newSize), pat); } // Removes orders from range [posBegin, posEnd]. - void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd); + void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd) noexcept; // Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. void RemovePattern(PATTERNINDEX pat); // Replaces all occurences of oldPat with newPat. - void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); } + void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) noexcept { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); } // Removes any "---" patterns at the end of the list. void Shrink() { resize(GetLengthTailTrimmed()); } // Check if pattern at sequence position ord is valid. - bool IsValidPat(ORDERINDEX ord) const; + bool IsValidPat(ORDERINDEX ord) const noexcept; - CPattern *PatternAt(ORDERINDEX ord) const; + CPattern *PatternAt(ORDERINDEX ord) const noexcept; void AdjustToNewModType(const MODTYPE oldtype); // Returns the internal representation of a stop '---' index - static constexpr PATTERNINDEX GetInvalidPatIndex() { return uint16_max; } + static constexpr PATTERNINDEX GetInvalidPatIndex() noexcept { return uint16_max; } // Returns the internal representation of an ignore '+++' index - static constexpr PATTERNINDEX GetIgnoreIndex() { return uint16_max - 1; } + static constexpr PATTERNINDEX GetIgnoreIndex() noexcept { return uint16_max - 1; } // Returns the previous/next order ignoring skip indices (+++). // If no previous/next order exists, return first/last order, and zero // when orderlist is empty. - ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const; - ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const; + ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const noexcept; + ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const noexcept; // Find an order item that contains a given pattern number. - ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const; + ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const noexcept; // Ensures that the pattern at the specified order position is used only once (across all sequences). // If another usage is found, the pattern is replaced by a copy and the new index is returned. @@ -107,17 +107,17 @@ public: #endif // MODPLUG_NO_FILESAVE // Returns true if the IT orderlist datafield is not sufficient to store orderlist information. - bool NeedsExtraDatafield() const; + bool NeedsExtraDatafield() const noexcept; #ifdef MODPLUG_TRACKER // Check if a playback position is currently locked (inaccessible) - bool IsPositionLocked(ORDERINDEX position) const; + bool IsPositionLocked(ORDERINDEX position) const noexcept; // Check if this sequence has subsongs separated by invalid ("---" or non-existing) patterns - bool HasSubsongs() const; + bool HasSubsongs() const noexcept; #endif // MODPLUG_TRACKER // Sequence name setter / getter - inline void SetName(const mpt::ustring &newName) { m_name = newName;} + inline void SetName(mpt::ustring newName) noexcept { m_name = std::move(newName); } inline mpt::ustring GetName() const { return m_name; } // Restart position setter / getter @@ -139,6 +139,7 @@ protected: public: ModSequenceSet(CSoundFile &sndFile); ModSequenceSet(ModSequenceSet &&) noexcept = default; + ModSequenceSet& operator=(const ModSequenceSet & other); // Remove all sequences and initialize default sequence void Initialize(); @@ -150,11 +151,11 @@ public: ModSequence& operator() (SEQUENCEINDEX seq) { return m_Sequences[seq]; } const ModSequence& operator() (SEQUENCEINDEX seq) const { return m_Sequences[seq]; } - SEQUENCEINDEX GetNumSequences() const { return static_cast(m_Sequences.size()); } - SEQUENCEINDEX GetCurrentSequenceIndex() const { return m_currentSeq; } + SEQUENCEINDEX GetNumSequences() const noexcept { return static_cast(m_Sequences.size()); } + SEQUENCEINDEX GetCurrentSequenceIndex() const noexcept { return m_currentSeq; } // Sets working sequence. - void SetSequence(SEQUENCEINDEX); + void SetSequence(SEQUENCEINDEX) noexcept; // Add new empty sequence. // Returns the ID of the new sequence, or SEQUENCEINDEX_INVALID on failure. SEQUENCEINDEX AddSequence(); @@ -162,9 +163,9 @@ public: void RemoveSequence(SEQUENCEINDEX); // Returns the internal representation of a stop '---' index - static constexpr PATTERNINDEX GetInvalidPatIndex() { return ModSequence::GetInvalidPatIndex(); } + static constexpr PATTERNINDEX GetInvalidPatIndex() noexcept { return ModSequence::GetInvalidPatIndex(); } // Returns the internal representation of an ignore '+++' index - static constexpr PATTERNINDEX GetIgnoreIndex() { return ModSequence::GetIgnoreIndex(); } + static constexpr PATTERNINDEX GetIgnoreIndex() noexcept { return ModSequence::GetIgnoreIndex(); } #ifdef MODPLUG_TRACKER // Assigns a new set of sequences. The vector contents indicate which existing sequences to keep / duplicate or if a new sequences should be inserted (SEQUENCEINDEX_INVALID) @@ -174,7 +175,7 @@ public: // Adjust sequence when converting between module formats void OnModTypeChanged(MODTYPE oldType); // Check if there is a single sequences that qualifies for subsong splitting - bool CanSplitSubsongs() const; + bool CanSplitSubsongs() const noexcept; // If there are subsongs (separated by "---" patterns) in the module, // asks user whether to convert these into multiple sequences (given that the // modformat supports multiple sequences). @@ -188,12 +189,12 @@ public: bool MergeSequences(); #endif // MODPLUG_TRACKER - std::vector::iterator begin() { return m_Sequences.begin(); } - std::vector::const_iterator begin() const { return m_Sequences.begin(); } - std::vector::const_iterator cbegin() const { return m_Sequences.cbegin(); } - std::vector::iterator end() { return m_Sequences.end(); } - std::vector::const_iterator end() const { return m_Sequences.end(); } - std::vector::const_iterator cend() const { return m_Sequences.cend(); } + std::vector::iterator begin() noexcept { return m_Sequences.begin(); } + std::vector::const_iterator begin() const noexcept { return m_Sequences.begin(); } + std::vector::const_iterator cbegin() const noexcept { return m_Sequences.cbegin(); } + std::vector::iterator end() noexcept { return m_Sequences.end(); } + std::vector::const_iterator end() const noexcept { return m_Sequences.end(); } + std::vector::const_iterator cend() const noexcept { return m_Sequences.cend(); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.cpp index 848b47d3b..6a1074acf 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.cpp @@ -10,6 +10,7 @@ #include "stdafx.h" #include "OggStream.h" #include "mpt/crc/crc.hpp" +#include "mpt/io_read/filereader.hpp" #include "../common/FileReader.h" @@ -53,86 +54,76 @@ uint16 PageInfo::GetPageDataSize() const } -bool AdvanceToPageMagic(FileReader &file) +bool AdvanceToPageMagic(FileCursor &file) { -#if MPT_COMPILER_MSVC -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#endif // MPT_COMPILER_MSVC - while(true) -#if MPT_COMPILER_MSVC -#pragma warning(pop) -#endif // MPT_COMPILER_MSVC + while(mpt::FR::CanRead(file, 4)) { - if(!file.CanRead(4)) + if(mpt::FR::ReadMagic(file, "OggS")) { - return false; - } - if(file.ReadMagic("OggS")) - { - file.SkipBack(4); + mpt::FR::SkipBack(file, 4); return true; } - file.Skip(1); + mpt::FR::Skip(file, 1); } + return false; } -bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector *pageData) +bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector *pageData) { pageInfo = PageInfo(); if(pageData) { (*pageData).clear(); } - if(!file.ReadMagic("OggS")) + if(!mpt::FR::ReadMagic(file, "OggS")) { return false; } - file.SkipBack(4); - FileReader filePageReader = file; // do not modify original file read position - if(!filePageReader.ReadStruct(pageInfo.header)) + mpt::FR::SkipBack(file, 4); + FileCursor filePageCursor = file; // do not modify original file read position + if(!mpt::FR::ReadStruct(filePageCursor, pageInfo.header)) { return false; } - if(!filePageReader.CanRead(pageInfo.header.page_segments)) + if(!mpt::FR::CanRead(filePageCursor, pageInfo.header.page_segments)) { return false; } uint16 pageDataSize = 0; for(uint8 segment = 0; segment < pageInfo.header.page_segments; ++segment) { - pageInfo.segment_table[segment] = filePageReader.ReadIntLE(); + pageInfo.segment_table[segment] = mpt::FR::ReadIntLE(filePageCursor); pageDataSize += pageInfo.segment_table[segment]; } - if(!filePageReader.CanRead(pageDataSize)) + if(!mpt::FR::CanRead(filePageCursor, pageDataSize)) { return false; } if(pageData) { - filePageReader.ReadVector(*pageData, pageDataSize); + mpt::FR::ReadVector(filePageCursor , *pageData, pageDataSize); } else { - filePageReader.Skip(pageDataSize); + mpt::FR::Skip(filePageCursor, pageDataSize); } - filePageReader.SkipBack(pageInfo.GetPagePhysicalSize()); + mpt::FR::SkipBack(filePageCursor, pageInfo.GetPagePhysicalSize()); { mpt::crc32_ogg calculatedCRC; uint8 rawHeader[sizeof(PageHeader)]; MemsetZero(rawHeader); - filePageReader.ReadArray(rawHeader); + mpt::FR::ReadArray(filePageCursor, rawHeader); std::memset(rawHeader + 22, 0, 4); // clear out old crc calculatedCRC.process(rawHeader, rawHeader + sizeof(rawHeader)); - filePageReader.Skip(pageInfo.header.page_segments); + mpt::FR::Skip(filePageCursor, pageInfo.header.page_segments); calculatedCRC.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); if(pageData) { - filePageReader.Skip(pageDataSize); + mpt::FR::Skip(filePageCursor, pageDataSize); calculatedCRC.process(*pageData); } else { - FileReader pageDataReader = filePageReader.ReadChunk(pageDataSize); + FileCursor pageDataReader = mpt::FR::ReadChunk(filePageCursor, pageDataSize); auto pageDataView = pageDataReader.GetPinnedView(); calculatedCRC.process(pageDataView.GetSpan()); } @@ -141,41 +132,30 @@ bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector *pageData return false; } } - file.Skip(pageInfo.GetPagePhysicalSize()); + mpt::FR::Skip(file, pageInfo.GetPagePhysicalSize()); return true; } -bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector &pageData) +bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector &pageData) { return ReadPage(file, pageInfo, &pageData); } -bool ReadPage(FileReader &file) +bool ReadPage(FileCursor &file) { PageInfo pageInfo; return ReadPage(file, pageInfo); } -bool ReadPageAndSkipJunk(FileReader &file, PageInfo &pageInfo, std::vector &pageData) +bool ReadPageAndSkipJunk(FileCursor &file, PageInfo &pageInfo, std::vector &pageData) { pageInfo = PageInfo(); pageData.clear(); -#if MPT_COMPILER_MSVC -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant -#endif // MPT_COMPILER_MSVC - while(true) -#if MPT_COMPILER_MSVC -#pragma warning(pop) -#endif // MPT_COMPILER_MSVC + while(AdvanceToPageMagic(file)) { - if(!AdvanceToPageMagic(file)) - { - return false; - } if(ReadPage(file, pageInfo, pageData)) { return true; @@ -184,8 +164,9 @@ bool ReadPageAndSkipJunk(FileReader &file, PageInfo &pageInfo, std::vector &pageData) } mpt::crc32_ogg crc; pageInfo.header.CRC_checksum = 0; - char rawHeader[sizeof(PageHeader)]; + std::byte rawHeader[sizeof(PageHeader)] = {}; std::memcpy(rawHeader, &pageInfo.header, sizeof(PageHeader)); crc.process(rawHeader, rawHeader + sizeof(PageHeader)); crc.process(pageInfo.segment_table, pageInfo.segment_table + pageInfo.header.page_segments); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h index a81655278..1229b1b11 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/OggStream.h @@ -55,13 +55,13 @@ struct PageInfo // returns false on EOF -bool AdvanceToPageMagic(FileReader &file); +bool AdvanceToPageMagic(FileCursor &file); -bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector *pageData = nullptr); -bool ReadPage(FileReader &file, PageInfo &pageInfo, std::vector &pageData); -bool ReadPage(FileReader &file); +bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector *pageData = nullptr); +bool ReadPage(FileCursor &file, PageInfo &pageInfo, std::vector &pageData); +bool ReadPage(FileCursor &file); -bool ReadPageAndSkipJunk(FileReader &file, PageInfo &pageInfo, std::vector &pageData); +bool ReadPageAndSkipJunk(FileCursor &file, PageInfo &pageInfo, std::vector &pageData); bool UpdatePageCRC(PageInfo &pageInfo, const std::vector &pageData); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.cpp index f3291d5d5..c27a625fb 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.cpp @@ -85,9 +85,10 @@ MPT_NOINLINE void FIR_MinPhase(std::vector &table, const TinyFFT &fft) class BiquadFilter { - double b0, b1, b2, a1, a2, x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0; + const double b0, b1, b2, a1, a2; + double x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0; - double Filter(double x0) + double Filter(double x0) noexcept { double y0 = b0 * x0 + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; x2 = x1; @@ -267,7 +268,6 @@ State::State(uint32 sampleRate) double amigaClocksPerSample = static_cast(PAULA_HZ) / sampleRate; numSteps = static_cast(amigaClocksPerSample / MINIMUM_INTERVAL); stepRemainder = SamplePosition::FromDouble(amigaClocksPerSample - numSteps * MINIMUM_INTERVAL); - remainder = SamplePosition(0); } @@ -305,7 +305,9 @@ int State::OutputSample(const BlepArray &WinSincIntegral) const auto &blep = blepState[i % MAX_BLEPS]; output -= WinSincIntegral[blep.age] * blep.level; } +#ifdef MPT_INTMIXER output /= (1 << (Paula::BLEP_SCALE - 2)); // - 2 to compensate for the fact that we reduced the input sample bit depth +#endif return output; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.h index 527ea9e42..932461b01 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Paula.h @@ -22,7 +22,7 @@ namespace Paula inline constexpr int PAULA_HZ = 3546895; inline constexpr int MINIMUM_INTERVAL = 4; // Tradeoff between quality and speed (lower = less aliasing) -inline constexpr int BLEP_SCALE = 17; // TODO: Should be 1 for float mixer +inline constexpr int BLEP_SCALE = 17; // TODO: Should be 0 for float mixer inline constexpr int BLEP_SIZE = 2048; using BlepArray = std::array; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Resampler.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Resampler.h index 1f617c775..fe3efdd6f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Resampler.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Resampler.h @@ -44,10 +44,10 @@ OPENMPT_NAMESPACE_BEGIN #define SINC_PHASES (1<= m_visitedRows.size()) + if(o >= m_visitedRows.size()) { // Not yet initialized => unvisited + ord = o; row = 0; return true; } - const auto &visitedRows = m_visitedRows[ord]; - const auto firstUnplayedRow = std::find(visitedRows.begin(), visitedRows.end(), onlyUnplayedPatterns); - if(onlyUnplayedPatterns && firstUnplayedRow == visitedRows.end()) + const auto &visitedRows = m_visitedRows[o]; + ROWINDEX firstUnplayedRow = 0; + for(; firstUnplayedRow < visitedRows.size(); firstUnplayedRow++) + { + if(visitedRows[firstUnplayedRow] == onlyUnplayedPatterns) + break; + } + if(onlyUnplayedPatterns && firstUnplayedRow == visitedRows.size()) { // No row of this pattern has been played yet. + ord = o; row = 0; return true; } else if(!onlyUnplayedPatterns) { // Return the first unplayed row in this pattern - if(firstUnplayedRow != visitedRows.end()) + if(firstUnplayedRow < visitedRows.size()) { - row = static_cast(std::distance(visitedRows.begin(), firstUnplayedRow)); + ord = o; + row = firstUnplayedRow; return true; } - if(visitedRows.size() < m_sndFile.Patterns[order[ord]].GetNumRows()) + if(visitedRows.size() < m_sndFile.Patterns[order[o]].GetNumRows()) { // History is not fully initialized + ord = o; row = static_cast(visitedRows.size()); return true; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatBRR.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatBRR.cpp index 3f7042a62..9f448736e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatBRR.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatBRR.cpp @@ -55,9 +55,9 @@ static void ProcessBRRSample(int32 sample, int16 *output, uint8 range, uint8 fil bool CSoundFile::ReadBRRSample(SAMPLEINDEX sample, FileReader &file) { - const auto fileSize = file.GetLength(); - if(fileSize < 9 || fileSize > uint16_max) + if(!file.LengthIsAtLeast(9) || file.LengthIsAtLeast(65536)) return false; + const auto fileSize = file.GetLength(); const bool hasLoopInfo = (fileSize % 9) == 2; if((fileSize % 9) != 0 && !hasLoopInfo) return false; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatFLAC.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatFLAC.cpp index 21265fe51..d7d2a3a96 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatFLAC.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatFLAC.cpp @@ -30,6 +30,7 @@ #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" +#include "mpt/parse/parse.hpp" //#include "mpt/crc/crc.hpp" #include "OggStream.h" #ifdef MPT_WITH_OGG @@ -66,16 +67,16 @@ OPENMPT_NAMESPACE_BEGIN struct FLACDecoder { - FileReader &file; - CSoundFile &sndFile; - SAMPLEINDEX sample; - bool ready; + FileReader &m_file; + CSoundFile &m_sndFile; + const SAMPLEINDEX m_sample; + bool m_ready = false; - FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : file(f), sndFile(sf), sample(smp), ready(false) { } + FLACDecoder(FileReader &f, CSoundFile &sf, SAMPLEINDEX smp) : m_file(f), m_sndFile(sf), m_sample(smp) { } static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data) { - FileReader &file = static_cast(client_data)->file; + FileReader &file = static_cast(client_data)->m_file; if(*bytes > 0) { FileReader::off_t readBytes = *bytes; @@ -94,7 +95,7 @@ struct FLACDecoder static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data) { - FileReader &file = static_cast(client_data)->file; + FileReader &file = static_cast(client_data)->m_file; if(!file.Seek(static_cast(absolute_byte_offset))) return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; else @@ -103,30 +104,30 @@ struct FLACDecoder static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data) { - FileReader &file = static_cast(client_data)->file; + FileReader &file = static_cast(client_data)->m_file; *absolute_byte_offset = file.GetPosition(); return FLAC__STREAM_DECODER_TELL_STATUS_OK; } static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data) { - FileReader &file = static_cast(client_data)->file; + FileReader &file = static_cast(client_data)->m_file; *stream_length = file.GetLength(); return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; } static FLAC__bool eof_cb(const FLAC__StreamDecoder *, void *client_data) { - FileReader &file = static_cast(client_data)->file; + FileReader &file = static_cast(client_data)->m_file; return file.NoBytesLeft(); } static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { FLACDecoder &client = *static_cast(client_data); - ModSample &sample = client.sndFile.GetSample(client.sample); + ModSample &sample = client.m_sndFile.GetSample(client.m_sample); - if(frame->header.number.sample_number >= sample.nLength || !client.ready) + if(frame->header.number.sample_number >= sample.nLength || !client.m_ready) { // We're reading beyond the sample size already, or we aren't even ready to decode yet! return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; @@ -176,25 +177,25 @@ struct FLACDecoder static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data) { FLACDecoder &client = *static_cast(client_data); - if(client.sample > client.sndFile.GetNumSamples()) + if(client.m_sample > client.m_sndFile.GetNumSamples()) { - client.sndFile.m_nSamples = client.sample; + client.m_sndFile.m_nSamples = client.m_sample; } - ModSample &sample = client.sndFile.GetSample(client.sample); + ModSample &sample = client.m_sndFile.GetSample(client.m_sample); if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0) { // Init sample information - client.sndFile.DestroySampleThreadsafe(client.sample); - client.sndFile.m_szNames[client.sample] = ""; + client.m_sndFile.DestroySampleThreadsafe(client.m_sample); + client.m_sndFile.m_szNames[client.m_sample] = ""; sample.Initialize(); sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8); sample.uFlags.set(CHN_STEREO, metadata->data.stream_info.channels > 1); sample.nLength = mpt::saturate_cast(metadata->data.stream_info.total_samples); LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); sample.nC5Speed = metadata->data.stream_info.sample_rate; - client.ready = (sample.AllocateSample() != 0); - } else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.ready) + client.m_ready = (sample.AllocateSample() != 0); + } else if(metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4) && client.m_ready) { // Try reading RIFF loop points and other sample information FileReader data(mpt::as_span(metadata->data.application.data, metadata->length)); @@ -203,8 +204,8 @@ struct FLACDecoder // We're not really going to read a WAV file here because there will be only one RIFF chunk per metadata event, but we can still re-use the code for parsing RIFF metadata... WAVReader riffReader(data); riffReader.FindMetadataChunks(chunks); - riffReader.ApplySampleSettings(sample, client.sndFile.GetCharsetInternal(), client.sndFile.m_szNames[client.sample]); - } else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.ready) + riffReader.ApplySampleSettings(sample, client.m_sndFile.GetCharsetInternal(), client.m_sndFile.m_szNames[client.m_sample]); + } else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && client.m_ready) { // Try reading Vorbis Comments for sample title, sample rate and loop points SmpLength loopStart = 0, loopLength = 0; @@ -214,17 +215,17 @@ struct FLACDecoder const FLAC__uint32 length = metadata->data.vorbis_comment.comments[i].length; if(length > 6 && !mpt::CompareNoCaseAscii(tag, "TITLE=", 6)) { - client.sndFile.m_szNames[client.sample] = mpt::ToCharset(client.sndFile.GetCharsetInternal(), mpt::Charset::UTF8, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, tag + 6, length - 6)); + client.m_sndFile.m_szNames[client.m_sample] = mpt::ToCharset(client.m_sndFile.GetCharsetInternal(), mpt::Charset::UTF8, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, tag + 6, length - 6)); } else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "SAMPLERATE=", 11)) { - uint32 sampleRate = ConvertStrTo(tag + 11); + uint32 sampleRate = mpt::parse(tag + 11); if(sampleRate > 0) sample.nC5Speed = sampleRate; } else if(length > 10 && !mpt::CompareNoCaseAscii(tag, "LOOPSTART=", 10)) { - loopStart = ConvertStrTo(tag + 10); + loopStart = mpt::parse(tag + 10); } else if(length > 11 && !mpt::CompareNoCaseAscii(tag, "LOOPLENGTH=", 11)) { - loopLength = ConvertStrTo(tag + 11); + loopLength = mpt::parse(tag + 11); } } if(loopLength > 0) @@ -458,7 +459,7 @@ bool CSoundFile::ReadFLACSample(SAMPLEINDEX sample, FileReader &file) FLAC__stream_decoder_finish(decoder); FLAC__stream_decoder_delete(decoder); - if(client.ready && Samples[sample].HasSampleData()) + if(client.m_ready && Samples[sample].HasSampleData()) { Samples[sample].Convert(MOD_TYPE_IT, GetType()); Samples[sample].PrecomputeLoops(*this, false); @@ -490,7 +491,7 @@ struct FLAC__StreamEncoder_RAII static FLAC__StreamEncoderWriteStatus StreamEncoderWriteCallback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data) { - mpt::ofstream & file = *reinterpret_cast(client_data); + mpt::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); MPT_UNUSED_VARIABLE(samples); MPT_UNUSED_VARIABLE(current_frame); @@ -502,7 +503,7 @@ struct FLAC__StreamEncoder_RAII } static FLAC__StreamEncoderSeekStatus StreamEncoderSeekCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) { - mpt::ofstream & file = *reinterpret_cast(client_data); + mpt::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); if(!mpt::in_range(absolute_byte_offset)) { @@ -516,7 +517,7 @@ struct FLAC__StreamEncoder_RAII } static FLAC__StreamEncoderTellStatus StreamEncoderTellCallback(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { - mpt::ofstream & file = *reinterpret_cast(client_data); + mpt::ofstream & file = *mpt::void_ptr(client_data); MPT_UNUSED_VARIABLE(encoder); mpt::IO::Offset pos = mpt::IO::TellWrite(file); if(pos < 0) @@ -586,7 +587,7 @@ bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false); if(sampleRate > FLAC__MAX_SAMPLE_RATE) { - // FLAC only supports a sample rate of up to 655350 Hz. + // FLAC only supports a sample rate of up to 1048575 Hz. // Store the real sample rate in a custom Vorbis comment. FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "SAMPLERATE", mpt::afmt::val(sampleRate).c_str()); FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, false); @@ -672,12 +673,12 @@ bool CSoundFile::SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const numBlocks++; } - // FLAC allows a maximum sample rate of 655350 Hz. + // FLAC allows a maximum sample rate of 1048575 Hz. // If the real rate is higher, we store it in a Vorbis comment above. LimitMax(sampleRate, FLAC__MAX_SAMPLE_RATE); if(!FLAC__format_sample_rate_is_subset(sampleRate)) { - // FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen. + // FLAC only supports 10 Hz granularity for frequencies above 65535 Hz if the streamable subset is chosen, and only a maximum frequency of 655350 Hz. FLAC__stream_encoder_set_streamable_subset(encoder, false); } FLAC__stream_encoder_set_channels(encoder, sample.GetNumChannels()); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp index a290a1eae..efeccd090 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMP3.cpp @@ -66,17 +66,17 @@ OPENMPT_NAMESPACE_BEGIN #if defined(MPT_WITH_MPG123) -typedef off_t mpg123_off_t; +using mpg123_off_t = off_t; -typedef size_t mpg123_size_t; +using mpg123_size_t = size_t; // Check for exactly _MSC_VER as libmpg123 does, in order to also catch clang-cl. #ifdef _MSC_VER // ssize_t definition in libmpg123.h.in should never have existed at all. // It got removed from libmpg23.h.in after 1.28.0 and before 1.28.1. -typedef ptrdiff_t mpg123_ssize_t; +using mpg123_ssize_t = ptrdiff_t; #else -typedef ssize_t mpg123_ssize_t; +using mpg123_ssize_t = ssize_t; #endif class ComponentMPG123 @@ -598,7 +598,7 @@ bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw, b { m_szNames[sample] = mpt::ToCharset(GetCharsetInternal(), sampleName); Samples[sample].Initialize(); - Samples[sample].nC5Speed = rate; + Samples[sample].nC5Speed = static_cast(rate); } Samples[sample].nLength = mpt::saturate_cast((data.size() / channels) - data_skip_frames); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMediaFoundation.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMediaFoundation.cpp index 07348ec0c..10cd0b7dd 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMediaFoundation.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatMediaFoundation.cpp @@ -23,6 +23,9 @@ #include "../soundlib/ModSampleCopy.h" #include "../common/ComponentManager.h" #if defined(MPT_WITH_MEDIAFOUNDATION) +#include "mpt/io_file_adapter/fileadapter.hpp" +#include "../common/FileReader.h" +#include "../common/mptFileTemporary.h" #include #include #include @@ -31,6 +34,7 @@ #include #include #endif // MPT_WITH_MEDIAFOUNDATION +#include "mpt/string/utility.hpp" OPENMPT_NAMESPACE_BEGIN @@ -304,7 +308,7 @@ bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, // When using MF to decode MP3 samples in MO3 files, we need the mp3 file extension // for some of them or otherwise MF refuses to recognize them. mpt::PathString tmpfileExtension = (mo3Decode ? P_("mp3") : P_("tmp")); - OnDiskFileWrapper diskfile(file, tmpfileExtension); + mpt::IO::FileAdapter diskfile(file, mpt::TemporaryPathname{tmpfileExtension}.GetPathname()); if(!diskfile.IsValid()) { return false; @@ -322,7 +326,7 @@ bool CSoundFile::ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, MPT_MF_CHECKED(MFCreateSourceResolver(&sourceResolver)); MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID; CComPtr unknownMediaSource; - MPT_MF_CHECKED(sourceResolver->CreateObjectFromURL(diskfile.GetFilename().ToWide().c_str(), MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, NULL, &objectType, &unknownMediaSource)); + MPT_MF_CHECKED(sourceResolver->CreateObjectFromURL(mpt::ToWide(diskfile.GetFilename()).c_str(), MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE | MF_RESOLUTION_READ, NULL, &objectType, &unknownMediaSource)); if(objectType != MF_OBJECT_MEDIASOURCE) { return false; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatOpus.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatOpus.cpp index 9a6f3f923..0d8341072 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatOpus.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatOpus.cpp @@ -45,6 +45,77 @@ OPENMPT_NAMESPACE_BEGIN #if defined(MPT_WITH_OPUSFILE) +static int OpusfileFilereaderRead(void *stream, unsigned char *ptr, int nbytes) +{ + FileReader &file = *mpt::void_ptr(stream); + return mpt::saturate_cast(file.ReadRaw(mpt::span(mpt::byte_cast(ptr), nbytes)).size()); +} + +static int OpusfileFilereaderSeek(void *stream, opus_int64 offset, int whence) +{ + FileReader &file = *mpt::void_ptr(stream); + switch(whence) + { + case SEEK_SET: + { + if(!mpt::in_range(offset)) + { + return -1; + } + return file.Seek(mpt::saturate_cast(offset)) ? 0 : -1; + } + break; + case SEEK_CUR: + { + if(offset < 0) + { + if(offset == std::numeric_limits::min()) + { + return -1; + } + if(!mpt::in_range(0-offset)) + { + return -1; + } + return file.SkipBack(mpt::saturate_cast(0 - offset)) ? 0 : -1; + } else + { + if(!mpt::in_range(offset)) + { + return -1; + } + return file.Skip(mpt::saturate_cast(offset)) ? 0 : -1; + } + } + break; + case SEEK_END: + { + if(!mpt::in_range(offset)) + { + return -1; + } + if(!mpt::in_range(file.GetLength() + offset)) + { + return -1; + } + return file.Seek(mpt::saturate_cast(file.GetLength() + offset)) ? 0 : -1; + } + break; + default: + return -1; + } +} + +static opus_int64 OpusfileFilereaderTell(void *stream) +{ + FileReader &file = *mpt::void_ptr(stream); + MPT_MAYBE_CONSTANT_IF(!mpt::in_range(file.GetPosition())) + { + return -1; + } + return static_cast(file.GetPosition()); +} + static mpt::ustring UStringFromOpus(const char *str) { return str ? mpt::ToUnicode(mpt::Charset::UTF8, str) : mpt::ustring(); @@ -83,15 +154,20 @@ bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file) int channels = 0; std::vector raw_sample_data; - std::string sampleName; - - FileReader initial = file.GetChunk(65536); // 512 is recommended by libopusfile - if(op_test(NULL, initial.GetRawData().data(), initial.GetLength()) != 0) { - return false; + FileReader::PinnedView initial = file.GetPinnedView(65536); // 512 is recommended by libopusfile + if(op_test(NULL, mpt::byte_cast(initial.data()), initial.size()) != 0) + { + return false; + } } - OggOpusFile *of = op_open_memory(file.GetRawData().data(), file.GetLength(), NULL); + OpusFileCallbacks callbacks = {}; + callbacks.read = &OpusfileFilereaderRead; + callbacks.seek = &OpusfileFilereaderSeek; + callbacks.tell = &OpusfileFilereaderTell; + callbacks.close = NULL; + OggOpusFile *of = op_open_callbacks(mpt::void_ptr(&file), &callbacks, NULL, 0, NULL); if(!of) { return false; @@ -114,7 +190,7 @@ bool CSoundFile::ReadOpusSample(SAMPLEINDEX sample, FileReader &file) channels = 2; } - sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetOpusFileTags(of))); + std::string sampleName = mpt::ToCharset(GetCharsetInternal(), GetSampleNameFromTags(GetOpusFileTags(of))); if(auto length = op_pcm_total(of, 0); length != OP_EINVAL) raw_sample_data.reserve(std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(length)) * channels); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp index a59b1931f..a2e15c986 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatSFZ.cpp @@ -12,12 +12,20 @@ #include "Sndfile.h" #ifdef MODPLUG_TRACKER #include "../mptrack/TrackerSettings.h" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" +#include "../common/mptFileIO.h" #endif // MODPLUG_TRACKER #ifndef MODPLUG_NO_FILESAVE +#include "mpt/io_file/outputfile.hpp" #include "../common/mptFileIO.h" +#ifdef MODPLUG_TRACKER +#include "mpt/fs/fs.hpp" +#endif // MODPLUG_TRACKER #endif // !MODPLUG_NO_FILESAVE #include "modsmp_ctrl.h" #include "mpt/base/numbers.hpp" +#include "mpt/parse/parse.hpp" #include @@ -52,9 +60,9 @@ struct SFZControl if(key == "default_path") defaultPath = value; else if(key == "octave_offset") - octaveOffset = ConvertStrTo(value); + octaveOffset = mpt::parse(value); else if(key == "note_offset") - noteOffset = ConvertStrTo(value); + noteOffset = mpt::parse(value); } }; @@ -72,7 +80,7 @@ struct SFZFlexEG void Parse(std::string_view key, const std::string &value) { key = key.substr(key.find('_') + 1); - const double v = ConvertStrTo(value); + const double v = mpt::parse(value); const bool isTime = SFZStartsWith(key, "time"), isLevel = SFZStartsWith(key, "level"); std::string_view pointStr; @@ -83,7 +91,7 @@ struct SFZFlexEG if(!pointStr.empty() && SFZIsNumeric(pointStr)) { - PointIndex point = ConvertStrTo(std::string(pointStr)); + PointIndex point = mpt::parse(std::string(pointStr)); if(point >= points.size() && point < MAX_ENVPOINTS) points.resize(point + 1); @@ -182,16 +190,16 @@ protected: static EnvelopeNode::value_t ToValue(double value, double scale, double minVal, double maxVal, const std::function &conversionFunc) { - value = conversionFunc((value * scale - minVal) / (maxVal - minVal)) * ENVELOPE_MAX + ENVELOPE_MIN; - Limit(value, ENVELOPE_MIN, ENVELOPE_MAX); + value = conversionFunc((value * scale - minVal) / (maxVal - minVal)) * double(ENVELOPE_MAX) + double(ENVELOPE_MIN); + Limit(value, double(ENVELOPE_MIN), double(ENVELOPE_MAX)); return mpt::saturate_round(value); } static double Identity(double v) noexcept { return v; } - static double CentsToFilterCutoff(double v, const CSoundFile &sndFile, int envBaseCutoff, uint32 envBaseFreq) + static double CentsToFilterCutoff(double v, const CSoundFile &sndFile, int envBaseCutoff, float envBaseFreq) { - const auto freq = envBaseFreq * std::pow(2.0, v / 1200.0); + const auto freq = static_cast(envBaseFreq) * std::pow(2.0, v / 1200.0); return Util::muldivr(sndFile.FrequencyToCutOff(freq), 127, envBaseCutoff) / 127.0; } @@ -211,7 +219,7 @@ struct SFZEnvelope void Parse(std::string_view key, const std::string &value) { key = key.substr(key.find('_') + 1); - double v = ConvertStrTo(value); + double v = mpt::parse(value); if(key == "depth") Limit(v, -12000.0, 12000.0); else if(key == "start" || key == "sustain") @@ -328,7 +336,7 @@ struct SFZRegion template static void Read(const std::string &valueStr, T &value, Tc valueMin = std::numeric_limits::min(), Tc valueMax = std::numeric_limits::max()) { - double valueF = ConvertStrTo(valueStr); + double valueF = mpt::parse(valueStr); if constexpr(std::numeric_limits::is_integer) { valueF = mpt::round(valueF); @@ -346,7 +354,7 @@ struct SFZRegion if(value[0] >= '0' && value[0] <= '9') { // MIDI key - key = ConvertStrTo(value); + key = mpt::parse(value); } else if(value.length() < 2) { return 0; @@ -376,7 +384,7 @@ struct SFZRegion if(octaveOffset >= value.length()) return 0; - int8 octave = ConvertStrTo(value.c_str() + octaveOffset); + int8 octave = mpt::parse(value.c_str() + octaveOffset); key += (octave + 1) * 12; } key += control.octaveOffset * 12 + control.noteOffset; @@ -480,7 +488,7 @@ struct SFZRegion pitchEnv.Parse(key, value); else if(SFZStartsWith(key, "eg") && SFZIsNumeric(key.substr(2, 2)) && key.substr(4, 1) == "_") { - uint8 eg = ConvertStrTo(std::string(key.substr(2, 2))); + uint8 eg = mpt::parse(std::string(key.substr(2, 2))); if(eg >= flexEGs.size()) flexEGs.resize(eg + 1); flexEGs[eg].Parse(key, value); @@ -491,10 +499,10 @@ struct SFZRegion struct SFZInputFile { FileReader file; - std::unique_ptr inputFile; // FileReader has pointers into this so its address must not change + std::unique_ptr inputFile; // FileReader has pointers into this so its address must not change std::string remain; - SFZInputFile(FileReader f = {}, std::unique_ptr i = {}, std::string r = {}) + SFZInputFile(FileReader f = {}, std::unique_ptr i = {}, std::string r = {}) : file{std::move(f)}, inputFile{std::move(i)}, remain{std::move(r)} {} SFZInputFile(SFZInputFile &&) = default; }; @@ -647,12 +655,12 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) if(!filename.empty()) { if(filenameU8.find(':') == std::string::npos) - filename = file.GetOptionalFileName().value_or(P_("")).GetPath() + filename; + filename = file.GetOptionalFileName().value_or(P_("")).GetDirectoryWithDrive() + filename; filename = filename.Simplify(); // Avoid recursive #include if(std::find_if(files.begin(), files.end(), [&filename](const SFZInputFile &f) { return f.file.GetOptionalFileName().value_or(P_("")) == filename; }) == files.end()) { - auto f = std::make_unique(filename); + auto f = std::make_unique(filename); if(f->IsValid()) { s.erase(0, charsRead); @@ -814,11 +822,11 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { if(region.filename.find(':') == std::string::npos) { - filename = file.GetOptionalFileName().value_or(P_("")).GetPath() + filename; + filename = file.GetOptionalFileName().value_or(P_("")).GetDirectoryWithDrive() + filename; } filename = filename.Simplify(); SetSamplePath(smp, filename); - InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); FileReader smpFile = GetFileReader(f); if(!ReadSampleFromFile(smp, smpFile, false)) { @@ -836,7 +844,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) if(!region.name.empty()) m_szNames[smp] = mpt::ToCharset(GetCharsetInternal(), mpt::Charset::UTF8, region.name); if(!m_szNames[smp][0]) - m_szNames[smp] = mpt::ToCharset(GetCharsetInternal(), mpt::PathString::FromUTF8(region.filename).GetFileName().ToUnicode()); + m_szNames[smp] = mpt::ToCharset(GetCharsetInternal(), mpt::PathString::FromUTF8(region.filename).GetFilenameBase().ToUnicode()); if(region.useSampleKeyRoot) { @@ -1004,7 +1012,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file) // Avoid ruining the original samples if(auto filename = GetSamplePath(smp); !filename.empty()) { - filename = filename.GetPath() + filename.GetFileName() + filenameModifier + filename.GetFileExt(); + filename = filename.GetDirectoryWithDrive() + filename.GetFilenameBase() + filenameModifier + filename.GetFilenameExtension(); SetSamplePath(smp, filename); } } @@ -1065,9 +1073,9 @@ static void WriteSFZEnvelope(std::ostream &f, double tickDuration, int index, co bool CSoundFile::SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool useFLACsamples) const { #ifdef MODPLUG_TRACKER - const mpt::FlushMode flushMode = mpt::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave); + const mpt::IO::FlushMode flushMode = mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave); #else - const mpt::FlushMode flushMode = mpt::FlushMode::Full; + const mpt::IO::FlushMode flushMode = mpt::IO::FlushMode::Full; #endif const ModInstrument *ins = Instruments[nInstr]; if(ins == nullptr) @@ -1075,10 +1083,10 @@ bool CSoundFile::SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, cons // Creating directory names with trailing spaces or dots is a bad idea, as they are difficult to remove in Windows. const mpt::RawPathString whitespaceDirName = PL_(" \n\r\t."); - const mpt::PathString sampleBaseName = mpt::PathString::FromNative(mpt::trim(filename.GetFileName().AsNative(), whitespaceDirName)); + const mpt::PathString sampleBaseName = mpt::PathString::FromNative(mpt::trim(filename.GetFilenameBase().AsNative(), whitespaceDirName)); const mpt::PathString sampleDirName = (sampleBaseName.empty() ? P_("Samples") : sampleBaseName) + P_("/"); - const mpt::PathString sampleBasePath = filename.GetPath() + sampleDirName; - if(!sampleBasePath.IsDirectory() && !::CreateDirectory(sampleBasePath.AsNative().c_str(), nullptr)) + const mpt::PathString sampleBasePath = filename.GetDirectoryWithDrive() + sampleDirName; + if(!mpt::native_fs{}.is_directory(sampleBasePath) && !::CreateDirectory(sampleBasePath.AsNative().c_str(), nullptr)) return false; const double tickDuration = m_PlayState.m_nSamplesPerTick / static_cast(m_MixerSettings.gdwMixingFreq); @@ -1183,10 +1191,10 @@ bool CSoundFile::SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, cons bool success = false; try { - mpt::SafeOutputFile sfSmp(sampleName, std::ios::binary, flushMode); + mpt::IO::SafeOutputFile sfSmp(sampleName, std::ios::binary, flushMode); if(sfSmp) { - mpt::ofstream &fSmp = sfSmp; + mpt::IO::ofstream &fSmp = sfSmp; fSmp.exceptions(fSmp.exceptions() | std::ios::badbit | std::ios::failbit); if(isAdlib) @@ -1211,7 +1219,7 @@ bool CSoundFile::SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, cons { f << "\nregion_label=" << mpt::ToCharset(mpt::Charset::UTF8, GetCharsetInternal(), m_szNames[ins->Keyboard[i]]); } - f << "\nsample=" << sampleName.GetFullFileName().ToUTF8(); + f << "\nsample=" << sampleName.GetFilename().ToUTF8(); f << "\nlokey=" << i; f << "\nhikey=" << endOfRegion; if(sample.rootNote != NOTE_NONE) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatVorbis.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatVorbis.cpp index 74a3cb1d5..794715c6f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatVorbis.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormatVorbis.cpp @@ -68,13 +68,13 @@ OPENMPT_NAMESPACE_BEGIN static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource) { - FileReader &file = *static_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); return file.ReadRaw(mpt::span(mpt::void_cast(ptr), size * nmemb)).size() / size; } static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence) { - FileReader &file = *static_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); switch(whence) { case SEEK_SET: @@ -129,7 +129,7 @@ static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int wh static long VorbisfileFilereaderTell(void *datasource) { - FileReader &file = *static_cast(datasource); + FileReader &file = *mpt::void_ptr(datasource); MPT_MAYBE_CONSTANT_IF(!mpt::in_range(file.GetPosition())) { return -1; @@ -178,7 +178,7 @@ bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file) file.Rewind(); - int rate = 0; + long rate = 0; int channels = 0; std::vector raw_sample_data; @@ -198,7 +198,7 @@ bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file) }; OggVorbis_File vf; MemsetZero(vf); - if(ov_open_callbacks(&file, &vf, NULL, 0, callbacks) == 0) + if(ov_open_callbacks(mpt::void_ptr(&file), &vf, NULL, 0, callbacks) == 0) { if(ov_streams(&vf) == 1) { // we do not support chained vorbis samples @@ -325,7 +325,7 @@ bool CSoundFile::ReadVorbisSample(SAMPLEINDEX sample, FileReader &file) DestroySampleThreadsafe(sample); ModSample &mptSample = Samples[sample]; mptSample.Initialize(); - mptSample.nC5Speed = rate; + mptSample.nC5Speed = static_cast(rate); mptSample.nLength = std::min(MAX_SAMPLE_LENGTH, mpt::saturate_cast(raw_sample_data.size() / channels)); mptSample.uFlags.set(CHN_16BIT); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp index df5d14785..bc682d358 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleFormats.cpp @@ -16,6 +16,7 @@ #include "Dlsbank.h" #endif // MODPLUG_TRACKER #include "../soundlib/AudioCriticalSection.h" +#include "mpt/format/join.hpp" #ifndef MODPLUG_NO_FILESAVE #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" @@ -33,6 +34,7 @@ #include "Loaders.h" #include "../common/FileReader.h" #include "../soundlib/ModSampleCopy.h" +#include "mpt/string/utility.hpp" #include #include @@ -231,9 +233,9 @@ bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoun Instruments[targetInstr] = pIns; *pIns = *srcSong.Instruments[sourceInstr]; - std::vector sourceSample; // Sample index in source song - std::vector targetSample; // Sample index in target song - SAMPLEINDEX targetIndex = 0; // Next index for inserting sample + std::vector sourceSample; // Sample index in source song + std::vector targetSample; // Sample index in target song + SAMPLEINDEX targetIndex = 0; // Next index for inserting sample for(auto &sample : pIns->Keyboard) { @@ -269,7 +271,7 @@ bool CSoundFile::ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoun #ifdef MODPLUG_TRACKER if(pIns->filename.empty() && srcSong.GetpModDoc() != nullptr && &srcSong != this) { - pIns->filename = srcSong.GetpModDoc()->GetPathNameMpt().GetFullFileName().ToLocale(); + pIns->filename = srcSong.GetpModDoc()->GetPathNameMpt().GetFilename().ToLocale(); } #endif pIns->Convert(srcSong.GetType(), GetType()); @@ -546,18 +548,18 @@ bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, std::ostream &f) const return false; mpt::IO::OFile ff(f); - WAVWriter file(ff); + WAVSampleWriter file(ff); file.WriteFormat(sample.GetSampleRate(GetType()), sample.GetElementarySampleSize() * 8, sample.GetNumChannels(), WAVFormatChunk::fmtPCM); // Write sample data file.StartChunk(RIFFChunk::iddata); - file.Skip(SampleIO( + SampleIO( sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, sample.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, sample.uFlags[CHN_16BIT] ? SampleIO::signedPCM : SampleIO::unsignedPCM) - .WriteSample(f, sample)); + .WriteSample(f, sample); file.WriteLoopInformation(sample); file.WriteExtraInformation(sample, GetType()); @@ -567,7 +569,7 @@ bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, std::ostream &f) const } FileTags tags; - tags.SetEncoder(); + tags.encoder = Version::Current().GetOpenMPTVersionString(); tags.title = mpt::ToUnicode(GetCharsetInternal(), m_szNames[nSample]); file.WriteMetatags(tags); file.Finalize(); @@ -910,10 +912,10 @@ MPT_BINARY_STRUCT(GF1SampleHeader, 96) // ---------------------------- | | | | | | // <---> attack rate 0 0 1 2 3 4 5 amplitudes // <----> attack rate 1 -// <> attack rate 2 -// <--> attack rate 3 -// <> attack rate 4 -// <-----> attack rate 5 +// <> attack rate 2 +// <--> attack rate 3 +// <> attack rate 4 +// <-----> attack rate 5 // // -- GF1 Flags -- // @@ -929,10 +931,10 @@ MPT_BINARY_STRUCT(GF1SampleHeader, 96) struct GF1Layer { - uint8le previous; // If !=0 the wavesample to use is from the previous layer. The waveheader is still needed - uint8le id; // Layer id: 0-3 - uint32le size; // data size in bytes in the layer, without the header. to skip to next layer for example: - uint8le samples; // number of wavesamples + uint8le previous; // If !=0 the wavesample to use is from the previous layer. The waveheader is still needed + uint8le id; // Layer id: 0-3 + uint32le size; // data size in bytes in the layer, without the header. to skip to next layer for example: + uint8le samples; // number of wavesamples char reserved[40]; }; @@ -941,7 +943,7 @@ MPT_BINARY_STRUCT(GF1Layer, 47) static double PatchFreqToNote(uint32 nFreq) { - return std::log(nFreq / 2044.0) * (12.0 * 1.44269504088896340736); // 1.0/std::log(2.0) + return std::log(nFreq / 2044.0) * (12.0 * 1.44269504088896340736); // 1.0/std::log(2.0) } @@ -965,7 +967,7 @@ static void PatchToSample(CSoundFile *that, SAMPLEINDEX nSample, GF1SampleHeader sample.nLoopStart = sampleHeader.loopstart; sample.nLoopEnd = sampleHeader.loopend; sample.nC5Speed = sampleHeader.freq; - sample.nPan = (sampleHeader.balance * 256 + 8) / 15; + sample.nPan = static_cast((sampleHeader.balance * 256 + 8) / 15); if(sample.nPan > 256) sample.nPan = 128; else sample.uFlags.set(CHN_PANNING); sample.nVibType = VIB_SINE; @@ -1002,7 +1004,7 @@ bool CSoundFile::ReadPATSample(SAMPLEINDEX nSample, FileReader &file) { file.Rewind(); GF1PatchFileHeader fileHeader; - GF1Instrument instrHeader; // We only support one instrument + GF1Instrument instrHeader; // We only support one instrument GF1Layer layerHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.magic, "GF1PATCH", 8) @@ -1010,7 +1012,7 @@ bool CSoundFile::ReadPATSample(SAMPLEINDEX nSample, FileReader &file) || memcmp(fileHeader.id, "ID#000002\0", 10) || !fileHeader.numInstr || !fileHeader.numSamples || !file.ReadStruct(instrHeader) - //|| !instrHeader.layers // DOO.PAT has 0 layers + //|| !instrHeader.layers // DOO.PAT has 0 layers || !file.ReadStruct(layerHeader) || !layerHeader.samples) { @@ -1034,7 +1036,7 @@ bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file) { file.Rewind(); GF1PatchFileHeader fileHeader; - GF1Instrument instrHeader; // We only support one instrument + GF1Instrument instrHeader; // We only support one instrument GF1Layer layerHeader; if(!file.ReadStruct(fileHeader) || memcmp(fileHeader.magic, "GF1PATCH", 8) @@ -1042,7 +1044,7 @@ bool CSoundFile::ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file) || memcmp(fileHeader.id, "ID#000002\0", 10) || !fileHeader.numInstr || !fileHeader.numSamples || !file.ReadStruct(instrHeader) - //|| !instrHeader.layers // DOO.PAT has 0 layers + //|| !instrHeader.layers // DOO.PAT has 0 layers || !file.ReadStruct(layerHeader) || !layerHeader.samples) { @@ -1412,7 +1414,7 @@ bool CSoundFile::ReadXISample(SAMPLEINDEX nSample, FileReader &file) uint16 numSamples = fileHeader.numSamples; FileReader::off_t samplePos = sizeof(XIInstrumentHeader) + numSamples * sizeof(XMSample); - // Preferrably read the middle-C sample + // Preferably read the middle-C sample auto sample = fileHeader.instrument.sampleMap[48]; if(sample >= fileHeader.numSamples) sample = 0; @@ -1489,11 +1491,11 @@ struct CAFChunk int64 length = header.mChunkSize; if(length == -1) { - length = std::numeric_limits::max(); // spec + length = std::numeric_limits::max(); // spec } if(length < 0) { - length = std::numeric_limits::max(); // heuristic + length = std::numeric_limits::max(); // heuristic } return mpt::saturate_cast(length); } @@ -1765,9 +1767,9 @@ bool CSoundFile::ReadCAFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNo // AIFF header struct AIFFHeader { - char magic[4]; // FORM - uint32be length; // Size of the file, not including magic and length - char type[4]; // AIFF or AIFC + char magic[4]; // FORM + uint32be length; // Size of the file, not including magic and length + char type[4]; // AIFF or AIFC }; MPT_BINARY_STRUCT(AIFFHeader, 12) @@ -1786,8 +1788,8 @@ struct AIFFChunk idNAME = MagicBE("NAME"), }; - uint32be id; // See ChunkIdentifiers - uint32be length; // Chunk size without header + uint32be id; // See ChunkIdentifiers + uint32be length; // Chunk size without header size_t GetLength() const { @@ -1809,7 +1811,7 @@ struct AIFFCommonChunk uint16be numChannels; uint32be numSampleFrames; uint16be sampleSize; - uint8be sampleRate[10]; // Sample rate in 80-Bit floating point + uint8be sampleRate[10]; // Sample rate in 80-Bit floating point // Convert sample rate to integer uint32 GetSampleRate() const @@ -1845,8 +1847,8 @@ MPT_BINARY_STRUCT(AIFFSoundChunk, 8) struct AIFFMarker { uint16be id; - uint32be position; // Position in sample - uint8be nameLength; // Not counting eventually existing padding byte in name string + uint32be position; // Position in sample + uint8be nameLength; // Not counting eventually existing padding byte in name string }; MPT_BINARY_STRUCT(AIFFMarker, 7) @@ -1857,14 +1859,14 @@ struct AIFFInstrumentLoop { enum PlayModes { - noLoop = 0, - loopNormal = 1, - loopBidi = 2, + noLoop = 0, + loopNormal = 1, + loopBidi = 2, }; uint16be playMode; - uint16be beginLoop; // Marker index - uint16be endLoop; // Marker index + uint16be beginLoop; // Marker index + uint16be endLoop; // Marker index }; MPT_BINARY_STRUCT(AIFFInstrumentLoop, 6) @@ -2162,7 +2164,7 @@ bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNor annotation = mpt::replace(annotation, std::string("\r\n"), std::string("\n")); annotation = mpt::replace(annotation, std::string("\r"), std::string("\n")); mpt::Charset charset = mpt::IsUTF8(annotation) ? mpt::Charset::UTF8 : mpt::Charset::ISO8859_1; - const auto lines = mpt::String::Split(annotation, "\n"); + const auto lines = mpt::split(annotation, std::string("\n")); bool hasFields = false; for(const auto &line : lines) { @@ -2184,12 +2186,12 @@ bool CSoundFile::ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNor } linesPerField[lastField].push_back(AUTrimFieldFromAnnotationLine(line)); } - tags.title = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["title" ], std::string("\n"))); - tags.artist = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["artist" ], std::string("\n"))); - tags.album = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["album" ], std::string("\n"))); - tags.trackno = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["track" ], std::string("\n"))); - tags.genre = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["genre" ], std::string("\n"))); - tags.comments = mpt::ToUnicode(charset, mpt::String::Combine(linesPerField["comment"], std::string("\n"))); + tags.title = mpt::ToUnicode(charset, mpt::join_format(linesPerField["title" ], std::string("\n"))); + tags.artist = mpt::ToUnicode(charset, mpt::join_format(linesPerField["artist" ], std::string("\n"))); + tags.album = mpt::ToUnicode(charset, mpt::join_format(linesPerField["album" ], std::string("\n"))); + tags.trackno = mpt::ToUnicode(charset, mpt::join_format(linesPerField["track" ], std::string("\n"))); + tags.genre = mpt::ToUnicode(charset, mpt::join_format(linesPerField["genre" ], std::string("\n"))); + tags.comments = mpt::ToUnicode(charset, mpt::join_format(linesPerField["comment"], std::string("\n"))); } else { // Most applications tend to write their own name here, @@ -2273,7 +2275,7 @@ bool CSoundFile::ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewin { if(file.GetOptionalFileName()) { - filename = filename.RelativePathToAbsolute(file.GetOptionalFileName()->GetPath()); + filename = mpt::RelativePathToAbsolute(filename, file.GetOptionalFileName()->GetDirectoryWithDrive()); } if(!LoadExternalSample(nSample, filename)) { @@ -2312,7 +2314,7 @@ bool CSoundFile::ReadITISample(SAMPLEINDEX nSample, FileReader &file) if(!nsamples) return false; - // Preferrably read the middle-C sample + // Preferably read the middle-C sample auto sample = dummy.Keyboard[NOTE_MIDDLEC - NOTE_MIN]; if(sample > 0) sample--; @@ -2453,7 +2455,7 @@ bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, cons } else { #ifdef MPT_EXTERNAL_SAMPLES - const std::string filenameU8 = GetSamplePath(smp).AbsolutePathToRelative(filename.GetPath()).ToUTF8(); + const std::string filenameU8 = mpt::AbsolutePathToRelative(GetSamplePath(smp), filename.GetDirectoryWithDrive()).ToUTF8(); const size_t strSize = filenameU8.size(); size_t intBytes = 0; if(mpt::IO::WriteVarInt(f, strSize, &intBytes)) @@ -2507,6 +2509,7 @@ struct IFFChunk idMDAT = MagicBE("MDAT"), idNAME = MagicBE("NAME"), + idANNO = MagicBE("ANNO"), }; uint32be id; // See ChunkIdentifiers @@ -2542,7 +2545,7 @@ struct IFFSampleHeader MPT_BINARY_STRUCT(IFFSampleHeader, 20) -bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) +bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file, bool allowLittleEndian) { file.Rewind(); @@ -2612,14 +2615,24 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) const uint8 numChannels = chanChunk.ReadUint32BE() == 6 ? 2 : 1; const uint8 bytesPerFrame = bytesPerSample * numChannels; - // While this is an Amiga format, the 16SV version appears to be only used on PC, and only with little-endian sample data. if(bytesPerSample == 2) - sampleIO = SampleIO(SampleIO::_16bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM); + sampleIO |= SampleIO::_16bit; if(numChannels == 2) sampleIO |= SampleIO::stereoSplit; loopStart = sampleHeader.oneShotHiSamples / bytesPerFrame; - loopLength = sampleHeader.repeatHiSamples / bytesPerFrame; + // Loops are a complicated mess in IFF samples. + // Some samples (e.g. those from the Ensoniq Mirage for Amiga collection available at https://archive.org/details/mirage4amiga) + // have a repeatHiSamples portion that includes garbage. However, these samples also have an appropriate samplesPerHiCycle value set + // which indicates the length of one cycle of the repeating waveform. If we just take that one cycle into account, the samples loop cleanly. + // However, some other, non-musical 8SVX samples use bogus samplesPerHiCycle values. The following conditions help us spot this sort of samples: + // - If samplesPerHiCycle is 32 or lower, we simply ignore it. + // - According to the documentation, repeatHiSamples is intended to be a multiple of samplesPerHiCycle if the latter is set (otherwise we wouldn't get a clean loop). + // So if this is not the case, we ignore samplesPerHiCycle and only use repeatHiSamples. + if(sampleHeader.samplesPerHiCycle > 32 && sampleHeader.samplesPerHiCycle < sampleHeader.repeatHiSamples && (sampleHeader.repeatHiSamples % sampleHeader.samplesPerHiCycle) == 0) + loopLength = sampleHeader.samplesPerHiCycle / bytesPerFrame; + else + loopLength = sampleHeader.repeatHiSamples / bytesPerFrame; sampleRate = sampleHeader.samplesPerSec; volume = sampleHeader.volume; numSamples = mpt::saturate_cast(sampleData.GetLength() / bytesPerFrame); @@ -2635,10 +2648,10 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) sample.uFlags.set(CHN_LOOP); sample.nC5Speed = sampleRate; - if(!sample.nC5Speed) + if(sample.nC5Speed <= 1) sample.nC5Speed = 22050; - sample.nVolume = static_cast(volume / 256); + sample.nVolume = static_cast((volume + 128) / 256); if(!sample.nVolume || sample.nVolume > 256) sample.nVolume = 256; @@ -2651,10 +2664,165 @@ bool CSoundFile::ReadIFFSample(SAMPLEINDEX nSample, FileReader &file) m_szNames[nSample] = ""; sampleIO.ReadSample(sample, sampleData); + + if(allowLittleEndian && !memcmp(fileHeader.magic, "16SV", 4)) + { + // Fasttracker 2 (and also Awave Studio up to version 11.7) writes little-endian 16-bit data. Great... + // It is relatively safe to assume (see raw sample import dialog) that "proper" sample data usually has some smoothness to it, + // i.e. its first derivative mostly consists of small-ish values. + // When interpreting the sample data with incorrect endianness, however, the first derivative is usually a lot more jumpy. + // So we compare the two derivatives when interpreting the data as little-endian and big-endian, + // and choose the waveform that has less jumps in it. + // Sample data is normalized for those comparisons, otherwise 8-bit data converted to 16-bit will almost always be more optimal + // when byte-swapped (as the upper byte is always 0). + const uint8 numChannels = sample.GetNumChannels(); + auto sample16 = mpt::as_span(sample.sample16(), sample.nLength * numChannels); + int32 minNative = int16_max, maxNative = int16_min, minSwapped = int16_max, maxSwapped = int16_min; + for(const auto vNative : sample16) + { + const int16 vSwapped = mpt::byteswap(vNative); + if(vNative < minNative) + minNative = vNative; + if(vNative > maxNative) + maxNative = vNative; + if(vSwapped < minSwapped) + minSwapped = vSwapped; + if(vSwapped > maxSwapped) + maxSwapped = vSwapped; + } + + const int32 minMaxNative = std::max({int32(1), -minNative, maxNative}); + const int32 minMaxSwapped = std::max({int32(1), -minSwapped, maxSwapped}); + const double factorNative = 1.0 / minMaxNative, factorSwapped = 1.0 / minMaxSwapped; + double errorNative = 0.0, errorSwapped = 0.0; + for(uint8 chn = 0; chn < numChannels; chn++) + { + const int16 *vNative = sample.sample16() + chn; + int32 prev = 0; + for(SmpLength i = sample.nLength; i != 0; i--, vNative += numChannels) + { + const double diffNative = (*vNative - prev) * factorNative; + errorNative += diffNative * diffNative; + const double diffSwapped = (mpt::byteswap(*vNative) - mpt::byteswap(static_cast(prev))) * factorSwapped; + errorSwapped += diffSwapped * diffSwapped; + prev = *vNative; + } + } + if(errorNative > errorSwapped) + { + for(auto &v : sample16) + { + v = mpt::byteswap(v); + } + } + } + sample.PrecomputeLoops(*this, false); return true; } +#ifndef MODPLUG_NO_FILESAVE + +static uint32 WriteIFFStringChunk(std::ostream &f, IFFChunk::ChunkIdentifiers id, const std::string &str) +{ + IFFChunk chunk{}; + chunk.id = id; + chunk.length = static_cast(str.size()); + mpt::IO::Write(f, chunk); + mpt::IO::WriteText(f, str); + uint32 totalSize = sizeof(IFFChunk) + chunk.length; + if(totalSize % 2u) + { + mpt::IO::WriteIntBE(f, 0); + totalSize++; + } + return totalSize; +} + + +bool CSoundFile::SaveIFFSample(SAMPLEINDEX smp, std::ostream &f) const +{ + const ModSample &sample = Samples[smp]; + if(sample.uFlags[CHN_ADLIB]) + return false; + + mpt::IO::OFile ff(f); + IFFHeader fileHeader{}; + memcpy(fileHeader.form, "FORM", 4); + if(sample.uFlags[CHN_16BIT]) + memcpy(fileHeader.magic, "16SV", 4); + else + memcpy(fileHeader.magic, "8SVX", 4); + mpt::IO::Write(f, fileHeader); + + uint32 totalSize = 4 + sizeof(IFFChunk) + sizeof(IFFSampleHeader); + + IFFChunk chunk{}; + chunk.id = IFFChunk::idVHDR; + chunk.length = sizeof(IFFSampleHeader); + mpt::IO::Write(f, chunk); + + IFFSampleHeader sampleHeader{}; + uint32 loopStart = sample.nLength, loopEnd = sample.nLength; + if(sample.uFlags[CHN_LOOP]) + { + loopStart = sample.nLoopStart; + loopEnd = sample.nLoopEnd; + } else if(sample.uFlags[CHN_SUSTAINLOOP]) + { + loopStart = sample.nSustainStart; + loopEnd = sample.nSustainEnd; + } + const uint8 bps = sample.GetBytesPerSample(); + sampleHeader.oneShotHiSamples = loopStart * bps; + sampleHeader.repeatHiSamples = (loopEnd - loopStart) * bps; + + sampleHeader.samplesPerHiCycle = 0; + sampleHeader.samplesPerSec = mpt::saturate_cast(sample.GetSampleRate(m_nType)); + sampleHeader.octave = 1; + sampleHeader.compression = 0; + sampleHeader.volume = mpt::saturate_cast(sample.nVolume * 256u); + mpt::IO::Write(f, sampleHeader); + + if(sample.uFlags[CHN_STEREO]) + { + chunk.id = IFFChunk::idCHAN; + chunk.length = 4; + mpt::IO::Write(f, chunk); + mpt::IO::WriteIntBE(f, 6); + totalSize += sizeof(chunk) + chunk.length; + } + + totalSize += WriteIFFStringChunk(f, IFFChunk::idNAME, mpt::ToCharset(mpt::Charset::Amiga, GetCharsetInternal(), m_szNames[smp])); + totalSize += WriteIFFStringChunk(f, IFFChunk::idANNO, mpt::ToCharset(mpt::Charset::Amiga, Version::Current().GetOpenMPTVersionString())); + + SampleIO sampleIO( + sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + sample.uFlags[CHN_STEREO] ? SampleIO::stereoSplit : SampleIO::mono, + SampleIO::bigEndian, + SampleIO::signedPCM); + + chunk.id = IFFChunk::idBODY; + chunk.length = mpt::saturate_cast(sampleIO.CalculateEncodedSize(sample.nLength)); + mpt::IO::Write(f, chunk); + sampleIO.WriteSample(f, sample); + totalSize += sizeof(chunk) + chunk.length; + if(totalSize % 2u) + { + mpt::IO::WriteIntBE(f, 0); + totalSize++; + } + + fileHeader.size = totalSize; + mpt::IO::SeekAbsolute(f, 0); + mpt::IO::Write(f, fileHeader); + + return true; +} + +#endif // MODPLUG_NO_FILESAVE + + OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp index 5423d159c..2ab77ad31 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.cpp @@ -916,12 +916,12 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength // Stereo signed interleaved MPT_ASSERT(len == numSamples * 2); const int8 *const pSample8 = sample.sample8(); - mpt::IO::WriteRaw(f, reinterpret_cast(pSample8), len); + mpt::IO::Write(f, mpt::as_span(pSample8, len)); } else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM && GetEndianness() == littleEndian) { - // Stereo signed interleaved + // Stereo signed interleaved, little-endian MPT_ASSERT(len == numSamples * 4); const int16 *const pSample16 = sample.sample16(); const int16 *p = pSample16; @@ -935,7 +935,7 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM && GetEndianness() == bigEndian) { - // Stereo signed interleaved + // Stereo signed interleaved, big-endian MPT_ASSERT(len == numSamples * 4); const int16 *const pSample16 = sample.sample16(); const int16 *p = pSample16; @@ -947,6 +947,21 @@ size_t SampleIO::WriteSample(std::ostream &f, const ModSample &sample, SmpLength } } + else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEncoding() == signedPCM && GetEndianness() == bigEndian) + { + // Stereo signed split, big-endian + MPT_ASSERT(len == numSamples * 4); + for(uint8 chn = 0; chn < 2; chn++) + { + const int16 *p = sample.sample16() + chn; + for(SmpLength j = 0; j < numSamples; j++) + { + mpt::IO::Write(fb, mpt::as_be(*p)); + p += 2; + } + } + } + else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved && GetEncoding() == unsignedPCM) { // Stereo unsigned interleaved diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.h b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.h index 416a60351..bf3b4a766 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleIO.h @@ -14,7 +14,7 @@ #include "openmpt/all/BuildSettings.hpp" - +#include "Snd_defs.h" #include "../common/FileReaderFwd.h" diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleNormalize.h b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleNormalize.h index 954b77041..bbe4b9723 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/SampleNormalize.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/SampleNormalize.h @@ -27,9 +27,9 @@ struct Normalize; template <> struct Normalize { - typedef int32 input_t; - typedef int32 output_t; - typedef uint32 peak_t; + using input_t = int32; + using output_t = int32; + using peak_t = uint32; uint32 maxVal; MPT_FORCEINLINE Normalize() : maxVal(0) {} @@ -66,9 +66,9 @@ struct Normalize template <> struct Normalize { - typedef float32 input_t; - typedef float32 output_t; - typedef float32 peak_t; + using input_t = float32; + using output_t = float32; + using peak_t = float32; float maxVal; float maxValInv; MPT_FORCEINLINE Normalize() @@ -106,9 +106,9 @@ struct Normalize template <> struct Normalize { - typedef float64 input_t; - typedef float64 output_t; - typedef float64 peak_t; + using input_t = float64; + using output_t = float64; + using peak_t = float64; double maxVal; double maxValInv; MPT_FORCEINLINE Normalize() @@ -151,10 +151,10 @@ struct Normalize template struct NormalizationChain { - typedef typename Func1::input_t input_t; - typedef typename Func1::output_t normalize_t; - typedef typename Normalize::peak_t peak_t; - typedef typename Func2::output_t output_t; + using input_t = typename Func1::input_t; + using normalize_t = typename Func1::output_t; + using peak_t = typename Normalize::peak_t; + using output_t = typename Func2::output_t; static constexpr std::size_t input_inc = Func1::input_inc; Func1 func1; Normalize normalize; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h index 784125baf..ce9605c4d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_defs.h @@ -105,15 +105,16 @@ enum MODTYPE DECLARE_FLAGSET(MODTYPE) -enum MODCONTAINERTYPE +enum class ModContainerType { - MOD_CONTAINERTYPE_NONE = 0x0, - MOD_CONTAINERTYPE_UMX = 0x3, - MOD_CONTAINERTYPE_XPK = 0x4, - MOD_CONTAINERTYPE_PP20 = 0x5, - MOD_CONTAINERTYPE_MMCMP= 0x6, - MOD_CONTAINERTYPE_WAV = 0x7, // WAV as module - MOD_CONTAINERTYPE_UAX = 0x8, // Unreal sample set as module + None, + UMX, + XPK, + PP20, + MMCMP, + WAV, // WAV as module + UAX, // Unreal sample set as module + Generic, // Generic CUnarchiver container }; @@ -180,9 +181,12 @@ DECLARE_FLAGSET(EnvelopeFlags) // Envelope value boundaries -#define ENVELOPE_MIN 0 // Vertical min value of a point -#define ENVELOPE_MID 32 // Vertical middle line -#define ENVELOPE_MAX 64 // Vertical max value of a point +enum : uint8 +{ + ENVELOPE_MIN = 0, // Vertical min value of a point + ENVELOPE_MID = 32, // Vertical middle line + ENVELOPE_MAX = 64, // Vertical max value of a point +}; #define MAX_ENVPOINTS 240 // Maximum length of each instrument envelope @@ -547,6 +551,7 @@ enum PlayBehaviour kPluginIgnoreTonePortamento, // Use old tone portamento behaviour for plugins (XM: no plugin pitch slides with commands E1x/E2x/X1x/X2x) kST3TonePortaWithAdlibNote, // Adlib note next to tone portamento is delayed until next row kITResetFilterOnPortaSmpChange, // Filter is reset on portamento if sample is swapped + kITInitialNoteMemory, // Initial "last note memory" for each channel is C-0 and not "no note" // Add new play behaviours here. @@ -585,7 +590,7 @@ public: MPT_CONSTEXPRINLINE SamplePosition(int32 intPart, uint32 fractPart) : v((static_cast(intPart) * (1ll << 32)) | fractPart) { } static SamplePosition Ratio(uint32 dividend, uint32 divisor) { return SamplePosition((static_cast(dividend) << 32) / divisor); } static SamplePosition FromDouble(double pos) { return SamplePosition(static_cast(pos * 4294967296.0)); } - double ToDouble() const { return v / 4294967296.0; } + double ToDouble() const { return static_cast(v) / 4294967296.0; } // Set integer and fractional part MPT_CONSTEXPRINLINE SamplePosition &Set(int32 intPart, uint32 fractPart = 0) { v = (static_cast(intPart) << 32) | fractPart; return *this; } @@ -647,7 +652,7 @@ public: // This is mostly for the clarity of stored values and to be able to represent any value .0000 to .9999 properly. // For easier debugging, use the Debugger Visualizers available in build/vs/debug/ // to easily display the stored values. -template +template struct FPInt { protected: @@ -655,7 +660,7 @@ protected: MPT_CONSTEXPRINLINE FPInt(T rawValue) : v(rawValue) { } public: - enum : size_t { fractFact = FFact }; + enum : T { fractFact = static_cast(FFact) }; using store_t = T; MPT_CONSTEXPRINLINE FPInt() : v(0) { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp index c3799a3c2..b17c9284a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_flt.cpp @@ -13,7 +13,6 @@ #include "stdafx.h" #include "Sndfile.h" -#include "Tables.h" #include "../common/misc_util.h" #include "mpt/base/numbers.hpp" @@ -38,53 +37,52 @@ uint8 CSoundFile::FrequencyToCutOff(double frequency) const } -uint32 CSoundFile::CutOffToFrequency(uint32 nCutOff, int envModifier) const +float CSoundFile::CutOffToFrequency(uint32 nCutOff, int envModifier) const { MPT_ASSERT(nCutOff < 128); float computedCutoff = static_cast(nCutOff * (envModifier + 256)); // 0...127*512 - float Fc; + float frequency; if(GetType() != MOD_TYPE_IMF) { - Fc = 110.0f * std::pow(2.0f, 0.25f + computedCutoff / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f)); + frequency = 110.0f * std::pow(2.0f, 0.25f + computedCutoff / (m_SongFlags[SONG_EXFILTERRANGE] ? 20.0f * 512.0f : 24.0f * 512.0f)); } else { // EMU8000: Documentation says the cutoff is in quarter semitones, with 0x00 being 125 Hz and 0xFF being 8 kHz // The first half of the sentence contradicts the second, though. - Fc = 125.0f * std::pow(2.0f, computedCutoff * 6.0f / (127.0f * 512.0f)); + frequency = 125.0f * std::pow(2.0f, computedCutoff * 6.0f / (127.0f * 512.0f)); } - int freq = mpt::saturate_round(Fc); - Limit(freq, 120, 20000); - if(freq * 2 > (int)m_MixerSettings.gdwMixingFreq) freq = m_MixerSettings.gdwMixingFreq / 2; - return static_cast(freq); + Limit(frequency, 120.0f, 20000.0f); + LimitMax(frequency, static_cast(m_MixerSettings.gdwMixingFreq) * 0.5f); + return frequency; } // Update channels with instrument filter settings updated through tracker UI -void CSoundFile::UpdateInstrumentFilter(const ModInstrument *ins, bool updateMode, bool updateCutoff, bool updateResonance) +void CSoundFile::UpdateInstrumentFilter(const ModInstrument &ins, bool updateMode, bool updateCutoff, bool updateResonance) { for(auto &chn : m_PlayState.Chn) { - if(chn.pModInstrument != ins) + if(chn.pModInstrument != &ins) continue; bool change = false; - if(updateMode && ins->filterMode != FilterMode::Unchanged && chn.nFilterMode != ins->filterMode) + if(updateMode && ins.filterMode != FilterMode::Unchanged && chn.nFilterMode != ins.filterMode) { - chn.nFilterMode = ins->filterMode; + chn.nFilterMode = ins.filterMode; change = true; } if(updateCutoff) { - chn.nCutOff = ins->IsCutoffEnabled() ? ins->GetCutoff() : 0x7F; + chn.nCutOff = ins.IsCutoffEnabled() ? ins.GetCutoff() : 0x7F; change |= (chn.nCutOff < 0x7F || chn.dwFlags[CHN_FILTER]); } if(updateResonance) { - chn.nResonance = ins->IsResonanceEnabled() ? ins->GetResonance() : 0; + chn.nResonance = ins.IsResonanceEnabled() ? ins.GetResonance() : 0; change |= (chn.nResonance > 0 || chn.dwFlags[CHN_FILTER]); } // If filter envelope is active, the filter will be updated in the next player tick anyway. - if(change && (!ins->PitchEnv.dwFlags[ENV_FILTER] || !IsEnvelopeProcessed(chn, ENV_PITCH))) + if(change && (!ins.PitchEnv.dwFlags[ENV_FILTER] || !IsEnvelopeProcessed(chn, ENV_PITCH))) SetupChannelFilter(chn, false); } } @@ -125,18 +123,18 @@ int CSoundFile::SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier chn.dwFlags.set(CHN_FILTER); // 2 * damping factor - const float dmpfac = std::pow(10.0f, -resonance * ((24.0f / 128.0f) / 20.0f)); + const float dmpfac = std::pow(10.0f, static_cast(-resonance) * ((24.0f / 128.0f) / 20.0f)); const float fc = CutOffToFrequency(cutoff, envModifier) * (2.0f * mpt::numbers::pi_v); float d, e; if(m_playBehaviour[kITFilterBehaviour] && !m_SongFlags[SONG_EXFILTERRANGE]) { - const float r = m_MixerSettings.gdwMixingFreq / fc; + const float r = static_cast(m_MixerSettings.gdwMixingFreq) / fc; d = dmpfac * r + dmpfac - 1.0f; e = r * r; } else { - const float r = fc / m_MixerSettings.gdwMixingFreq; + const float r = fc / static_cast(m_MixerSettings.gdwMixingFreq); d = (1.0f - 2.0f * dmpfac) * r; LimitMax(d, 2.0f); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp index 5c4311f0b..178fdbbdc 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Snd_fx.cpp @@ -91,7 +91,7 @@ public: state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn, muteFlag); state->Chn[chn].nOldGlobalVolSlide = 0; state->Chn[chn].nOldChnVolSlide = 0; - state->Chn[chn].nNote = state->Chn[chn].nNewNote = state->Chn[chn].nLastNote = NOTE_NONE; + state->Chn[chn].nLastNote = NOTE_NONE; } } @@ -120,20 +120,69 @@ public: bool updateInc = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED; if(i >= portaStart) { - chn.isFirstTick = false; + state->m_nTickCount = i - portaStart; + chn.isFirstTick = (i == portaStart); const ModCommand &m = *sndFile.Patterns[state->m_nPattern].GetpModCommand(state->m_nRow, channel); auto command = m.command; - if(m.volcmd == VOLCMD_TONEPORTAMENTO) + switch(m.volcmd) { - const auto [porta, clearEffectCommand] = sndFile.GetVolCmdTonePorta(m, 0); - sndFile.TonePortamento(chn, porta); - if(clearEffectCommand) - command = CMD_NONE; + case VOLCMD_TONEPORTAMENTO: + { + const auto [porta, clearEffectCommand] = sndFile.GetVolCmdTonePorta(m, 0); + sndFile.TonePortamento(*state, channel, porta); + if(clearEffectCommand) + command = CMD_NONE; + } + break; + case VOLCMD_PORTAUP: + sndFile.PortamentoUp(*state, channel, static_cast(m.vol << 2), sndFile.m_playBehaviour[kITVolColFinePortamento]); + break; + case VOLCMD_PORTADOWN: + sndFile.PortamentoDown(*state, channel, static_cast(m.vol << 2), sndFile.m_playBehaviour[kITVolColFinePortamento]); + break; + default: + break; } - if(command == CMD_TONEPORTAMENTO) - sndFile.TonePortamento(chn, m.param); - else if(command == CMD_TONEPORTAVOL) - sndFile.TonePortamento(chn, 0); + switch(command) + { + case CMD_TONEPORTAMENTO: + sndFile.TonePortamento(*state, channel, m.param); + break; + case CMD_TONEPORTAVOL: + sndFile.TonePortamento(*state, channel, 0); + break; + case CMD_PORTAMENTOUP: + if(m.param || !(sndFile.GetType() & MOD_TYPE_MOD)) + sndFile.PortamentoUp(*state, channel, m.param, false); + break; + case CMD_PORTAMENTODOWN: + if(m.param || !(sndFile.GetType() & MOD_TYPE_MOD)) + sndFile.PortamentoDown(*state, channel, m.param, false); + break; + case CMD_MODCMDEX: + if(!(m.param & 0x0F) && !(sndFile.GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) + break; + if((m.param & 0xF0) == 0x10) + sndFile.FinePortamentoUp(chn, m.param & 0x0F); + else if((m.param & 0xF0) == 0x20) + sndFile.FinePortamentoDown(chn, m.param & 0x0F); + break; + case CMD_XFINEPORTAUPDOWN: + if((m.param & 0xF0) == 0x10) + sndFile.ExtraFinePortamentoUp(chn, m.param & 0x0F); + else if((m.param & 0xF0) == 0x20) + sndFile.ExtraFinePortamentoDown(chn, m.param & 0x0F); + break; + case CMD_NOTESLIDEUP: + case CMD_NOTESLIDEDOWN: + case CMD_NOTESLIDEUPRETRIG: + case CMD_NOTESLIDEDOWNRETRIG: + sndFile.NoteSlide(chn, m.param, command == CMD_NOTESLIDEUP || command == CMD_NOTESLIDEUPRETRIG, command == CMD_NOTESLIDEUPRETRIG || command == CMD_NOTESLIDEDOWNRETRIG); + break; + default: + break; + } + updateInc = true; } @@ -216,6 +265,7 @@ public: } } } + state->m_nTickCount = 0; if(stopNote) { @@ -261,15 +311,10 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod // Fast LUTs for commands that are too weird / complicated / whatever to emulate in sample position adjust mode. std::bitset forbiddenCommands; - std::bitset forbiddenVolCommands; if(adjustSamplePos) { - forbiddenCommands.set(CMD_ARPEGGIO); forbiddenCommands.set(CMD_PORTAMENTOUP); - forbiddenCommands.set(CMD_PORTAMENTODOWN); forbiddenCommands.set(CMD_XFINEPORTAUPDOWN); - forbiddenCommands.set(CMD_NOTESLIDEUP); forbiddenCommands.set(CMD_NOTESLIDEUPRETRIG); - forbiddenCommands.set(CMD_NOTESLIDEDOWN); forbiddenCommands.set(CMD_NOTESLIDEDOWNRETRIG); - forbiddenVolCommands.set(VOLCMD_PORTAUP); forbiddenVolCommands.set(VOLCMD_PORTADOWN); + forbiddenCommands.set(CMD_ARPEGGIO); if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.size()) { @@ -518,6 +563,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod playState.m_nPatternDelay = 1 + (p->param & 0x0F); } break; + + default: + break; } } const uint32 numTicks = playState.TicksOnRow(); @@ -548,6 +596,21 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod { chn.nLastNote = note; chn.RestorePanAndFilter(); + + if(!adjustSamplePos || memory.chnSettings[nChn].ticksToRender == GetLengthMemory::IGNORE_CHANNEL) + { + // Even if we don't intend to render anything on this channel, update instrument cutoff/resonance because it might override a Zxx effect evaluated earlier. + const ModInstrument *instr = chn.pModInstrument; + if(chn.nNewIns && chn.nNewIns <= GetNumInstruments()) + instr = Instruments[chn.nNewIns]; + if(instr != nullptr) + { + if(instr->IsCutoffEnabled()) + chn.nCutOff = instr->GetCutoff(); + if(instr->IsResonanceEnabled()) + chn.nResonance = instr->GetResonance(); + } + } } // Update channel panning @@ -586,6 +649,8 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod command = CMD_NONE; } break; + default: + break; } } @@ -687,6 +752,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod if(((param & 0xF0) == 0xA0) && !m_playBehaviour[kFT2RestrictXCommand]) chn.nOldHiOffset = param & 0x0F; break; + + default: + break; } // The following calculations are not interesting if we just want to get the song length. @@ -733,6 +801,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod case CMD_VOLUME: memory.chnSettings[nChn].vol = param; break; + case CMD_VOLUME8: + memory.chnSettings[nChn].vol = static_cast((param + 3u) / 4u); + break; // Global Volume case CMD_GLOBALVOLUME: if(!(GetType() & GLOBALVOL_7BIT_FORMATS) && param < 128) param *= 2; @@ -863,6 +934,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod case VOLCMD_VIBRATODEPTH: Vibrato(chn, chn.rowCommand.vol); break; + + default: + break; } // Process vibrato / tremolo / panbrello @@ -900,6 +974,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod ProcessPanbrello(chn); } break; + + default: + break; } if(m_playBehaviour[kST3EffectMemory] && param != 0) @@ -911,7 +988,9 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod // Interpret F00 effect in XM files as "stop song" if(GetType() == MOD_TYPE_XM && playState.m_nMusicSpeed == uint16_max) { - break; + playState.m_nNextRow = playState.m_nRow; + playState.m_nNextOrder = playState.m_nCurrentOrder; + continue; } playState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat; @@ -940,7 +1019,7 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod uint32 paramHi = m.param >> 4, paramLo = m.param & 0x0F; uint32 startTick = 0; - bool porta = m.command == CMD_TONEPORTAMENTO || m.command == CMD_TONEPORTAVOL || m.volcmd == VOLCMD_TONEPORTAMENTO; + const bool porta = m.IsPortamento(); bool stopNote = false; if(m.instr) chn.prevNoteOffset = 0; @@ -955,6 +1034,7 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod chn.nNewNote = chn.nLastNote; if(chn.nNewIns != 0) InstrumentChange(chn, chn.nNewIns, porta); NoteChange(chn, m.note, porta); + HandleNoteChangeFilter(chn); HandleDigiSamplePlayDirection(playState, nChn); memory.chnSettings[nChn].incChanged = true; @@ -1016,12 +1096,11 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod } if(m.command == CMD_VOLUME) - { - chn.nVolume = m.param * 4; - } else if(m.volcmd == VOLCMD_VOLUME) - { - chn.nVolume = m.vol * 4; - } + chn.nVolume = m.param * 4u; + else if(m.command == CMD_VOLUME8) + chn.nVolume = m.param; + else if(m.volcmd == VOLCMD_VOLUME) + chn.nVolume = m.vol * 4u; if(chn.pModSample && !stopNote) { @@ -1042,11 +1121,6 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod } } } - - if(m.volcmd < forbiddenVolCommands.size() && forbiddenVolCommands[m.volcmd]) - { - stopNote = true; - } } if(stopNote) @@ -1118,6 +1192,8 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far chn.microTuning = CalculateFinetuneTarget(playState.m_nPattern, playState.m_nRow, nChn); // TODO should render each tick individually for CMD_FINETUNE_SMOOTH for higher sync accuracy break; + default: + break; } chn.isFirstTick = true; switch(m.volcmd) @@ -1149,14 +1225,16 @@ std::vector CSoundFile::GetLength(enmGetLengthResetMode adjustMod if(m.vol <= 1) chn.isPaused = (m.vol == 0); break; + default: + break; } if(chn.isPaused) continue; - if(porta) + if(m.IsAnyPitchSlide()) { // Portamento needs immediate syncing, as the pitch changes on each tick - uint32 portaTick = memory.chnSettings[nChn].ticksToRender + startTick + 1; + uint32 portaTick = memory.chnSettings[nChn].ticksToRender + startTick; memory.chnSettings[nChn].ticksToRender += numTicks; memory.RenderChannel(nChn, tickDuration, portaTick); } else @@ -1749,7 +1827,7 @@ void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetE if(bPorta && !chn.IsSamplePlaying()) { - if(m_playBehaviour[kFT2PortaNoNote]) + if(m_playBehaviour[kFT2PortaNoNote] && (!chn.HasMIDIOutput() || m_playBehaviour[kPluginIgnoreTonePortamento])) { // FT2 Compatibility: Ignore notes with portamento if there was no note playing. // Test case: 3xx-no-old-samp.xm @@ -2217,11 +2295,10 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo case DuplicateNoteAction::NoteOff: case DuplicateNoteAction::NoteFade: // Switch off duplicated note played on this plugin - if(const auto oldNote = chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]); oldNote != NOTE_NONE) + if(chn.lastMidiNoteWithoutArp != NOTE_NONE) { - SendMIDINote(i, oldNote + NOTE_MAX_SPECIAL, 0); - chn.nArpeggioLastNote = NOTE_NONE; - chn.nNote = NOTE_NONE; + SendMIDINote(i, chn.lastMidiNoteWithoutArp | IMixPlugin::MIDI_NOTE_OFF, 0); + chn.lastMidiNoteWithoutArp = NOTE_NONE; } break; } @@ -2274,8 +2351,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo { // apply NNA to this plugin iff it is currently playing a note on this tracker channel // (and if it is playing a note, we know that would be the last note played on this chan). - const auto oldNote = srcChn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]); - applyNNAtoPlug = (oldNote != NOTE_NONE) && pPlugin->IsNotePlaying(oldNote, nChn); + applyNNAtoPlug = (srcChn.lastMidiNoteWithoutArp != NOTE_NONE) && pPlugin->IsNotePlaying(srcChn.lastMidiNoteWithoutArp, nChn); } } } @@ -2296,6 +2372,7 @@ CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, boo // Switch off note played on this plugin, on this tracker channel and midi channel SendMIDINote(nChn, NOTE_KEYOFF, 0); srcChn.nArpeggioLastNote = NOTE_NONE; + srcChn.lastMidiNoteWithoutArp = NOTE_NONE; break; case NewNoteAction::Continue: break; @@ -2626,11 +2703,14 @@ bool CSoundFile::ProcessEffects() // Apparently, any note number in a pattern causes instruments to recall their original volume settings - no matter if there's a Note Off next to it or whatever. // Test cases: keyoff+instr.xm, delay.xm bool reloadSampleSettings = (m_playBehaviour[kFT2ReloadSampleSettings] && instr != 0); - // ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it - // Test case: PTSwapEmpty.mod, PTInstrVolume.mod, SampleSwap.s3m - bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) - || m_playBehaviour[kST3SampleSwap] - || (m_playBehaviour[kMODSampleSwap] && !chn.IsSamplePlaying() && (chn.pModSample == nullptr || !chn.pModSample->HasSampleData())); + bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || m_playBehaviour[kST3SampleSwap]; + if(m_playBehaviour[kMODSampleSwap]) + { + // ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it + // Test case: PTSwapEmpty.mod, PTInstrVolume.mod, SampleSwap.s3m + if(!chn.IsSamplePlaying() && (chn.pModSample == nullptr || !chn.pModSample->HasSampleData())) + keepInstr = true; + } // Now it's time for some FT2 crap... if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) @@ -2700,7 +2780,10 @@ bool CSoundFile::ProcessEffects() if(oldSample != nullptr) { if(!oldSample->uFlags[SMP_NODEFAULTVOLUME] && (GetType() != MOD_TYPE_S3M || oldSample->HasSampleData())) + { chn.nVolume = oldSample->nVolume; + chn.dwFlags.set(CHN_FASTVOLRAMP); + } if(reloadSampleSettings) { // Also reload panning @@ -2931,7 +3014,7 @@ bool CSoundFile::ProcessEffects() if(clearEffectCommand) cmd = CMD_NONE; - TonePortamento(chn, porta); + TonePortamento(nChn, porta); } else { // FT2 Compatibility: FT2 ignores some volume commands with parameter = 0. @@ -3049,6 +3132,9 @@ bool CSoundFile::ProcessEffects() if(vol <= 1) chn.isPaused = (vol == 0); break; + + default: + break; } } } @@ -3064,17 +3150,24 @@ bool CSoundFile::ProcessEffects() chn.dwFlags.set(CHN_FASTVOLRAMP); } break; + case CMD_VOLUME8: + if(m_SongFlags[SONG_FIRSTTICK]) + { + chn.nVolume = param; + chn.dwFlags.set(CHN_FASTVOLRAMP); + } + break; // Portamento Up case CMD_PORTAMENTOUP: - if ((!param) && (GetType() & MOD_TYPE_MOD)) break; - PortamentoUp(nChn, static_cast(param)); + if(param || !(GetType() & MOD_TYPE_MOD)) + PortamentoUp(nChn, static_cast(param), false); break; // Portamento Down case CMD_PORTAMENTODOWN: - if ((!param) && (GetType() & MOD_TYPE_MOD)) break; - PortamentoDown(nChn, static_cast(param)); + if(param || !(GetType() & MOD_TYPE_MOD)) + PortamentoDown(nChn, static_cast(param), false); break; // Volume Slide @@ -3084,13 +3177,13 @@ bool CSoundFile::ProcessEffects() // Tone-Portamento case CMD_TONEPORTAMENTO: - TonePortamento(chn, static_cast(param)); + TonePortamento(nChn, static_cast(param)); break; // Tone-Portamento + Volume Slide case CMD_TONEPORTAVOL: if ((param) || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast(param)); - TonePortamento(chn, 0); + TonePortamento(nChn, 0); break; // Vibrato @@ -3328,8 +3421,16 @@ bool CSoundFile::ProcessEffects() case CMD_XFINEPORTAUPDOWN: switch(param & 0xF0) { - case 0x10: ExtraFinePortamentoUp(chn, param & 0x0F); break; - case 0x20: ExtraFinePortamentoDown(chn, param & 0x0F); break; + case 0x10: + ExtraFinePortamentoUp(chn, param & 0x0F); + if(!m_playBehaviour[kPluginIgnoreTonePortamento]) + MidiPortamento(nChn, 0xE0 | (param & 0x0F), true); + break; + case 0x20: + ExtraFinePortamentoDown(chn, param & 0x0F); + if(!m_playBehaviour[kPluginIgnoreTonePortamento]) + MidiPortamento(nChn, -static_cast(0xE0 | (param & 0x0F)), true); + break; // ModPlug XM Extensions (ignore in compatible mode) case 0x50: case 0x60: @@ -3447,6 +3548,9 @@ bool CSoundFile::ProcessEffects() case CMD_DIGIREVERSESAMPLE: DigiBoosterSampleReverse(chn, static_cast(param)); break; + + default: + break; } if(m_playBehaviour[kST3EffectMemory] && param != 0) @@ -3609,7 +3713,7 @@ uint32 CSoundFile::CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX if(m->command != CMD_XPARAM) break; - if(xmTempoFix && val < 256) + if(xmTempoFix && val >= 0x20 && val < 256) { // With XM, 0x20 is the lowest tempo. Anything below changes ticks per row. val -= 0x20; @@ -3660,7 +3764,14 @@ ROWINDEX CSoundFile::PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 para void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) { - ModChannel &chn = m_PlayState.Chn[nChn]; + PortamentoUp(m_PlayState, nChn, param, doFinePortamentoAsRegular); + MidiPortamento(nChn, m_PlayState.Chn[nChn].nOldPortaUp, !doFinePortamentoAsRegular && UseCombinedPortamentoCommands()); +} + + +void CSoundFile::PortamentoUp(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const +{ + ModChannel &chn = playState.Chn[nChn]; if(param) { @@ -3674,16 +3785,13 @@ void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const param = chn.nOldPortaUp; } - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)); - - // Process MIDI pitch bend for instrument plugins - MidiPortamento(nChn, param, doFineSlides); + const bool doFineSlides = !doFinePortamentoAsRegular && UseCombinedPortamentoCommands(); if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { // Portamento for instruments with custom tuning if(param >= 0xF0 && !doFinePortamentoAsRegular) - PortamentoFineMPT(chn, param - 0xF0); + PortamentoFineMPT(playState, nChn, param - 0xF0); else if(param >= 0xE0 && !doFinePortamentoAsRegular) PortamentoExtraFineMPT(chn, param - 0xE0); else @@ -3728,7 +3836,14 @@ void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) { - ModChannel &chn = m_PlayState.Chn[nChn]; + PortamentoDown(m_PlayState, nChn, param, doFinePortamentoAsRegular); + MidiPortamento(nChn, -static_cast(m_PlayState.Chn[nChn].nOldPortaDown), !doFinePortamentoAsRegular && UseCombinedPortamentoCommands()); +} + + +void CSoundFile::PortamentoDown(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const +{ + ModChannel &chn = playState.Chn[nChn]; if(param) { @@ -3742,16 +3857,13 @@ void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, cons param = chn.nOldPortaDown; } - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)); - - // Process MIDI pitch bend for instrument plugins - MidiPortamento(nChn, -static_cast(param), doFineSlides); + const bool doFineSlides = !doFinePortamentoAsRegular && UseCombinedPortamentoCommands(); if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { // Portamento for instruments with custom tuning if(param >= 0xF0 && !doFinePortamentoAsRegular) - PortamentoFineMPT(chn, -static_cast(param - 0xF0)); + PortamentoFineMPT(playState, nChn, -static_cast(param - 0xF0)); else if(param >= 0xE0 && !doFinePortamentoAsRegular) PortamentoExtraFineMPT(chn, -static_cast(param - 0xE0)); else @@ -3795,7 +3907,7 @@ void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, cons // Send portamento commands to plugins -void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides) +void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, const bool doFineSlides) { int actualParam = std::abs(param); int pitchBend = 0; @@ -3970,7 +4082,7 @@ int16 CSoundFile::CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CH // Oktalyzer: Slide down on first tick only, or on every tick void CSoundFile::NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const { - if(m_SongFlags[SONG_FIRSTTICK]) + if(chn.isFirstTick) { if(param & 0xF0) chn.noteSlideParam = static_cast(param & 0xF0) | (chn.noteSlideParam & 0x0F); @@ -3983,7 +4095,7 @@ void CSoundFile::NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool ret if(GetType() == MOD_TYPE_OKT) doTrigger = ((chn.noteSlideParam & 0xF0) == 0x10) || m_SongFlags[SONG_FIRSTTICK]; else - doTrigger = !m_SongFlags[SONG_FIRSTTICK] && (--chn.noteSlideCounter == 0); + doTrigger = !chn.isFirstTick && (--chn.noteSlideCounter == 0); if(doTrigger) { @@ -4031,9 +4143,30 @@ std::pair CSoundFile::GetVolCmdTonePorta(const ModCommand &m, uint } -// Portamento Slide -void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const +void CSoundFile::TonePortamento(CHANNELINDEX nChn, uint16 param) { + auto delta = TonePortamento(m_PlayState, nChn, param); + if(!delta) + return; + +#ifndef NO_PLUGINS + ModChannel &chn = m_PlayState.Chn[nChn]; + if(!m_playBehaviour[kPluginIgnoreTonePortamento] && chn.pModInstrument != nullptr && chn.pModInstrument->midiPWD != 0) + { + IMixPlugin *plugin = GetChannelInstrumentPlugin(chn); + if(plugin != nullptr) + { + plugin->MidiTonePortamento(delta, chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping], true), chn.pModInstrument->midiPWD, nChn); + } + } +#endif // NO_PLUGINS +} + + +// Portamento Slide +int32 CSoundFile::TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const +{ + ModChannel &chn = playState.Chn[nChn]; chn.dwFlags.set(CHN_PORTAMENTO); //IT compatibility 03: Share effect memory with portamento up/down @@ -4051,15 +4184,15 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const //Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando) //to slide per row(not per tick). if(chn.portamentoSlide == 0) - return; + return 0; - const int32 oldPortamentoTickSlide = (m_PlayState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0; + const int32 oldPortamentoTickSlide = (playState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0; int32 delta = chn.portamentoSlide; if(chn.nPortamentoDest < 0) delta = -delta; - chn.m_PortamentoTickSlide = static_cast((m_PlayState.m_nTickCount + 1.0) * delta / m_PlayState.m_nMusicSpeed); + chn.m_PortamentoTickSlide = static_cast((playState.m_nTickCount + 1.0) * delta / playState.m_nMusicSpeed); if(chn.dwFlags[CHN_GLISSANDO]) { @@ -4084,12 +4217,17 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const chn.m_CalculateFreq = true; } - return; + return 0; } + // ST3: Adlib Note + Tone Portamento does not execute the slide, but changes to the target note instantly on the next row (unless there is another note with tone portamento) + // Test case: TonePortamentoWithAdlibNote.s3m + if(m_playBehaviour[kST3TonePortaWithAdlibNote] && chn.dwFlags[CHN_ADLIB] && chn.rowCommand.IsNote()) + return 0; + bool doPorta = !chn.isFirstTick || (GetType() & (MOD_TYPE_DBM | MOD_TYPE_669)) - || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1]) + || (playState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1]) || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]); int32 delta = chn.portamentoSlide; @@ -4098,20 +4236,19 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const delta -= 0xF0; doPorta = chn.isFirstTick; } + delta *= (GetType() == MOD_TYPE_669) ? 2 : 4; if(chn.nPeriod && chn.nPortamentoDest && doPorta) { - delta *= (GetType() == MOD_TYPE_669) ? 2 : 4; - if(!PeriodsAreFrequencies()) - delta = -delta; + const int32 actualDelta = PeriodsAreFrequencies() ? delta : -delta; if(chn.nPeriod < chn.nPortamentoDest || chn.portaTargetReached) { - DoFreqSlide(chn, chn.nPeriod, delta, true); + DoFreqSlide(chn, chn.nPeriod, actualDelta, true); if(chn.nPeriod > chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest; } else if(chn.nPeriod > chn.nPortamentoDest) { - DoFreqSlide(chn, chn.nPeriod, -delta, true); + DoFreqSlide(chn, chn.nPeriod, -actualDelta, true); if(chn.nPeriod < chn.nPortamentoDest) chn.nPeriod = chn.nPortamentoDest; // FT2 compatibility: Reaching portamento target from below forces subsequent portamentos on the same note to use the logic for reaching the note from above instead. @@ -4127,6 +4264,7 @@ void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const if(chn.nPeriod == chn.nPortamentoDest && (m_playBehaviour[kITPortaTargetReached] || GetType() == MOD_TYPE_MOD)) chn.nPortamentoDest = 0; + return doPorta ? delta : 0; } @@ -4466,9 +4604,23 @@ void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param) } break; // E1x: Fine Portamento Up - case 0x10: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(chn, param); break; + case 0x10: + if(param || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) + { + FinePortamentoUp(chn, param); + if(!m_playBehaviour[kPluginIgnoreTonePortamento]) + MidiPortamento(nChn, 0xF0 | param, true); + } + break; // E2x: Fine Portamento Down - case 0x20: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(chn, param); break; + case 0x20: + if(param || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) + { + FinePortamentoDown(chn, param); + if(!m_playBehaviour[kPluginIgnoreTonePortamento]) + MidiPortamento(nChn, -static_cast(0xF0 | param), true); + } + break; // E3x: Set Glissando Control case 0x30: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break; // E4x: Set Vibrato WaveForm @@ -4648,7 +4800,7 @@ void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param) IMixPlugin *pPlugin; if(pIns != nullptr && pIns->nMixPlug && (pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin) != nullptr) { - pPlugin->MidiCommand(*pIns, bkChn.nNote + NOTE_MAX_SPECIAL, 0, nChn); + pPlugin->MidiCommand(*pIns, bkChn.nNote | IMixPlugin::MIDI_NOTE_OFF, 0, nChn); } #endif // NO_PLUGINS } @@ -5538,6 +5690,14 @@ void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset) if(param < 0x100) resetEnv = true; } + // ProTracker Compatibility: Retrigger with lone instrument number causes instant sample change + // Test case: InstrSwapRetrigger.mod + if(m_playBehaviour[kMODSampleSwap] && chn.rowCommand.instr) + { + auto oldFineTune = chn.nFineTune; + InstrumentChange(chn, chn.rowCommand.instr, false, false); + chn.nFineTune = oldFineTune; + } const bool fading = chn.dwFlags[CHN_NOTEFADE]; const auto oldPrevNoteOffset = chn.prevNoteOffset; @@ -5699,7 +5859,7 @@ void CSoundFile::NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample) chn.dwFlags.set(CHN_FASTVOLRAMP); // instro sends to a midi chan - SendMIDINote(nChn, /*chn.nNote+*/NOTE_MAX_SPECIAL, 0); + SendMIDINote(nChn, NOTE_KEYOFF, 0); if(chn.dwFlags[CHN_ADLIB] && m_opl) { @@ -6294,7 +6454,7 @@ void CSoundFile::UpdateTimeSignature() } -void CSoundFile::PortamentoMPT(ModChannel &chn, int param) +void CSoundFile::PortamentoMPT(ModChannel &chn, int param) const { //Behavior: Modifies portamento by param-steps on every tick. //Note that step meaning depends on tuning. @@ -6304,18 +6464,19 @@ void CSoundFile::PortamentoMPT(ModChannel &chn, int param) } -void CSoundFile::PortamentoFineMPT(ModChannel &chn, int param) +void CSoundFile::PortamentoFineMPT(PlayState &playState, CHANNELINDEX nChn, int param) const { + ModChannel &chn = playState.Chn[nChn]; //Behavior: Divides portamento change between ticks/row. For example //if Ticks/row == 6, and param == +-6, portamento goes up/down by one tuning-dependent //fine step every tick. - if(m_PlayState.m_nTickCount == 0) + if(playState.m_nTickCount == 0) chn.nOldFinePortaUpDown = 0; - const int tickParam = static_cast((m_PlayState.m_nTickCount + 1.0) * param / m_PlayState.m_nMusicSpeed); + const int tickParam = static_cast((playState.m_nTickCount + 1.0) * param / playState.m_nMusicSpeed); chn.m_PortamentoFineSteps += (param >= 0) ? tickParam - chn.nOldFinePortaUpDown : tickParam + chn.nOldFinePortaUpDown; - if(m_PlayState.m_nTickCount + 1 == m_PlayState.m_nMusicSpeed) + if(playState.m_nTickCount + 1 == playState.m_nMusicSpeed) chn.nOldFinePortaUpDown = static_cast(std::abs(param)); else chn.nOldFinePortaUpDown = static_cast(std::abs(tickParam)); @@ -6324,7 +6485,7 @@ void CSoundFile::PortamentoFineMPT(ModChannel &chn, int param) } -void CSoundFile::PortamentoExtraFineMPT(ModChannel &chn, int param) +void CSoundFile::PortamentoExtraFineMPT(ModChannel &chn, int param) const { // This kinda behaves like regular fine portamento. // It changes the pitch by n finetune steps on the first tick. diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp index 366237e82..dd722f97b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.cpp @@ -18,6 +18,9 @@ #include "../mptrack/Mainfrm.h" #endif // MODPLUG_TRACKER #ifdef MPT_EXTERNAL_SAMPLES +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" +#include "../common/mptFileIO.h" #include "../common/mptFileIO.h" #endif // MPT_EXTERNAL_SAMPLES #include "../common/version.h" @@ -54,19 +57,47 @@ bool SettingCacheCompleteFileBeforeLoading() } -mpt::ustring FileHistory::AsISO8601() const +mpt::ustring FileHistory::AsISO8601(mpt::Date::LogicalTimezone internalTimezone) const { - tm date = loadDate; if(openTime > 0) { // Calculate the date when editing finished. double openSeconds = static_cast(openTime) / HISTORY_TIMER_PRECISION; - tm tmpLoadDate = loadDate; - int64 loadDateSinceEpoch = mpt::Date::Unix::FromUTC(tmpLoadDate); - int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); - date = mpt::Date::Unix(saveDateSinceEpoch).AsUTC(); + mpt::Date::AnyGregorian tmpLoadDate = loadDate; + if (internalTimezone == mpt::Date::LogicalTimezone::UTC) + { + int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(tmpLoadDate))); + int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); + return mpt::Date::ToShortenedISO8601(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds(saveDateSinceEpoch))); +#ifdef MODPLUG_TRACKER + } else if(internalTimezone == mpt::Date::LogicalTimezone::Local) + { + int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromLocal(mpt::Date::interpret_as_timezone(tmpLoadDate))); + int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); + return mpt::Date::ToShortenedISO8601(mpt::Date::UnixAsLocal(mpt::Date::UnixFromSeconds(saveDateSinceEpoch))); +#endif // MODPLUG_TRACKER + } else + { + // assume UTC for unspecified timezone when calculating + int64 loadDateSinceEpoch = mpt::Date::UnixAsSeconds(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(tmpLoadDate))); + int64 saveDateSinceEpoch = loadDateSinceEpoch + mpt::saturate_round(openSeconds); + return mpt::Date::ToShortenedISO8601(mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds(saveDateSinceEpoch)))); + } + } else + { + if(internalTimezone == mpt::Date::LogicalTimezone::UTC) + { + return mpt::Date::ToShortenedISO8601(mpt::Date::interpret_as_timezone(loadDate)); +#ifdef MODPLUG_TRACKER + } else if(internalTimezone == mpt::Date::LogicalTimezone::Local) + { + return mpt::Date::ToShortenedISO8601(mpt::Date::interpret_as_timezone(loadDate)); +#endif // MODPLUG_TRACKER + } else + { + return mpt::Date::ToShortenedISO8601(loadDate); + } } - return mpt::Date::ToShortenedISO8601(date); } @@ -91,12 +122,12 @@ CSoundFile::CSoundFile() : m_pModSpecs(&ModSpecs::itEx), m_nType(MOD_TYPE_NONE), Patterns(*this), -#ifdef MODPLUG_TRACKER - m_MIDIMapper(*this), -#endif Order(*this), m_PRNG(mpt::make_prng(mpt::global_prng())), m_visitedRows(*this) +#ifdef MODPLUG_TRACKER + , m_MIDIMapper(*this) +#endif { MemsetZero(MixSoundBuffer); MemsetZero(MixRearBuffer); @@ -151,6 +182,11 @@ void CSoundFile::InitializeGlobals(MODTYPE type) MODTYPE bestType = GetBestSaveFormat(); m_playBehaviour = GetDefaultPlaybackBehaviour(bestType); + if(bestType == MOD_TYPE_IT && type != bestType) + { + // This is such an odd behaviour that it's unlikely that any of the other formats will need it by default. Re-enable as needed. + m_playBehaviour.reset(kITInitialNoteMemory); + } SetModSpecsPointer(m_pModSpecs, bestType); // Delete instruments in case some previously called loader already created them. @@ -160,7 +196,7 @@ void CSoundFile::InitializeGlobals(MODTYPE type) Instruments[i] = nullptr; } - m_ContainerType = MOD_CONTAINERTYPE_NONE; + m_ContainerType = ModContainerType::None; m_nChannels = 0; m_nInstruments = 0; m_nSamples = 0; @@ -263,6 +299,8 @@ static constexpr FileFormatLoader ModuleFormatLoaders[] = MPT_DECLARE_FORMAT(PLM), MPT_DECLARE_FORMAT(AM), MPT_DECLARE_FORMAT(J2B), + MPT_DECLARE_FORMAT(GT2), + MPT_DECLARE_FORMAT(GTK), MPT_DECLARE_FORMAT(PT36), MPT_DECLARE_FORMAT(SymMOD), MPT_DECLARE_FORMAT(MUS_KM), @@ -274,9 +312,12 @@ static constexpr FileFormatLoader ModuleFormatLoaders[] = MPT_DECLARE_FORMAT(MOD), MPT_DECLARE_FORMAT(ICE), MPT_DECLARE_FORMAT(669), + MPT_DECLARE_FORMAT(667), MPT_DECLARE_FORMAT(C67), MPT_DECLARE_FORMAT(MO3), + MPT_DECLARE_FORMAT(DSm), MPT_DECLARE_FORMAT(M15), + MPT_DECLARE_FORMAT(XMF), }; #undef MPT_DECLARE_FORMAT @@ -365,7 +406,7 @@ CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span= ProbeRecommendedSize)) { - // If the prober wants more daat but we already provided the recommended required maximum, + // If the prober wants more data but we already provided the recommended required maximum, // just return success as this is the best we can do for the suggestesd probing size. result = ProbeSuccess; } @@ -398,13 +439,25 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags, CModDoc *pMo CUnarchiver unarchiver(file); if(unarchiver.ExtractBestFile(GetSupportedExtensions(true))) { - if(CreateInternal(unarchiver.GetOutputFile(), loadFlags)) + FileReader outputFile = unarchiver.GetOutputFile(); +#if defined(MPT_WITH_ANCIENT) + // Special case for MMCMP/PP20/XPK/etc. inside ZIP/RAR/LHA + std::unique_ptr ancientArchive; + if(!unarchiver.IsKind()) + { + ancientArchive = std::make_unique(outputFile); + if(ancientArchive->IsArchive() && ancientArchive->ExtractFile(0)) + outputFile = ancientArchive->GetOutputFile(); + } +#endif + if(CreateInternal(outputFile, loadFlags)) { // Read archive comment if there is no song comment if(m_songMessage.empty()) { m_songMessage.assign(mpt::ToCharset(mpt::Charset::Locale, unarchiver.GetComment())); } + m_ContainerType = ModContainerType::Generic; return true; } } @@ -420,17 +473,17 @@ bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) if(file.IsValid()) { std::vector containerItems; - MODCONTAINERTYPE packedContainerType = MOD_CONTAINERTYPE_NONE; + ModContainerType packedContainerType = ModContainerType::None; if(!(loadFlags & skipContainer)) { ContainerLoadingFlags containerLoadFlags = (loadFlags == onlyVerifyHeader) ? ContainerOnlyVerifyHeader : ContainerUnwrapData; #if !defined(MPT_WITH_ANCIENT) - if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackXPK(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_XPK; - if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackPP20(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_PP20; - if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackMMCMP(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_MMCMP; + if(packedContainerType == ModContainerType::None && UnpackXPK(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::XPK; + if(packedContainerType == ModContainerType::None && UnpackPP20(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::PP20; + if(packedContainerType == ModContainerType::None && UnpackMMCMP(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::MMCMP; #endif // !MPT_WITH_ANCIENT - if(packedContainerType == MOD_CONTAINERTYPE_NONE && UnpackUMX(containerItems, file, containerLoadFlags)) packedContainerType = MOD_CONTAINERTYPE_UMX; - if(packedContainerType != MOD_CONTAINERTYPE_NONE) + if(packedContainerType == ModContainerType::None && UnpackUMX(containerItems, file, containerLoadFlags)) packedContainerType = ModContainerType::UMX; + if(packedContainerType != ModContainerType::None) { if(loadFlags == onlyVerifyHeader) { @@ -462,14 +515,14 @@ bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) if(!loaderSuccess) { m_nType = MOD_TYPE_NONE; - m_ContainerType = MOD_CONTAINERTYPE_NONE; + m_ContainerType = ModContainerType::None; } if(loadFlags == onlyVerifyHeader) { return loaderSuccess; } - if(packedContainerType != MOD_CONTAINERTYPE_NONE && m_ContainerType == MOD_CONTAINERTYPE_NONE) + if(packedContainerType != ModContainerType::None && m_ContainerType == ModContainerType::None) { m_ContainerType = packedContainerType; } @@ -481,8 +534,50 @@ bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) InitializeGlobals(); m_visitedRows.Initialize(true); m_dwCreatedWithVersion = Version::Current(); +#if MPT_TIME_UTC_ON_DISK +#ifdef MODPLUG_TRACKER + if(GetType() & MOD_TYPE_IT) + { + m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; + } else + { + m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; + } +#else // !MODPLUG_TRACKER + if (GetType() & MOD_TYPE_IT) + { + m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; + } else + { + m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; + } +#endif // MODPLUG_TRACKER +#else +#ifdef MODPLUG_TRACKER + m_modFormat.timezone = mpt::Date::LogicalTimezone::Local; +#else // !MODPLUG_TRACKER + m_modFormat.timezone = mpt::Date::LogicalTimezone::Unspecified; +#endif // MODPLUG_TRACKER +#endif } +#if MPT_TIME_UTC_ON_DISK +#ifdef MODPLUG_TRACKER + // convert timestamps to UTC + if(m_modFormat.timezone == mpt::Date::LogicalTimezone::Local) + { + for(auto & fileHistoryEntry : m_FileHistory) + { + if(fileHistoryEntry.HasValidDate()) + { + fileHistoryEntry.loadDate = mpt::Date::forget_timezone(mpt::Date::UnixAsUTC(mpt::Date::UnixFromLocal(mpt::Date::interpret_as_timezone(fileHistoryEntry.loadDate)))); + } + } + m_modFormat.timezone = mpt::Date::LogicalTimezone::UTC; + } +#endif // MODPLUG_TRACKER +#endif + // Adjust channels const auto muteFlag = GetChannelMuteFlag(); for(CHANNELINDEX chn = 0; chn < MAX_BASECHANNELS; chn++) @@ -506,10 +601,10 @@ bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) mpt::PathString filename = GetSamplePath(nSmp); if(file.GetOptionalFileName()) { - filename = filename.RelativePathToAbsolute(file.GetOptionalFileName()->GetPath()); + filename = mpt::RelativePathToAbsolute(filename, file.GetOptionalFileName()->GetDirectoryWithDrive()); } else if(GetpModDoc() != nullptr) { - filename = filename.RelativePathToAbsolute(GetpModDoc()->GetPathNameMpt().GetPath()); + filename = mpt::RelativePathToAbsolute(filename, GetpModDoc()->GetPathNameMpt().GetDirectoryWithDrive()); } filename = filename.Simplify(); if(!LoadExternalSample(nSmp, filename)) @@ -560,6 +655,8 @@ bool CSoundFile::CreateInternal(FileReader file, ModLoadingFlags loadFlags) if(!m_nDefaultSpeed) m_nDefaultSpeed = 6; + if(!m_nDefaultRowsPerBeat && m_nTempoMode == TempoMode::Modern) + m_nDefaultRowsPerBeat = 1; if(m_nDefaultRowsPerMeasure < m_nDefaultRowsPerBeat) m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat; LimitMax(m_nDefaultRowsPerBeat, MAX_ROWS_PER_BEAT); @@ -737,7 +834,7 @@ bool CSoundFile::Destroy() #endif // NO_PLUGINS m_nType = MOD_TYPE_NONE; - m_ContainerType = MOD_CONTAINERTYPE_NONE; + m_ContainerType = ModContainerType::None; m_nChannels = m_nSamples = m_nInstruments = 0; return true; } @@ -1075,6 +1172,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type) playBehaviour.set(kITDCTBehaviour); playBehaviour.set(kITPitchPanSeparation); playBehaviour.set(kITResetFilterOnPortaSmpChange); + playBehaviour.set(kITInitialNoteMemory); if(type == MOD_TYPE_MPT) { playBehaviour.set(kOPLFlexibleNoteOff); @@ -1143,6 +1241,7 @@ PlayBehaviourSet CSoundFile::GetSupportedPlaybackBehaviour(MODTYPE type) playBehaviour.set(kST3SampleSwap); playBehaviour.set(kOPLNoteOffOnNoteChange); playBehaviour.set(kApplyUpperPeriodLimit); + playBehaviour.set(kST3TonePortaWithAdlibNote); break; case MOD_TYPE_MOD: @@ -1508,7 +1607,7 @@ std::unique_ptr CSoundFile::CreateTuning12TET(const mpt::ustring &name) } -mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const +mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst, const NoteName *noteNames) const { // For MPTM instruments with custom tuning, find the appropriate note name. Else, use default note names. if(ModCommand::IsNote(note) && GetType() == MOD_TYPE_MPT && inst >= 1 && inst <= GetNumInstruments() && Instruments[inst] && Instruments[inst]->pTuning) @@ -1516,7 +1615,7 @@ mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const INSTRUME return Instruments[inst]->pTuning->GetNoteName(note - NOTE_MIDDLEC); } else { - return GetNoteName(note); + return GetNoteName(note, noteNames ? noteNames : m_NoteNames); } } @@ -1540,7 +1639,7 @@ mpt::ustring CSoundFile::GetNoteName(const ModCommand::NOTE note, const NoteName { return mpt::ustring() .append(noteNames[(note - NOTE_MIN) % 12]) - .append(1, UC_('0') + (note - NOTE_MIN) / 12) + .append(1, static_cast(UC_('0') + ((note - NOTE_MIN) / 12))) ; // e.g. "C#" + "5" } else if(note == NOTE_NONE) { @@ -1632,7 +1731,7 @@ void CSoundFile::ChangeModTypeTo(const MODTYPE newType, bool adjust) Order.OnModTypeChanged(oldType); Patterns.OnModTypeChanged(oldType); - m_modFormat.type = mpt::ToUnicode(mpt::Charset::UTF8, GetModSpecifications().fileExtension); + m_modFormat.type = GetModSpecifications().GetFileExtension(); } #endif // MODPLUG_TRACKER @@ -1749,7 +1848,7 @@ uint32 CSoundFile::GetTickDuration(PlayState &playState) const case TempoMode::Modern: { - double accurateBufferCount = static_cast(m_MixerSettings.gdwMixingFreq) * (60.0 / (playState.m_nMusicTempo.ToDouble() * Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat))); + double accurateBufferCount = static_cast(m_MixerSettings.gdwMixingFreq) * (60.0 / (playState.m_nMusicTempo.ToDouble() * static_cast(Util::mul32to64_unsigned(playState.m_nMusicSpeed, playState.m_nCurrentRowsPerBeat)))); const TempoSwing &swing = (Patterns.IsValidPat(playState.m_nPattern) && Patterns[playState.m_nPattern].HasTempoSwing()) ? Patterns[playState.m_nPattern].GetTempoSwing() : m_tempoSwing; @@ -1963,7 +2062,7 @@ void CSoundFile::PrecomputeSampleLoops(bool updateChannels) bool CSoundFile::LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename) { bool ok = false; - InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(filename, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h index aeb2f9933..2e52bf42d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndfile.h @@ -16,6 +16,7 @@ #include "SoundFilePlayConfig.h" #include "MixerSettings.h" #include "../common/misc_util.h" +#include "../common/mptFileType.h" #include "../common/mptRandom.h" #include "../common/version.h" #include @@ -243,13 +244,16 @@ class CModDoc; struct FileHistory { // Date when the file was loaded in the the tracker or created. - tm loadDate = {}; + mpt::Date::AnyGregorian loadDate = {}; // Time the file was open in the editor, in 1/18.2th seconds (frequency of a standard DOS timer, to keep compatibility with Impulse Tracker easy). uint32 openTime = 0; // Return the date as a (possibly truncated if not enough precision is available) ISO 8601 formatted date. - mpt::ustring AsISO8601() const; + mpt::ustring AsISO8601(mpt::Date::LogicalTimezone internalTimezone) const; // Returns true if the date component is valid. Some formats only store edit time, not edit date. - bool HasValidDate() const { return loadDate.tm_mday != 0; } + bool HasValidDate() const + { + return loadDate != mpt::Date::AnyGregorian{}; + } }; @@ -282,6 +286,7 @@ struct ModFormatDetails mpt::ustring originalFormatName; // "FastTracker 2" in the case of converted formats like MO3 or GDM mpt::ustring originalType; // "xm" in the case of converted formats like MO3 or GDM mpt::Charset charset = mpt::Charset::UTF8; + mpt::Date::LogicalTimezone timezone = mpt::Date::LogicalTimezone::Unspecified; }; @@ -377,7 +382,7 @@ public: static CTuning *GetDefaultTuning() {return nullptr;} CTuningCollection& GetTuneSpecificTunings() {return *m_pTuningsTuneSpecific;} - mpt::ustring GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const; + mpt::ustring GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst, const NoteName *noteNames = nullptr) const; mpt::ustring GetNoteName(const ModCommand::NOTE note) const; static mpt::ustring GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames); #ifdef MODPLUG_TRACKER @@ -398,15 +403,6 @@ private: private: CTuningCollection* m_pTuningsTuneSpecific = nullptr; -#ifdef MODPLUG_TRACKER -public: - CMIDIMapper& GetMIDIMapper() {return m_MIDIMapper;} - const CMIDIMapper& GetMIDIMapper() const {return m_MIDIMapper;} -private: - CMIDIMapper m_MIDIMapper; - -#endif // MODPLUG_TRACKER - private: //Misc private methods. static void SetModSpecsPointer(const CModSpecifications* &pModSpecs, const MODTYPE type); @@ -457,7 +453,7 @@ public: // for Editing #endif // MODPLUG_TRACKER Enum m_nType; private: - MODCONTAINERTYPE m_ContainerType = MOD_CONTAINERTYPE_NONE; + ModContainerType m_ContainerType = ModContainerType::None; public: CHANNELINDEX m_nChannels = 0; SAMPLEINDEX m_nSamples = 0; @@ -509,8 +505,8 @@ public: ModInstrument *Instruments[MAX_INSTRUMENTS]; // Instrument Headers MIDIMacroConfig m_MidiCfg; // MIDI Macro config table #ifndef NO_PLUGINS - SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS]; // Mix plugins - uint32 m_loadedPlugins = 0; // Not a PLUGINDEX because number of loaded plugins may exceed MAX_MIXPLUGINS during MIDI conversion + std::array m_MixPlugins; // Mix plugins + uint32 m_loadedPlugins = 0; // Not a PLUGINDEX because number of loaded plugins may exceed MAX_MIXPLUGINS during MIDI conversion #endif mpt::charbuf m_szNames[MAX_SAMPLES]; // Sample names @@ -626,6 +622,14 @@ public: std::unique_ptr m_opl; +#ifdef MODPLUG_TRACKER +public: + CMIDIMapper& GetMIDIMapper() { return m_MIDIMapper; } + const CMIDIMapper& GetMIDIMapper() const { return m_MIDIMapper; } +private: + CMIDIMapper m_MIDIMapper; +#endif // MODPLUG_TRACKER + public: #ifdef LIBOPENMPT_BUILD #ifndef NO_PLUGINS @@ -735,7 +739,7 @@ public: bool Destroy(); Enum GetType() const noexcept { return m_nType; } - MODCONTAINERTYPE GetContainerType() const noexcept { return m_ContainerType; } + ModContainerType GetContainerType() const noexcept { return m_ContainerType; } // rough heuristic, could be improved mpt::Charset GetCharsetFile() const // 8bit string encoding of strings in the on-disk file @@ -750,6 +754,10 @@ public: return GetCharsetFile(); #endif // MODPLUG_TRACKER } + mpt::Date::LogicalTimezone GetTimezoneInternal() const + { + return m_modFormat.timezone; + } ModMessageHeuristicOrder GetMessageHeuristic() const; @@ -828,6 +836,7 @@ public: #endif // !MPT_WITH_ANCIENT static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64* pfilesize); + static ProbeResult ProbeFileHeader667(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize); @@ -840,10 +849,13 @@ public: static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize); + static ProbeResult ProbeFileHeaderDSm(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderDSym(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderFMT(MemoryFileReader file, const uint64* pfilesize); static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize); + static ProbeResult ProbeFileHeaderGT2(MemoryFileReader file, const uint64 *pfilesize); + static ProbeResult ProbeFileHeaderGTK(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize); @@ -871,12 +883,14 @@ public: static ProbeResult ProbeFileHeaderSymMOD(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize); + static ProbeResult ProbeFileHeaderXMF(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderMID(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderUAX(MemoryFileReader file, const uint64 *pfilesize); static ProbeResult ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize); // Module Loaders + bool Read667(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); @@ -889,10 +903,13 @@ public: bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadDSm(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadDSym(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFAR(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadFMT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadGDM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadGT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadGTK(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadICE(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadIMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); @@ -920,6 +937,7 @@ public: bool ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadULT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadXMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); @@ -927,8 +945,8 @@ public: static std::vector GetSupportedExtensions(bool otherFormats); static bool IsExtensionSupported(std::string_view ext); // UTF8, casing of ext is ignored - static mpt::ustring ModContainerTypeToString(MODCONTAINERTYPE containertype); - static mpt::ustring ModContainerTypeToTracker(MODCONTAINERTYPE containertype); + static mpt::ustring ModContainerTypeToString(ModContainerType containertype); + static mpt::ustring ModContainerTypeToTracker(ModContainerType containertype); // Repair non-standard stuff in modules saved with previous ModPlug versions void UpgradeModule(); @@ -944,7 +962,7 @@ public: void SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments, std::ostream &f) const; void SaveExtendedSongProperties(std::ostream &f) const; #endif // MODPLUG_NO_FILESAVE - void LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool* pInterpretMptMade = nullptr); + bool LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool* pInterpretMptMade = nullptr); void LoadMPTMProperties(FileReader &file, uint16 cwtv); static mpt::ustring GetSchismTrackerVersion(uint16 cwtv, uint32 reserved); @@ -959,12 +977,14 @@ public: // MOD Convert function MODTYPE GetBestSaveFormat() const; - static void ConvertModCommand(ModCommand &m); - static void S3MConvert(ModCommand &m, bool fromIT); - void S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool compatibilityExport = false) const; - void ModSaveCommand(uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport = false) const; - static void ReadMODPatternEntry(FileReader &file, ModCommand &m); - static void ReadMODPatternEntry(const std::array data, ModCommand &m); + static void ConvertModCommand(ModCommand &m, const uint8 command, const uint8 param); + static void S3MConvert(ModCommand &m, const uint8 command, const uint8 param, const bool fromIT); + void S3MSaveConvert(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toIT, const bool compatibilityExport = false) const; + void ModSaveCommand(const ModCommand &source, uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport = false) const; + // Reads 4 bytes formatted like SoundTracker/NoiseTracker/ProTracker pattern data, converts the period to a note, fills the instrument number and returns the effect command and parameter bytes. + static std::pair ReadMODPatternEntry(FileReader &file, ModCommand &m); + // Converts 4 bytes formatted like SoundTracker/NoiseTracker/ProTracker pattern data by converting the period to a note and filling the instrument number, and returns the effect command and parameter bytes. + static std::pair ReadMODPatternEntry(const std::array data, ModCommand &m); void SetupMODPanning(bool bForceSetup = false); // Setup LRRL panning, max channel volume @@ -998,7 +1018,7 @@ public: bool IsRenderingToDisc() const { return m_bIsRendering; } void PrecomputeSampleLoops(bool updateChannels = false); - void UpdateInstrumentFilter(const ModInstrument *ins, bool updateMode, bool updateCutoff, bool updateResonance); + void UpdateInstrumentFilter(const ModInstrument &ins, bool updateMode, bool updateCutoff, bool updateResonance); public: // Mixer Config @@ -1077,21 +1097,24 @@ protected: }; // Channel Effects void UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param) const; - void PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular = false); - void PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular = false); - void MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides); + void PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular); + void PortamentoUp(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const; + void PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular); + void PortamentoDown(PlayState &playState, CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular) const; + void MidiPortamento(CHANNELINDEX nChn, int param, const bool doFineSlides); void FinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const; void FinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const; void ExtraFinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const; void ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const; - void PortamentoMPT(ModChannel &chn, int); - void PortamentoFineMPT(ModChannel &chn, int); - void PortamentoExtraFineMPT(ModChannel &chn, int); + void PortamentoMPT(ModChannel &chn, int param) const; + void PortamentoFineMPT(PlayState &playState, CHANNELINDEX nChn, int param) const; + void PortamentoExtraFineMPT(ModChannel &chn, int param) const; void SetFinetune(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel, PlayState &playState, bool isSmooth) const; int16 CalculateFinetuneTarget(PATTERNINDEX pattern, ROWINDEX row, CHANNELINDEX channel) const; void NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const; std::pair GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const; - void TonePortamento(ModChannel &chn, uint16 param) const; + void TonePortamento(CHANNELINDEX chn, uint16 param); + int32 TonePortamento(PlayState &playState, CHANNELINDEX nChn, uint16 param) const; void Vibrato(ModChannel &chn, uint32 param) const; void FineVibrato(ModChannel &chn, uint32 param) const; void VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const; @@ -1127,6 +1150,7 @@ protected: void SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume); int SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier = 256) const; + int HandleNoteChangeFilter(ModChannel &chn) const; // Low-Level effect processing void DoFreqSlide(ModChannel &chn, int32 &period, int32 amount, bool isTonePorta = false) const; @@ -1136,7 +1160,7 @@ public: // Convert frequency to IT cutoff (0...127) uint8 FrequencyToCutOff(double frequency) const; // Convert IT cutoff (0...127 + modifier) to frequency - uint32 CutOffToFrequency(uint32 nCutOff, int envModifier = 256) const; // [0-127] => [1-10KHz] + float CutOffToFrequency(uint32 nCutOff, int envModifier = 256) const; // Returns true if periods are actually plain frequency values in Hz. bool PeriodsAreFrequencies() const noexcept @@ -1144,7 +1168,7 @@ public: return m_playBehaviour[kPeriodsAreHertz] && !UseFinetuneAndTranspose(); } - // Returns true if the current format uses transpose+finetune rather than frequency in Hz to specify middle-C. + // Returns true if the format uses transpose+finetune rather than frequency in Hz to specify middle-C. static constexpr bool UseFinetuneAndTranspose(MODTYPE type) noexcept { return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP | MOD_TYPE_XM)); @@ -1154,6 +1178,16 @@ public: return UseFinetuneAndTranspose(GetType()); } + // Returns true if the format uses combined commands for fine and regular portamento slides + static constexpr bool UseCombinedPortamentoCommands(MODTYPE type) noexcept + { + return !(type & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)); + } + bool UseCombinedPortamentoCommands() const noexcept + { + return UseCombinedPortamentoCommands(GetType()); + } + bool DestroySample(SAMPLEINDEX nSample); bool DestroySampleThreadsafe(SAMPLEINDEX nSample); @@ -1189,7 +1223,7 @@ protected: bool ReadXISample(SAMPLEINDEX nSample, FileReader &file); bool ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind = true); bool ReadITISample(SAMPLEINDEX nSample, FileReader &file); - bool ReadIFFSample(SAMPLEINDEX sample, FileReader &file); + bool ReadIFFSample(SAMPLEINDEX sample, FileReader &file, bool allowLittleEndian = true); bool ReadBRRSample(SAMPLEINDEX sample, FileReader &file); bool ReadFLACSample(SAMPLEINDEX sample, FileReader &file); bool ReadOpusSample(SAMPLEINDEX sample, FileReader &file); @@ -1205,6 +1239,7 @@ public: bool SaveRAWSample(SAMPLEINDEX nSample, std::ostream &f) const; bool SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const; bool SaveS3ISample(SAMPLEINDEX smp, std::ostream &f) const; + bool SaveIFFSample(SAMPLEINDEX smp, std::ostream &f) const; #endif // Instrument file I/O @@ -1239,14 +1274,14 @@ public: uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns); size_t ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers); - bool LoadMixPlugins(FileReader &file); + std::pair LoadMixPlugins(FileReader &file); #ifndef NO_PLUGINS static void ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin); void ProcessMidiOut(CHANNELINDEX nChn); #endif // NO_PLUGINS - void ProcessGlobalVolume(long countChunk); - void ProcessStereoSeparation(long countChunk); + void ProcessGlobalVolume(samplecount_t countChunk); + void ProcessStereoSeparation(samplecount_t countChunk); private: PLUGINDEX GetChannelPlugin(const PlayState &playState, CHANNELINDEX nChn, PluginMutePriority respectMutes) const; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp index 85cc0b22d..3207d3ea8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Sndmix.cpp @@ -692,6 +692,17 @@ bool CSoundFile::ProcessRow() // Test case: NoteDelay-NextRow.mod pChn->nPeriod = GetPeriodFromNote(pChn->rowCommand.note, pChn->nFineTune, 0); } + if(m_playBehaviour[kST3TonePortaWithAdlibNote] + && !m->IsNote() + && pChn->dwFlags[CHN_ADLIB] + && pChn->nPortamentoDest + && pChn->rowCommand.IsNote() + && pChn->rowCommand.IsPortamento()) + { + // ST3: Adlib Note + Tone Portamento does not execute the slide, but changes to the target note instantly on the next row (unless there is another note with tone portamento) + // Test case: TonePortamentoWithAdlibNote.s3m + pChn->nPeriod = pChn->nPortamentoDest; + } if(m_playBehaviour[kMODTempoOnSecondTick] && !m_playBehaviour[kMODVBlankTiming] && m_PlayState.m_nMusicSpeed == 1 && pChn->rowCommand.command == CMD_TEMPO) { // ProTracker sets the tempo after the first tick. This block handles the case of one tick per row. @@ -1047,7 +1058,7 @@ void CSoundFile::ProcessTremor(CHANNELINDEX nChn, int &vol) { const bool isPlaying = pPlugin->IsNotePlaying(chn.nLastNote, nChn); if(vol == 0 && isPlaying) - pPlugin->MidiCommand(*pIns, chn.nLastNote + NOTE_MAX_SPECIAL, 0, nChn); + pPlugin->MidiCommand(*pIns, chn.nLastNote | IMixPlugin::MIDI_NOTE_OFF, 0, nChn); else if(vol != 0 && !isPlaying) pPlugin->MidiCommand(*pIns, chn.nLastNote, static_cast(chn.nVolume), nChn); } @@ -1172,7 +1183,7 @@ int CSoundFile::ProcessPitchFilterEnvelope(ModChannel &chn, int32 &period) const #else // TODO: AMS2 envelopes behave differently when linear slides are off - emulate with 15 * (-128...127) >> 6 // Copy over vibrato behaviour for that? - const int32 range = GetType() == MOD_TYPE_AMS ? uint8_max : ENVELOPE_MAX; + const int32 range = GetType() == MOD_TYPE_AMS ? uint8_max : uint8(ENVELOPE_MAX); int32 amp; switch(GetType()) { @@ -1444,17 +1455,17 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEI IMixPlugin *pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin; if(pPlugin) { - uint8 step = 0; const bool arpOnRow = (chn.rowCommand.command == CMD_ARPEGGIO); - const ModCommand::NOTE lastNote = ModCommand::IsNote(chn.nLastNote) ? static_cast(pIns->NoteMap[chn.nLastNote - NOTE_MIN]) : static_cast(NOTE_NONE); + const ModCommand::NOTE lastNote = chn.lastMidiNoteWithoutArp; + ModCommand::NOTE arpNote = chn.lastMidiNoteWithoutArp; if(arpOnRow) { - switch(m_PlayState.m_nTickCount % 3) + const uint32 tick = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay); + switch(tick % 3) { - case 1: step = chn.nArpeggio >> 4; break; - case 2: step = chn.nArpeggio & 0x0F; break; + case 1: arpNote += chn.nArpeggio >> 4; break; + case 2: arpNote += chn.nArpeggio & 0x0F; break; } - chn.nArpeggioBaseNote = lastNote; } // Trigger new note: @@ -1464,19 +1475,23 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEI // - If there's no arpeggio // - but an arpeggio note is still active and // - there's no note stop or new note that would stop it anyway - if((arpOnRow && chn.nArpeggioLastNote != chn.nArpeggioBaseNote + step && (!m_SongFlags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote())) - || (!arpOnRow && chn.rowCommand.note == NOTE_NONE && chn.nArpeggioLastNote != NOTE_NONE)) - SendMIDINote(nChn, chn.nArpeggioBaseNote + step, static_cast(chn.nVolume)); + if((arpOnRow && chn.nArpeggioLastNote != arpNote && (!chn.isFirstTick || !chn.rowCommand.IsNote() || chn.rowCommand.IsPortamento())) + || (!arpOnRow && (chn.rowCommand.note == NOTE_NONE || chn.rowCommand.IsPortamento()) && chn.nArpeggioLastNote != NOTE_NONE)) + SendMIDINote(nChn, arpNote | IMixPlugin::MIDI_NOTE_ARPEGGIO, static_cast(chn.nVolume)); // Stop note: // - If some arpeggio note is still registered or // - When starting an arpeggio on a row with no other note on it, stop some possibly still playing note. if(chn.nArpeggioLastNote != NOTE_NONE) - SendMIDINote(nChn, chn.nArpeggioLastNote + NOTE_MAX_SPECIAL, 0); - else if(arpOnRow && m_SongFlags[SONG_FIRSTTICK] && !chn.rowCommand.IsNote() && ModCommand::IsNote(lastNote)) - SendMIDINote(nChn, lastNote + NOTE_MAX_SPECIAL, 0); + { + if(!arpOnRow || chn.nArpeggioLastNote != arpNote) + SendMIDINote(nChn, chn.nArpeggioLastNote | IMixPlugin::MIDI_NOTE_OFF, 0); + } else if(arpOnRow && chn.isFirstTick && !chn.rowCommand.IsNote() && ModCommand::IsNote(lastNote)) + { + SendMIDINote(nChn, lastNote | IMixPlugin::MIDI_NOTE_OFF, 0); + } if(chn.rowCommand.command == CMD_ARPEGGIO) - chn.nArpeggioLastNote = chn.nArpeggioBaseNote + step; + chn.nArpeggioLastNote = arpNote; else chn.nArpeggioLastNote = NOTE_NONE; } @@ -1507,7 +1522,8 @@ void CSoundFile::ProcessArpeggio(CHANNELINDEX nChn, int32 &period, Tuning::NOTEI { //IT playback compatibility 01 & 02 - // Pattern delay restarts tick counting. Not quite correct yet! + // Pattern delay restarts tick counting. + // Test case: JxxTicks.it const uint32 tick = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay); if(chn.nArpeggio != 0) { @@ -1985,6 +2001,44 @@ void CSoundFile::ProcessRamping(ModChannel &chn) const } +int CSoundFile::HandleNoteChangeFilter(ModChannel &chn) const +{ + int cutoff = -1; + if(!chn.triggerNote) + return cutoff; + + bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE]; + if(const ModInstrument *pIns = chn.pModInstrument; pIns != nullptr) + { + if(pIns->IsResonanceEnabled()) + { + chn.nResonance = pIns->GetResonance(); + useFilter = true; + } + if(pIns->IsCutoffEnabled()) + { + chn.nCutOff = pIns->GetCutoff(); + useFilter = true; + } + if(useFilter && (pIns->filterMode != FilterMode::Unchanged)) + { + chn.nFilterMode = pIns->filterMode; + } + } else + { + chn.nVolSwing = chn.nPanSwing = 0; + chn.nCutSwing = chn.nResSwing = 0; + } + if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter) + { + cutoff = SetupChannelFilter(chn, true); + if(cutoff >= 0) + cutoff = chn.nCutOff / 2u; + } + return cutoff; +} + + // Returns channel increment and frequency with FREQ_FRACBITS fractional bits std::pair CSoundFile::GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const { @@ -2251,38 +2305,8 @@ bool CSoundFile::ReadNote() } // Setup Initial Filter for this note - int cutoff = -1; - if(chn.triggerNote) - { - bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE]; - if(pIns) - { - if(pIns->IsResonanceEnabled()) - { - chn.nResonance = pIns->GetResonance(); - useFilter = true; - } - if(pIns->IsCutoffEnabled()) - { - chn.nCutOff = pIns->GetCutoff(); - useFilter = true; - } - if(useFilter && (pIns->filterMode != FilterMode::Unchanged)) - { - chn.nFilterMode = pIns->filterMode; - } - } else - { - chn.nVolSwing = chn.nPanSwing = 0; - chn.nCutSwing = chn.nResSwing = 0; - } - if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter) - { - cutoff = SetupChannelFilter(chn, true); - if(cutoff >= 0) - cutoff = chn.nCutOff / 2u; - } - } + if(int cutoff = HandleNoteChangeFilter(chn); cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl) + m_opl->Volume(nChn, static_cast(cutoff), true); // Now that all relevant envelopes etc. have been processed, we can parse the MIDI macro data. ProcessMacroOnChannel(nChn); @@ -2291,14 +2315,11 @@ bool CSoundFile::ReadNote() if(samplePlaying) { int envCutoff = ProcessPitchFilterEnvelope(chn, period); - if(envCutoff >= 0) - cutoff = envCutoff / 4; + // Cutoff doubles as modulator intensity for FM instruments + if(envCutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl) + m_opl->Volume(nChn, static_cast(envCutoff / 4), true); } - // Cutoff doubles as modulator intensity for FM instruments - if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl) - m_opl->Volume(nChn, static_cast(cutoff), true); - if(chn.rowCommand.volcmd == VOLCMD_VIBRATODEPTH && (chn.rowCommand.command == CMD_VIBRATO || chn.rowCommand.command == CMD_VIBRATOVOL || chn.rowCommand.command == CMD_FINEVIBRATO)) { @@ -2611,12 +2632,12 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) // Check for volume commands uint8 vol = 0xFF; if(chn.rowCommand.volcmd == VOLCMD_VOLUME) - { vol = std::min(chn.rowCommand.vol, uint8(64)); - } else if(chn.rowCommand.command == CMD_VOLUME) - { + else if(chn.rowCommand.command == CMD_VOLUME) vol = std::min(chn.rowCommand.param, uint8(64)); - } + else if(chn.rowCommand.command == CMD_VOLUME8) + vol = static_cast((chn.rowCommand.param + 3u) / 4u); + const bool hasVolCommand = (vol != 0xFF); if(m_playBehaviour[kMIDICCBugEmulation]) @@ -2659,7 +2680,8 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) realNote = pIns->NoteMap[note - NOTE_MIN]; // Experimental VST panning //ProcessMIDIMacro(nChn, false, m_MidiCfg.Global[MIDIOUT_PAN], 0, nPlugin); - SendMIDINote(nChn, realNote, static_cast(velocity)); + if(m_playBehaviour[kPluginIgnoreTonePortamento] || !chn.rowCommand.IsPortamento()) + SendMIDINote(nChn, realNote, static_cast(velocity)); } const bool processVolumeAlsoOnNote = (pIns->pluginVelocityHandling == PLUGIN_VELOCITYHANDLING_VOLUME); @@ -2687,11 +2709,11 @@ void CSoundFile::ProcessMidiOut(CHANNELINDEX nChn) template -MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int32 *SoundBuffer, int32 *RearBuffer, int32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume) +MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int32 *SoundBuffer, int32 *RearBuffer, uint32 lCount, int32 m_nGlobalVolume, int32 step, int32 &m_nSamplesToGlobalVolRampDest, int32 &m_lHighResRampingGlobalVolume) { const bool isStereo = (channels >= 2); const bool hasRear = (channels >= 4); - for(int pos = 0; pos < lCount; ++pos) + for(uint32 pos = 0; pos < lCount; ++pos) { if(m_nSamplesToGlobalVolRampDest > 0) { @@ -2716,7 +2738,7 @@ MPT_FORCEINLINE void ApplyGlobalVolumeWithRamping(int32 *SoundBuffer, int32 *Rea } -void CSoundFile::ProcessGlobalVolume(long lCount) +void CSoundFile::ProcessGlobalVolume(samplecount_t lCount) { // should we ramp? @@ -2779,7 +2801,7 @@ void CSoundFile::ProcessGlobalVolume(long lCount) } -void CSoundFile::ProcessStereoSeparation(long countChunk) +void CSoundFile::ProcessStereoSeparation(samplecount_t countChunk) { ApplyStereoSeparation(MixSoundBuffer, MixRearBuffer, m_MixerSettings.gnChannels, countChunk, m_MixerSettings.m_nStereoSeparation); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp index 09aca4071..2c256585f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Tables.cpp @@ -42,7 +42,6 @@ const mpt::uchar NoteNamesFlat[12][4] = struct ModFormatInfo { - MODTYPE format; // MOD_TYPE_XXXX const mpt::uchar *name; // "ProTracker" const char *extension; // "mod" }; @@ -50,74 +49,80 @@ struct ModFormatInfo // Note: Formats with identical extensions must be grouped together. static constexpr ModFormatInfo modFormatInfo[] = { - { MOD_TYPE_MPT, UL_("OpenMPT"), "mptm" }, - { MOD_TYPE_MOD, UL_("ProTracker"), "mod" }, - { MOD_TYPE_S3M, UL_("Scream Tracker 3"), "s3m" }, - { MOD_TYPE_XM, UL_("FastTracker 2"), "xm" }, - { MOD_TYPE_IT, UL_("Impulse Tracker"), "it" }, + { UL_("OpenMPT"), "mptm" }, + { UL_("ProTracker"), "mod" }, + { UL_("Scream Tracker 3"), "s3m" }, + { UL_("FastTracker 2"), "xm" }, + { UL_("Impulse Tracker"), "it" }, - { MOD_TYPE_669, UL_("Composer 669 / UNIS 669"), "669" }, - { MOD_TYPE_AMF0, UL_("ASYLUM Music Format"), "amf" }, - { MOD_TYPE_AMF, UL_("DSMI Advanced Music Format"), "amf" }, - { MOD_TYPE_AMS, UL_("Extreme's Tracker"), "ams" }, - { MOD_TYPE_AMS, UL_("Velvet Studio"), "ams" }, - { MOD_TYPE_S3M, UL_("CDFM / Composer 670"), "c67" }, - { MOD_TYPE_DBM, UL_("DigiBooster Pro"), "dbm" }, - { MOD_TYPE_DIGI, UL_("DigiBooster"), "digi" }, - { MOD_TYPE_DMF, UL_("X-Tracker"), "dmf" }, - { MOD_TYPE_DSM, UL_("DSIK Format"), "dsm" }, - { MOD_TYPE_MOD, UL_("Digital Symphony"), "dsym" }, - { MOD_TYPE_DTM, UL_("Digital Tracker"), "dtm" }, - { MOD_TYPE_FAR, UL_("Farandole Composer"), "far" }, - { MOD_TYPE_S3M, UL_("FM Tracker"), "fmt" }, - { MOD_TYPE_IMF, UL_("Imago Orpheus"), "imf" }, - { MOD_TYPE_MOD, UL_("Ice Tracker"), "ice" }, + { UL_("Composer 667"), "667" }, + { UL_("Composer 669 / UNIS 669"), "669" }, + { UL_("ASYLUM Music Format"), "amf" }, + { UL_("DSMI Advanced Music Format"), "amf" }, + { UL_("Extreme's Tracker"), "ams" }, + { UL_("Velvet Studio"), "ams" }, + { UL_("CDFM / Composer 670"), "c67" }, + { UL_("DigiBooster Pro"), "dbm" }, + { UL_("DigiBooster"), "digi" }, + { UL_("X-Tracker"), "dmf" }, + { UL_("DSMI Compact Advanced Music Format"), "dmf" }, + { UL_("DSIK Format"), "dsm" }, + { UL_("Dynamic Studio"), "dsm" }, + { UL_("Digital Symphony"), "dsym" }, + { UL_("Digital Tracker"), "dtm" }, + { UL_("Farandole Composer"), "far" }, + { UL_("FM Tracker"), "fmt" }, + { UL_("Imago Orpheus"), "imf" }, + { UL_("Ice Tracker"), "ice" }, #ifdef MPT_EXTERNAL_SAMPLES - { MOD_TYPE_IT, UL_("Impulse Tracker Project"), "itp" }, + { UL_("Impulse Tracker Project"), "itp" }, #endif - { MOD_TYPE_J2B, UL_("Galaxy Sound System"), "j2b" }, - { MOD_TYPE_MOD, UL_("Soundtracker"), "m15" }, - { MOD_TYPE_MDL, UL_("Digitrakker"), "mdl" }, - { MOD_TYPE_MED, UL_("OctaMED"), "med" }, - { MOD_TYPE_SFX, UL_("MultiMedia Sound"), "mms" }, - { MOD_TYPE_MT2, UL_("MadTracker 2"), "mt2" }, - { MOD_TYPE_MTM, UL_("MultiTracker"), "mtm" }, - { MOD_TYPE_MOD, UL_("Karl Morton Music Format"), "mus" }, - { MOD_TYPE_MOD, UL_("NoiseTracker"), "nst" }, - { MOD_TYPE_OKT, UL_("Oktalyzer"), "okt" }, - { MOD_TYPE_PLM, UL_("Disorder Tracker 2"), "plm" }, - { MOD_TYPE_PSM, UL_("Epic Megagames MASI"), "psm" }, - { MOD_TYPE_MOD, UL_("ProTracker"), "pt36" }, - { MOD_TYPE_PTM, UL_("PolyTracker"), "ptm" }, - { MOD_TYPE_SFX, UL_("SoundFX"), "sfx" }, - { MOD_TYPE_SFX, UL_("SoundFX"), "sfx2" }, - { MOD_TYPE_MOD, UL_("SoundTracker 2.6"), "st26" }, - { MOD_TYPE_MOD, UL_("Soundtracker"), "stk" }, - { MOD_TYPE_STM, UL_("Scream Tracker 2"), "stm" }, - { MOD_TYPE_STM, UL_("Scream Tracker Music Interface Kit"), "stx" }, - { MOD_TYPE_STP, UL_("Soundtracker Pro II"), "stp" }, - { MOD_TYPE_MPT, UL_("Symphonie"), "symmod"}, - { MOD_TYPE_ULT, UL_("UltraTracker"), "ult" }, - { MOD_TYPE_MOD, UL_("Mod's Grave"), "wow" }, + { UL_("Galaxy Sound System"), "j2b" }, + { UL_("Soundtracker"), "m15" }, + { UL_("Digitrakker"), "mdl" }, + { UL_("OctaMED"), "med" }, + { UL_("MultiMedia Sound"), "mms" }, + { UL_("MadTracker 2"), "mt2" }, + { UL_("MultiTracker"), "mtm" }, + { UL_("Karl Morton Music Format"), "mus" }, + { UL_("NoiseTracker"), "nst" }, + { UL_("Oktalyzer"), "okt" }, + { UL_("Disorder Tracker 2"), "plm" }, + { UL_("Epic Megagames MASI"), "psm" }, + { UL_("ProTracker"), "pt36" }, + { UL_("PolyTracker"), "ptm" }, + { UL_("SoundFX"), "sfx" }, + { UL_("SoundFX"), "sfx2" }, + { UL_("SoundTracker 2.6"), "st26" }, + { UL_("Soundtracker"), "stk" }, + { UL_("Scream Tracker 2"), "stm" }, + { UL_("Scream Tracker Music Interface Kit"), "stx" }, + { UL_("Soundtracker Pro II"), "stp" }, + { UL_("Symphonie"), "symmod"}, + { UL_("Graoumf Tracker"), "gtk"}, + { UL_("Graoumf Tracker 1 / 2"), "gt2"}, + { UL_("UltraTracker"), "ult" }, + { UL_("Mod's Grave"), "wow" }, + { UL_("Imperium Galactica"), "xmf" }, // converted formats (no MODTYPE) - { MOD_TYPE_NONE, UL_("General Digital Music"), "gdm" }, - { MOD_TYPE_NONE, UL_("Un4seen MO3"), "mo3" }, - { MOD_TYPE_NONE, UL_("OggMod FastTracker 2"), "oxm" }, + { UL_("General Digital Music"), "gdm" }, + { UL_("Un4seen MO3"), "mo3" }, + { UL_("OggMod FastTracker 2"), "oxm" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules - { MOD_TYPE_MOD, UL_("Compressed ProTracker"), "mdz" }, - { MOD_TYPE_MOD, UL_("Compressed Module"), "mdr" }, - { MOD_TYPE_S3M, UL_("Compressed Scream Tracker 3"), "s3z" }, - { MOD_TYPE_XM, UL_("Compressed FastTracker 2"), "xmz" }, - { MOD_TYPE_IT, UL_("Compressed Impulse Tracker"), "itz" }, - { MOD_TYPE_MPT, UL_("Compressed OpenMPT"), "mptmz" }, + { UL_("Compressed ProTracker"), "mdz" }, + { UL_("Compressed Module"), "mdr" }, + { UL_("Compressed Scream Tracker 3"), "s3z" }, + { UL_("Compressed FastTracker 2"), "xmz" }, + { UL_("Compressed Impulse Tracker"), "itz" }, + { UL_("Compressed OpenMPT"), "mptmz" }, #endif }; struct ModContainerInfo { - MODCONTAINERTYPE format; // MOD_CONTAINERTYPE_XXXX + ModContainerType format; // ModContainerType::XXX const mpt::uchar *name; // "Unreal Music" const char *extension; // "umx" }; @@ -125,13 +130,14 @@ struct ModContainerInfo static constexpr ModContainerInfo modContainerInfo[] = { // Container formats - { MOD_CONTAINERTYPE_UMX, UL_("Unreal Music"), "umx" }, - { MOD_CONTAINERTYPE_XPK, UL_("XPK packed"), "xpk" }, - { MOD_CONTAINERTYPE_PP20, UL_("PowerPack PP20"), "ppm" }, - { MOD_CONTAINERTYPE_MMCMP, UL_("Music Module Compressor"), "mmcmp" }, + { ModContainerType::UMX, UL_("Unreal Music"), "umx" }, + { ModContainerType::XPK, UL_("XPK packed"), "xpk" }, + { ModContainerType::PP20, UL_("PowerPack PP20"), "ppm" }, + { ModContainerType::MMCMP, UL_("Music Module Compressor"), "mmcmp" }, #ifdef MODPLUG_TRACKER - { MOD_CONTAINERTYPE_WAV, UL_("Wave"), "wav" }, - { MOD_CONTAINERTYPE_UAX, UL_("Unreal Sounds"), "uax" }, + { ModContainerType::WAV, UL_("Wave"), "wav" }, + { ModContainerType::UAX, UL_("Unreal Sounds"), "uax" }, + { ModContainerType::Generic, UL_("Generic Archive"), "" }, #endif }; @@ -139,9 +145,9 @@ static constexpr ModContainerInfo modContainerInfo[] = #ifdef MODPLUG_TRACKER static constexpr ModFormatInfo otherFormatInfo[] = { - { MOD_TYPE_MID, UL_("MIDI"), "mid" }, - { MOD_TYPE_MID, UL_("MIDI"), "rmi" }, - { MOD_TYPE_MID, UL_("MIDI"), "smf" } + { UL_("MIDI"), "mid" }, + { UL_("MIDI"), "rmi" }, + { UL_("MIDI"), "smf" } }; #endif @@ -152,18 +158,20 @@ std::vector CSoundFile::GetSupportedExtensions(bool otherFormats) for(const auto &formatInfo : modFormatInfo) { // Avoid dupes in list - if(exts.empty() || strcmp(formatInfo.extension, exts.back())) - { + const std::string_view ext = formatInfo.extension; + if(ext.empty()) + continue; + if(exts.empty() || ext != exts.back()) exts.push_back(formatInfo.extension); - } } for(const auto &containerInfo : modContainerInfo) { // Avoid dupes in list - if(exts.empty() || strcmp(containerInfo.extension, exts.back())) - { - exts.push_back(containerInfo.extension); - } + const std::string_view ext = containerInfo.extension; + if(ext.empty()) + continue; + if(exts.empty() || ext != exts.back()) + exts.push_back(ext.data()); } #ifdef MODPLUG_TRACKER if(otherFormats) @@ -214,7 +222,7 @@ bool CSoundFile::IsExtensionSupported(std::string_view ext) } -mpt::ustring CSoundFile::ModContainerTypeToString(MODCONTAINERTYPE containertype) +mpt::ustring CSoundFile::ModContainerTypeToString(ModContainerType containertype) { for(const auto &containerInfo : modContainerInfo) { @@ -227,7 +235,7 @@ mpt::ustring CSoundFile::ModContainerTypeToString(MODCONTAINERTYPE containertype } -mpt::ustring CSoundFile::ModContainerTypeToTracker(MODCONTAINERTYPE containertype) +mpt::ustring CSoundFile::ModContainerTypeToTracker(ModContainerType containertype) { std::set retvals; mpt::ustring retval; @@ -781,7 +789,7 @@ void CResampler::InitializeTablesFromScratch(bool force) getsinc(gKaiserSinc, 9.6377, 0.97); getsinc(gDownsample13x, 8.5, 0.5); - getsinc(gDownsample2x, 2.7625, 0.425); + getsinc(gDownsample2x, 7.0, 0.425); #ifdef MODPLUG_TRACKER StaticTablesInitialized = true; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.cpp index 1fb7b13a9..0db6ddf4a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.cpp @@ -15,12 +15,6 @@ OPENMPT_NAMESPACE_BEGIN -void FileTags::SetEncoder() -{ - encoder = Version::Current().GetOpenMPTVersionString(); -} - - mpt::ustring GetSampleNameFromTags(const FileTags &tags) { mpt::ustring result; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.h b/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.h index 272262a9e..81cb4f0f3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/Tagging.h @@ -35,8 +35,6 @@ struct FileTags mpt::ustring genre; - void SetEncoder(); - }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/UMXTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/UMXTools.cpp index 383663184..1f57de88e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/UMXTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/UMXTools.cpp @@ -35,7 +35,7 @@ bool FileHeader::IsValid() const uint32 FileHeader::GetMinimumAdditionalFileSize() const { - return std::max({nameOffset + nameCount * 5u, exportOffset + exportCount * 8u, importOffset + importCount * 4u}) - sizeof(FileHeader); + return std::max({nameOffset + nameCount * 5u, exportOffset + exportCount * 8u, importOffset + importCount * 4u}) - static_cast(sizeof(FileHeader)); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp index c17efe2cc..526396803 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/UpgradeModule.cpp @@ -258,9 +258,11 @@ void CSoundFile::UpgradeModule() if(m_dwLastSavedWithVersion < MPT_V("1.20.00.00")) { - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { ModInstrument *ins = Instruments[i]; + if(!ins) + continue; // Previously, volume swing values ranged from 0 to 64. They should reach from 0 to 100 instead. ins->nVolSwing = static_cast(std::min(static_cast(ins->nVolSwing * 100 / 64), uint32(100))); @@ -268,7 +270,7 @@ void CSoundFile::UpgradeModule() { // Previously, Pitch/Pan Separation was only half depth (plot twist: it was actually only quarter depth). // This was corrected in compatible mode in OpenMPT 1.18, and in OpenMPT 1.20 it is corrected in normal mode as well. - ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2; + ins->nPPS = static_cast((ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2); } if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.17.03.02")) @@ -405,26 +407,28 @@ void CSoundFile::UpgradeModule() if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00")) { - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { ModInstrument *ins = Instruments[i]; + if(!ins) + continue; // Even after fixing it in OpenMPT 1.18, instrument PPS was only half the depth. - ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2; + ins->nPPS = static_cast((ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2); // OpenMPT 1.18 fixed the depth of random pan in compatible mode. // OpenMPT 1.26 fixes it in normal mode too. if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.18.00.00")) { - ins->nPanSwing = (ins->nPanSwing + 3) / 4u; + ins->nPanSwing = static_cast((ins->nPanSwing + 3) / 4u); } } } if(m_dwLastSavedWithVersion < MPT_V("1.28.00.12")) { - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { - if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET) + if(Instruments[i] != nullptr && Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET) { m_playBehaviour.set(kLegacyReleaseNode); break; @@ -434,9 +438,9 @@ void CSoundFile::UpgradeModule() if(m_dwLastSavedWithVersion < MPT_V("1.28.03.04")) { - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if (Instruments[i] != nullptr) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { - if(Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET) + if(Instruments[i] != nullptr && (Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET)) { m_playBehaviour.set(kMIDIVolumeOnNoteOffBug); break; @@ -578,6 +582,7 @@ void CSoundFile::UpgradeModule() { kITDCTBehaviour, MPT_V("1.29.00.57") }, { kITPitchPanSeparation, MPT_V("1.30.00.53") }, { kITResetFilterOnPortaSmpChange, MPT_V("1.30.08.02") }, + { kITInitialNoteMemory, MPT_V("1.31.00.25") }, }; for(const auto &b : behaviours) @@ -624,6 +629,7 @@ void CSoundFile::UpgradeModule() { kST3RetrigAfterNoteCut, MPT_V("1.29.00.00") }, { kFT2ST3OffsetOutOfRange, MPT_V("1.29.00.00") }, { kApplyUpperPeriodLimit, MPT_V("1.30.00.45") }, + { kST3TonePortaWithAdlibNote, MPT_V("1.31.00.13") }, }; for(const auto &b : behaviours) @@ -686,9 +692,10 @@ void CSoundFile::UpgradeModule() && m_dwLastSavedWithVersion >= MPT_V("1.23.01.02") && m_dwLastSavedWithVersion < MPT_V("1.28.00.43")) { // Bug that effectively clamped the release node to the sustain end - for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr) + for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) { - if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET + if(Instruments[i] != nullptr + && Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && Instruments[i]->VolEnv.dwFlags[ENV_SUSTAIN] && Instruments[i]->VolEnv.nReleaseNode > Instruments[i]->VolEnv.nSustainEnd) { @@ -729,6 +736,19 @@ void CSoundFile::UpgradeModule() } } + if(m_dwLastSavedWithVersion < MPT_V("1.31.00.09") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM))) + { + // Old-style plugin tone portamento + for(auto &plugin : m_MixPlugins) + { + if(plugin.IsValidPlugin()) + { + m_playBehaviour.set(kPluginIgnoreTonePortamento); + break; + } + } + } + if(m_dwLastSavedWithVersion >= MPT_V("1.27") && m_dwLastSavedWithVersion < MPT_V("1.30.06.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM))) { // Fix off-by-one delay length in older Echo DMO emulation diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.cpp index eebe2c98f..2147820c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.cpp @@ -342,7 +342,7 @@ WAVWriter::WAVWriter(mpt::IO::OFileBase &stream) : s(stream) { // Skip file header for now - Seek(sizeof(RIFFHeader)); + mpt::IO::SeekRelative(s, sizeof(RIFFHeader)); } @@ -353,18 +353,21 @@ WAVWriter::~WAVWriter() // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file. -std::size_t WAVWriter::Finalize() +mpt::IO::Offset WAVWriter::Finalize() { FinalizeChunk(); + mpt::IO::Offset totalSize = mpt::IO::TellWrite(s); + RIFFHeader fileHeader; Clear(fileHeader); fileHeader.magic = RIFFHeader::idRIFF; - fileHeader.length = static_cast(totalSize - 8); + fileHeader.length = mpt::saturate_cast(totalSize - 8); fileHeader.type = RIFFHeader::idWAVE; - Seek(0); - Write(fileHeader); + mpt::IO::SeekBegin(s); + mpt::IO::Write(s, fileHeader); + mpt::IO::SeekAbsolute(s, totalSize); finalized = true; return totalSize; @@ -376,79 +379,39 @@ void WAVWriter::StartChunk(RIFFChunk::ChunkIdentifiers id) { FinalizeChunk(); - chunkStartPos = position; + chunkHeaderPos = mpt::IO::TellWrite(s); chunkHeader.id = id; - Skip(sizeof(chunkHeader)); + mpt::IO::SeekRelative(s, sizeof(chunkHeader)); } // End current chunk by updating the chunk header and writing a padding byte if necessary. void WAVWriter::FinalizeChunk() { - if(chunkStartPos != 0) + if(chunkHeaderPos != 0) { - const std::size_t chunkSize = position - (chunkStartPos + sizeof(RIFFChunk)); + const mpt::IO::Offset position = mpt::IO::TellWrite(s); + + const mpt::IO::Offset chunkSize = position - (chunkHeaderPos + sizeof(RIFFChunk)); chunkHeader.length = mpt::saturate_cast(chunkSize); - std::size_t curPos = position; - Seek(chunkStartPos); - Write(chunkHeader); + mpt::IO::SeekAbsolute(s, chunkHeaderPos); + mpt::IO::Write(s, chunkHeader); + + mpt::IO::SeekAbsolute(s, position); - Seek(curPos); if((chunkSize % 2u) != 0) { // Write padding uint8 padding = 0; - Write(padding); + mpt::IO::Write(s, padding); } - chunkStartPos = 0; + chunkHeaderPos = 0; } } -// Seek to a position in file. -void WAVWriter::Seek(std::size_t pos) -{ - position = pos; - totalSize = std::max(totalSize, position); - mpt::IO::SeekAbsolute(s, pos); -} - - -// Write some data to the file. -void WAVWriter::Write(mpt::const_byte_span data) -{ - MPT_ASSERT(!finalized); - auto success = mpt::IO::WriteRaw(s, data); - MPT_ASSERT(success); // this assertion is useful to catch mis-calculation of required buffer size for pre-allocate in-memory file buffers (like in View_smp.cpp for clipboard) - if(!success) - { - return; - } - position += data.size(); - totalSize = std::max(totalSize, position); -} - - -void WAVWriter::WriteBeforeDirect() -{ - MPT_ASSERT(!finalized); -} - - -void WAVWriter::WriteAfterDirect(bool success, std::size_t count) -{ - MPT_ASSERT(success); // this assertion is useful to catch mis-calculation of required buffer size for pre-allocate in-memory file buffers (like in View_smp.cpp for clipboard) - if (!success) - { - return; - } - position += count; - totalSize = std::max(totalSize, position); -} - - // Write the WAV format to the file. void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding) { @@ -461,11 +424,11 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne wavFormat.format = static_cast(extensible ? WAVFormatChunk::fmtExtensible : encoding); wavFormat.numChannels = numChannels; wavFormat.sampleRate = sampleRate; - wavFormat.blockAlign = (bitDepth * numChannels + 7) / 8; + wavFormat.blockAlign = static_cast((bitDepth * numChannels + 7u) / 8u); wavFormat.byteRate = wavFormat.sampleRate * wavFormat.blockAlign; wavFormat.bitsPerSample = bitDepth; - Write(wavFormat); + mpt::IO::Write(s, wavFormat); if(extensible) { @@ -492,7 +455,7 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne break; } extFormat.subFormat = mpt::UUID(static_cast(encoding), 0x0000, 0x0010, 0x800000AA00389B71ull); - Write(extFormat); + mpt::IO::Write(s, extFormat); } } @@ -501,14 +464,14 @@ void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChanne void WAVWriter::WriteMetatags(const FileTags &tags) { StartChunk(RIFFChunk::idCSET); - Write(mpt::as_le(uint16(65001))); // code page (UTF-8) - Write(mpt::as_le(uint16(0))); // country code (unset) - Write(mpt::as_le(uint16(0))); // language (unset) - Write(mpt::as_le(uint16(0))); // dialect (unset) + mpt::IO::Write(s, mpt::as_le(uint16(65001))); // code page (UTF-8) + mpt::IO::Write(s, mpt::as_le(uint16(0))); // country code (unset) + mpt::IO::Write(s, mpt::as_le(uint16(0))); // language (unset) + mpt::IO::Write(s, mpt::as_le(uint16(0))); // dialect (unset) StartChunk(RIFFChunk::idLIST); const char info[] = { 'I', 'N', 'F', 'O' }; - Write(info); + mpt::IO::Write(s, info); WriteTag(RIFFChunk::idINAM, tags.title); WriteTag(RIFFChunk::idIART, tags.artist); @@ -536,20 +499,33 @@ void WAVWriter::WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &ute Clear(chunk); chunk.id = static_cast(id); chunk.length = length; - Write(chunk); - Write(mpt::byte_cast(mpt::span(text.c_str(), length))); + mpt::IO::Write(s, chunk); + mpt::IO::Write(s, mpt::byte_cast(mpt::span(text.c_str(), length))); if((length % 2u) != 0) { uint8 padding = 0; - Write(padding); + mpt::IO::Write(s, padding); } } } +WAVSampleWriter::WAVSampleWriter(mpt::IO::OFileBase &stream) + : WAVWriter(stream) +{ + return; +} + + +WAVSampleWriter::~WAVSampleWriter() +{ + return; +} + + // Write a sample loop information chunk to the file. -void WAVWriter::WriteLoopInformation(const ModSample &sample) +void WAVSampleWriter::WriteLoopInformation(const ModSample &sample) { if(!sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP] && !ModCommand::IsNote(sample.rootNote)) { @@ -585,16 +561,16 @@ void WAVWriter::WriteLoopInformation(const ModSample &sample) loops[info.numLoops++].ConvertToWAV(0, 0, false); } - Write(info); + mpt::IO::Write(s, info); for(uint32 i = 0; i < info.numLoops; i++) { - Write(loops[i]); + mpt::IO::Write(s, loops[i]); } } // Write a sample's cue points to the file. -void WAVWriter::WriteCueInformation(const ModSample &sample) +void WAVSampleWriter::WriteCueInformation(const ModSample &sample) { uint32 numMarkers = 0; for(const auto cue : sample.cues) @@ -604,7 +580,7 @@ void WAVWriter::WriteCueInformation(const ModSample &sample) } StartChunk(RIFFChunk::idcue_); - Write(mpt::as_le(numMarkers)); + mpt::IO::Write(s, mpt::as_le(numMarkers)); uint32 i = 0; for(const auto cue : sample.cues) { @@ -612,20 +588,20 @@ void WAVWriter::WriteCueInformation(const ModSample &sample) { WAVCuePoint cuePoint; cuePoint.ConvertToWAV(i++, cue); - Write(cuePoint); + mpt::IO::Write(s, cuePoint); } } } // Write MPT's sample information chunk to the file. -void WAVWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName) +void WAVSampleWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName) { StartChunk(RIFFChunk::idxtra); WAVExtraChunk mptInfo; mptInfo.ConvertToWAV(sample, modType); - Write(mptInfo); + mpt::IO::Write(s, mptInfo); if(sampleName != nullptr) { @@ -637,11 +613,11 @@ void WAVWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, char name[MAX_SAMPLENAME]; mpt::String::WriteBuf(mpt::String::nullTerminated, name) = sampleName; - Write(name); + mpt::IO::Write(s, name); char filename[MAX_SAMPLEFILENAME]; mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = sample.filename; - Write(filename); + mpt::IO::Write(s, filename); } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.h b/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.h index 380eaf806..a0744647e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/WAVTools.h @@ -331,7 +331,6 @@ public: void ApplySampleSettings(ModSample &sample, mpt::Charset sampleCharset, mpt::charbuf &sampleName); }; - #ifndef MODPLUG_NO_FILESAVE class WAVWriter @@ -340,13 +339,8 @@ protected: // Output stream mpt::IO::OFileBase &s; - // Cursor position - std::size_t position = 0; - // Total number of bytes written to file / memory - std::size_t totalSize = 0; - // Currently written chunk - std::size_t chunkStartPos = 0; + mpt::IO::Offset chunkHeaderPos = 0; RIFFChunk chunkHeader; bool finalized = false; @@ -356,44 +350,16 @@ public: ~WAVWriter(); // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file. - std::size_t Finalize(); + mpt::IO::Offset Finalize(); // Begin writing a new chunk to the file. void StartChunk(RIFFChunk::ChunkIdentifiers id); - // Skip some bytes... For example after writing sample data. - void Skip(size_t numBytes) { Seek(position + numBytes); } - // Get position in file (not counting any changes done to the file from outside this class, i.e. through GetFile()) - std::size_t GetPosition() const { return position; } - - // Write some data to the file. - template - void Write(const T &data) - { - Write(mpt::as_raw_memory(data)); - } - - // Write a buffer to the file. - void Write(mpt::const_byte_span data); - - // Use before writing raw data directly to the underlying stream s - void WriteBeforeDirect(); - // Use after writing raw data directly to the underlying stream s - void WriteAfterDirect(bool success, std::size_t count); - // Write the WAV format to the file. void WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding); // Write text tags to the file. void WriteMetatags(const FileTags &tags); - // Write a sample loop information chunk to the file. - void WriteLoopInformation(const ModSample &sample); - // Write a sample's cue points to the file. - void WriteCueInformation(const ModSample &sample); - // Write MPT's sample information chunk to the file. - void WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName = nullptr); protected: - // Seek to a position in file. - void Seek(std::size_t pos); // End current chunk by updating the chunk header and writing a padding byte if necessary. void FinalizeChunk(); @@ -401,6 +367,23 @@ protected: void WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext); }; +class WAVSampleWriter + : public WAVWriter +{ + +public: + WAVSampleWriter(mpt::IO::OFileBase &stream); + ~WAVSampleWriter(); + +public: + // Write a sample loop information chunk to the file. + void WriteLoopInformation(const ModSample &sample); + // Write a sample's cue points to the file. + void WriteCueInformation(const ModSample &sample); + // Write MPT's sample information chunk to the file. + void WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName = nullptr); +}; + #endif // MODPLUG_NO_FILESAVE OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/WindowedFIR.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/WindowedFIR.cpp index 256889ba8..435b56083 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/WindowedFIR.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/WindowedFIR.cpp @@ -16,80 +16,80 @@ OPENMPT_NAMESPACE_BEGIN -double CWindowedFIR::coef( int _PCnr, double _POfs, double _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen ) +double CWindowedFIR::coef(int cnr, double ofs, double cut, int width, int type) { const double epsilon = 1e-8; - const double _LWidthM1 = _PWidth - 1; - const double _LWidthM1Half = 0.5 * _LWidthM1; - const double _LPosU = (_PCnr - _POfs); - const double _LPIdl = (2.0 * mpt::numbers::pi) / _LWidthM1; - double _LPos = _LPosU - _LWidthM1Half; - double _LWc, _LSi; - if(std::abs(_LPos) < epsilon) + const double widthM1 = width - 1; + const double widthM1Half = 0.5 * widthM1; + const double posU = (cnr - ofs); + const double idl = (2.0 * mpt::numbers::pi) / widthM1; + double pos = posU - widthM1Half; + double wc, si; + if(std::abs(pos) < epsilon) { - _LWc = 1.0; - _LSi = _PCut; + wc = 1.0; + si = cut; } else { - switch(_PType) + switch(type) { case WFIR_HANN: - _LWc = 0.50 - 0.50 * std::cos(_LPIdl * _LPosU); + wc = 0.50 - 0.50 * std::cos(idl * posU); break; case WFIR_HAMMING: - _LWc = 0.54 - 0.46 * std::cos(_LPIdl * _LPosU); + wc = 0.54 - 0.46 * std::cos(idl * posU); break; case WFIR_BLACKMANEXACT: - _LWc = 0.42 - 0.50 * std::cos(_LPIdl * _LPosU) + 0.08 * std::cos(2.0 * _LPIdl * _LPosU); + wc = 0.42 - 0.50 * std::cos(idl * posU) + 0.08 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN3T61: - _LWc = 0.44959 - 0.49364 * std::cos(_LPIdl * _LPosU) + 0.05677 * std::cos(2.0 * _LPIdl * _LPosU); + wc = 0.44959 - 0.49364 * std::cos(idl * posU) + 0.05677 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN3T67: - _LWc = 0.42323 - 0.49755 * std::cos(_LPIdl * _LPosU) + 0.07922 * std::cos(2.0 * _LPIdl * _LPosU); + wc = 0.42323 - 0.49755 * std::cos(idl * posU) + 0.07922 * std::cos(2.0 * idl * posU); break; case WFIR_BLACKMAN4T92: // blackman harris - _LWc = 0.35875 - 0.48829 * std::cos(_LPIdl * _LPosU) + 0.14128 * std::cos(2.0 * _LPIdl * _LPosU) - 0.01168 * std::cos(3.0 * _LPIdl * _LPosU); + wc = 0.35875 - 0.48829 * std::cos(idl * posU) + 0.14128 * std::cos(2.0 * idl * posU) - 0.01168 * std::cos(3.0 * idl * posU); break; case WFIR_BLACKMAN4T74: - _LWc = 0.40217 - 0.49703 * std::cos(_LPIdl * _LPosU) + 0.09392 * std::cos(2.0 * _LPIdl * _LPosU) - 0.00183 * std::cos(3.0 * _LPIdl * _LPosU); + wc = 0.40217 - 0.49703 * std::cos(idl * posU) + 0.09392 * std::cos(2.0 * idl * posU) - 0.00183 * std::cos(3.0 * idl * posU); break; case WFIR_KAISER4T: // kaiser-bessel, alpha~7.5 - _LWc = 0.40243 - 0.49804 * std::cos(_LPIdl * _LPosU) + 0.09831 * std::cos(2.0 * _LPIdl * _LPosU) - 0.00122 * std::cos(3.0 * _LPIdl * _LPosU); + wc = 0.40243 - 0.49804 * std::cos(idl * posU) + 0.09831 * std::cos(2.0 * idl * posU) - 0.00122 * std::cos(3.0 * idl * posU); break; default: - _LWc = 1.0; + wc = 1.0; break; } - _LPos *= mpt::numbers::pi; - _LSi = std::sin(_PCut * _LPos) / _LPos; + pos *= mpt::numbers::pi; + si = std::sin(cut * pos) / pos; } - return (_LWc * _LSi); + return (wc * si); } void CWindowedFIR::InitTable(double WFIRCutoff, uint8 WFIRType) { - const double _LPcllen = (double)(1 << WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0) - const double _LNorm = 1.0 / (2.0 * _LPcllen); - const double _LCut = WFIRCutoff; - for(int _LPcl = 0; _LPcl < WFIR_LUTLEN; _LPcl++) + const double pcllen = (double)(1 << WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0) + const double norm = 1.0 / (2.0 * pcllen); + const double cut = WFIRCutoff; + for(int pcl = 0; pcl < WFIR_LUTLEN; pcl++) { - double _LGain = 0.0, _LCoefs[WFIR_WIDTH]; - const double _LOfs = (_LPcl - _LPcllen) * _LNorm; - const int _LIdx = _LPcl << WFIR_LOG2WIDTH; - for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++) + double gain = 0.0, coefs[WFIR_WIDTH]; + const double ofs = (pcl - pcllen) * norm; + const int idx = pcl << WFIR_LOG2WIDTH; + for(int cc = 0; cc < WFIR_WIDTH; cc++) { - _LGain += (_LCoefs[_LCc] = coef(_LCc, _LOfs, _LCut, WFIR_WIDTH, WFIRType)); + gain += (coefs[cc] = coef(cc, ofs, cut, WFIR_WIDTH, WFIRType)); } - _LGain = 1.0 / _LGain; - for(int _LCc = 0; _LCc < WFIR_WIDTH; _LCc++) + gain = 1.0 / gain; + for(int cc = 0; cc < WFIR_WIDTH; cc++) { #ifdef MPT_INTMIXER - double _LCoef = std::floor(0.5 + WFIR_QUANTSCALE * _LCoefs[_LCc] * _LGain); - lut[_LIdx + _LCc] = (signed short)((_LCoef < -WFIR_QUANTSCALE) ? -WFIR_QUANTSCALE : ((_LCoef > WFIR_QUANTSCALE) ? WFIR_QUANTSCALE : _LCoef)); + double coef = std::floor(0.5 + WFIR_QUANTSCALE * coefs[cc] * gain); + lut[idx + cc] = (signed short)((coef < -WFIR_QUANTSCALE) ? -WFIR_QUANTSCALE : ((coef > WFIR_QUANTSCALE) ? WFIR_QUANTSCALE : coef)); #else - double _LCoef = _LCoefs[_LCc] * _LGain; - lut[_LIdx + _LCc] = (float)_LCoef; + double coef = coefs[cc] * gain; + lut[idx + cc] = (float)coef; #endif // MPT_INTMIXER } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp index ddb796536..4f0bdcd3e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/XMTools.cpp @@ -65,6 +65,14 @@ uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibility ConvertEnvelopeToXM(mptIns.VolEnv, volPoints, volFlags, volSustain, volLoopStart, volLoopEnd, EnvTypeVol); ConvertEnvelopeToXM(mptIns.PanEnv, panPoints, panFlags, panSustain, panLoopStart, panLoopEnd, EnvTypePan); + if(mptIns.nMidiChannel != MidiNoChannel) + { + midiEnabled = 1; + midiChannel = (mptIns.nMidiChannel != MidiMappedChannel ? (mptIns.nMidiChannel - MidiFirstChannel) : 0); + } + midiProgram = (mptIns.nMidiProgram != 0 ? mptIns.nMidiProgram - 1 : 0); + pitchWheelRange = std::min(mptIns.midiPWD, int8(36)); + // Create sample assignment table auto sampleList = GetSampleList(mptIns, compatibilityExport); for(std::size_t i = 0; i < std::size(sampleMap); i++) @@ -80,14 +88,6 @@ uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibility } } - if(mptIns.nMidiChannel != MidiNoChannel) - { - midiEnabled = 1; - midiChannel = (mptIns.nMidiChannel != MidiMappedChannel ? (mptIns.nMidiChannel - MidiFirstChannel) : 0); - } - midiProgram = (mptIns.nMidiProgram != 0 ? mptIns.nMidiProgram - 1 : 0); - pitchWheelRange = std::min(mptIns.midiPWD, int8(36)); - return static_cast(sampleList.size()); } @@ -118,6 +118,9 @@ std::vector XMInstrument::GetSampleList(const ModInstrument &mptIns } } } + // FT2 completely ignores MIDI settings (and also the less important stuff) if not at least one (empty) sample is assigned to this instrument! + if(sampleList.empty() && compatibilityExport && midiEnabled) + sampleList.assign(1, 0); return sampleList; } @@ -236,8 +239,8 @@ void XMInstrumentHeader::Finalise() sampleHeaderSize = sizeof(XMSample); } else { - // TODO: FT2 completely ignores MIDI settings (and also the less important stuff) if not at least one (empty) sample is assigned to this instrument! - size -= sizeof(XMInstrument); + if(!instrument.midiEnabled) + size -= sizeof(XMInstrument); sampleHeaderSize = 0; } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/load_j2b.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/load_j2b.cpp index 90ca009e8..7e43e52f1 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/load_j2b.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/load_j2b.cpp @@ -592,6 +592,8 @@ static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSou } m.param = (m.param & 0x0F) | 0xE0; break; + default: + break; } } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp index 60f881feb..e6016da25 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.cpp @@ -67,7 +67,7 @@ constexpr CModSpecifications mptm_ = true, // Has artist name true, // Has default resampling true, // Fixed point tempo - " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\:#+*?????????", // Supported Effects + " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\:#+*??????????", // Supported Effects " vpcdabuh??gfe?o", // Supported Volume Column commands }; @@ -117,7 +117,7 @@ constexpr CModSpecifications mod_ = false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo - " 0123456789ABCD?FF?E??????????????????????????", // Supported Effects + " 0123456789ABCD?FF?E???????????????????????????", // Supported Effects " ???????????????", // Supported Volume Column commands }; @@ -165,7 +165,7 @@ constexpr CModSpecifications xm_ = false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo - " 0123456789ABCDRFFTE???GHK??XPL??????W????????", // Supported Effects + " 0123456789ABCDRFFTE???GHK??XPL??????W?????????", // Supported Effects " vpcdabuhlrg????", // Supported Volume Column commands }; @@ -213,7 +213,7 @@ constexpr CModSpecifications xmEx_ = true, // Has artist name false, // Doesn't have default resampling false, // Integer tempo - " 0123456789ABCDRFFTE???GHK?YXPLZ\\?#??W????????", // Supported Effects + " 0123456789ABCDRFFTE???GHK?YXPLZ\\?#??W?????????", // Supported Effects " vpcdabuhlrg????", // Supported Volume Column commands }; @@ -260,7 +260,7 @@ constexpr CModSpecifications s3m_ = false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo - " JFEGHLKRXODB?CQATI?SMNVW?U?????????? ????????", // Supported Effects + " JFEGHLKRXODB?CQATI?SMNVW?U?????????? ?????????", // Supported Effects " vp?????????????", // Supported Volume Column commands }; @@ -308,7 +308,7 @@ constexpr CModSpecifications s3mEx_ = false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo - " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ????????", // Supported Effects + " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ?????????", // Supported Effects " vp?????????????", // Supported Volume Column commands }; @@ -355,7 +355,7 @@ constexpr CModSpecifications it_ = false, // Doesn't have artist name false, // Doesn't have default resampling false, // Integer tempo - " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ????????", // Supported Effects + " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z????? ?????????", // Supported Effects " vpcdab?h??gfe??", // Supported Volume Column commands }; @@ -402,7 +402,7 @@ constexpr CModSpecifications itEx_ = true, // Has artist name false, // Doesn't have default resampling false, // Integer tempo - " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\?#?? ????????", // Supported Effects + " JFEGHLKRXODB?CQATI?SMNVW?UY?P?Z\\?#?? ?????????", // Supported Effects " vpcdab?h??gfe??", // Supported Volume Column commands }; @@ -441,6 +441,12 @@ MODTYPE CModSpecifications::ExtensionToType(std::string ext) } +MODTYPE CModSpecifications::ExtensionToType(mpt::ustring ext) +{ + return ExtensionToType(mpt::ToCharset(mpt::Charset::ASCII, ext)); +} + + bool CModSpecifications::HasNote(ModCommand::NOTE note) const { if(note >= noteMin && note <= noteMax) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.h b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.h index bbf2a1703..692236047 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/mod_specifications.h @@ -24,7 +24,8 @@ struct CModSpecifications { /// Returns modtype corresponding to given file extension. The extension string /// may begin with or without dot, e.g. both ".it" and "it" will be handled correctly. - static MODTYPE ExtensionToType(std::string ext); // (encoded in UTF8) + static MODTYPE ExtensionToType(std::string ext); // (encoded in ASCII) + static MODTYPE ExtensionToType(mpt::ustring ext); // Return true if format supports given note. bool HasNote(ModCommand::NOTE note) const; @@ -36,7 +37,10 @@ struct CModSpecifications // NOTE: If changing order, update all initializations in .cpp file. MODTYPE internalType; // Internal MODTYPE value - const char *fileExtension; // File extension without dot (encoded in UTF8). + const char *fileExtension; // File extension without dot (encoded in ASCII). + mpt::ustring GetFileExtension() const { return mpt::ToUnicode(mpt::Charset::ASCII, fileExtension); } + mpt::ustring GetFileExtensionLower() const { return mpt::ToUnicode(mpt::Charset::ASCII, mpt::ToLowerCaseAscii(fileExtension)); } + mpt::ustring GetFileExtensionUpper() const { return mpt::ToUnicode(mpt::Charset::ASCII, mpt::ToUpperCaseAscii(fileExtension)); } ModCommand::NOTE noteMin; // Minimum note index (index starts from 1) ModCommand::NOTE noteMax; // Maximum note index (index starts from 1) PATTERNINDEX patternsMax; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.cpp index f0171784f..4ec2ea9e3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.cpp @@ -17,31 +17,31 @@ OPENMPT_NAMESPACE_BEGIN -const EffectType effectTypes[] = +static constexpr EffectType effectTypes[] = { - EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, EFFECT_TYPE_PITCH, EFFECT_TYPE_PITCH, - EFFECT_TYPE_PITCH, EFFECT_TYPE_PITCH, EFFECT_TYPE_VOLUME, EFFECT_TYPE_VOLUME, - EFFECT_TYPE_VOLUME, EFFECT_TYPE_PANNING, EFFECT_TYPE_NORMAL, EFFECT_TYPE_VOLUME, - EFFECT_TYPE_GLOBAL, EFFECT_TYPE_VOLUME, EFFECT_TYPE_GLOBAL, EFFECT_TYPE_NORMAL, - EFFECT_TYPE_GLOBAL, EFFECT_TYPE_GLOBAL, EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, - EFFECT_TYPE_NORMAL, EFFECT_TYPE_VOLUME, EFFECT_TYPE_VOLUME, EFFECT_TYPE_GLOBAL, - EFFECT_TYPE_GLOBAL, EFFECT_TYPE_NORMAL, EFFECT_TYPE_PITCH, EFFECT_TYPE_PANNING, - EFFECT_TYPE_PITCH, EFFECT_TYPE_PANNING, EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, - EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, EFFECT_TYPE_PITCH, - EFFECT_TYPE_PITCH, EFFECT_TYPE_NORMAL, EFFECT_TYPE_PITCH, EFFECT_TYPE_PITCH, - EFFECT_TYPE_PITCH, EFFECT_TYPE_PITCH, EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, - EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, + EffectType::Normal, EffectType::Normal, EffectType::Pitch, EffectType::Pitch, + EffectType::Pitch, EffectType::Pitch, EffectType::Volume, EffectType::Volume, + EffectType::Volume, EffectType::Panning, EffectType::Normal, EffectType::Volume, + EffectType::Global, EffectType::Volume, EffectType::Global, EffectType::Normal, + EffectType::Global, EffectType::Global, EffectType::Normal, EffectType::Normal, + EffectType::Normal, EffectType::Volume, EffectType::Volume, EffectType::Global, + EffectType::Global, EffectType::Normal, EffectType::Pitch, EffectType::Panning, + EffectType::Pitch, EffectType::Panning, EffectType::Normal, EffectType::Normal, + EffectType::Normal, EffectType::Normal, EffectType::Normal, EffectType::Pitch, + EffectType::Pitch, EffectType::Normal, EffectType::Pitch, EffectType::Pitch, + EffectType::Pitch, EffectType::Pitch, EffectType::Normal, EffectType::Normal, + EffectType::Normal, EffectType::Normal, EffectType::Volume }; static_assert(std::size(effectTypes) == MAX_EFFECTS); -const EffectType volumeEffectTypes[] = +static constexpr EffectType volumeEffectTypes[] = { - EFFECT_TYPE_NORMAL, EFFECT_TYPE_VOLUME, EFFECT_TYPE_PANNING, EFFECT_TYPE_VOLUME, - EFFECT_TYPE_VOLUME, EFFECT_TYPE_VOLUME, EFFECT_TYPE_VOLUME, EFFECT_TYPE_PITCH, - EFFECT_TYPE_PITCH, EFFECT_TYPE_PANNING, EFFECT_TYPE_PANNING, EFFECT_TYPE_PITCH, - EFFECT_TYPE_PITCH, EFFECT_TYPE_PITCH, EFFECT_TYPE_NORMAL, EFFECT_TYPE_NORMAL, + EffectType::Normal, EffectType::Volume, EffectType::Panning, EffectType::Volume, + EffectType::Volume, EffectType::Volume, EffectType::Volume, EffectType::Pitch, + EffectType::Pitch, EffectType::Panning, EffectType::Panning, EffectType::Pitch, + EffectType::Pitch, EffectType::Pitch, EffectType::Normal, EffectType::Normal, }; static_assert(std::size(volumeEffectTypes) == MAX_VOLCMDS); @@ -52,7 +52,7 @@ EffectType ModCommand::GetEffectType(COMMAND cmd) if(cmd < std::size(effectTypes)) return effectTypes[cmd]; else - return EFFECT_TYPE_NORMAL; + return EffectType::Normal; } @@ -61,7 +61,7 @@ EffectType ModCommand::GetVolumeEffectType(VOLCMD volcmd) if(volcmd < std::size(volumeEffectTypes)) return volumeEffectTypes[volcmd]; else - return EFFECT_TYPE_NORMAL; + return EffectType::Normal; } @@ -147,6 +147,11 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd command = CMD_S3MCMDEX; param = 0x9F; } + if(command == CMD_VOLUME8) + { + command = CMD_VOLUME; + param = static_cast((param + 3u) / 4u); + } // helper variables const bool oldTypeIsMOD = (fromType == MOD_TYPE_MOD), oldTypeIsXM = (fromType == MOD_TYPE_XM), @@ -169,13 +174,13 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd { if(newTypeIsS3M) { - param = (param + 1) >> 1; + param = static_cast((param + 1u) >> 1); } else if(oldTypeIsS3M) { if(param == 0xA4) { // surround remap - command = static_cast((toType & (MOD_TYPE_IT | MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN); + command = (toType & (MOD_TYPE_IT | MOD_TYPE_MPT)) ? CMD_S3MCMDEX : CMD_XFINEPORTAUPDOWN; param = 0x91; } else { @@ -196,7 +201,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd { if(IsPcNote()) { - COMMAND newCmd = static_cast(note == NOTE_PC ? CMD_MIDI : CMD_SMOOTHMIDI); + COMMAND newCmd = (note == NOTE_PC) ? CMD_MIDI : CMD_SMOOTHMIDI; if(!newSpecs.HasCommand(newCmd)) { newCmd = CMD_MIDI; // assuming that this was CMD_SMOOTHMIDI @@ -234,9 +239,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd param -= 0x80; } if(param <= 30) - param = 0xE0 | ((param + 1u) / 2u); + param = static_cast(0xE0u | ((param + 1u) / 2u)); else - param = 0xF0 | std::min(static_cast((param + 7u) / 8u), PARAM(15)); + param = static_cast(0xF0u | std::min(static_cast((param + 7u) / 8u), PARAM(15))); } } // End if(oldTypeIsMPT) @@ -324,6 +329,12 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd } break; + case CMD_DUMMY: + // Command "W" in XM, equivalent implementation in IT / S3M is command " ". + // Don't convert this command, as it overwrites effect memory in S3M in particular - a feature not supported by all S3M players. + command = CMD_NONE; + break; + default: break; } @@ -398,7 +409,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd } else { command = CMD_MODCMDEX; - param = (((param & 0x0F) + 3) >> 2) | 0x10; + param = static_cast((((param & 0x0Fu) + 3u) >> 2) | 0x10u); } } else { @@ -420,7 +431,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd } else { command = CMD_MODCMDEX; - param = (((param & 0x0F) + 3) >> 2) | 0x20; + param = static_cast((((param & 0x0Fu) + 3u) >> 2) | 0x20u); } } else { @@ -495,7 +506,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd break; case CMD_GLOBALVOLUME: - param = (std::min(PARAM(0x80), param) + 1) / 2u; + param = static_cast((std::min(PARAM(0x80), param) + 1u) / 2u); break; default: @@ -511,10 +522,12 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd { case CMD_VIBRATO: // With linear slides, strength is roughly doubled. - param = (param & 0xF0) | (((param & 0x0F) + 1) / 2u); + param = static_cast((param & 0xF0u) | (((param & 0x0Fu) + 1u) / 2u)); break; case CMD_GLOBALVOLUME: - param = (std::min(PARAM(0x80), param) + 1) / 2u; + param = static_cast((std::min(PARAM(0x80), param) + 1u) / 2u); + break; + default: break; } } // End if(oldTypeIsIT_MPT && newTypeIsXM) @@ -532,6 +545,8 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd case CMD_GLOBALVOLUME: param = std::min(PARAM(0x40), param) * 2u; break; + default: + break; } } // End if(oldTypeIsIT_MPT && newTypeIsXM) @@ -548,6 +563,8 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd case CMD_TEMPO: param = std::max(param, PARAM(0x20)); break; + default: + break; } } @@ -557,7 +574,7 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd { switch(command) { - case CMD_TONEPORTAVOL: // lacks memory -> 500 is the same as 300 + case CMD_TONEPORTAVOL: // lacks memory -> 500 is the same as 300 if(param == 0x00) command = CMD_TONEPORTAMENTO; break; @@ -574,11 +591,21 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd command = CMD_NONE; break; - case CMD_MODCMDEX: // This would turn into "Set Active Macro", so let's better remove it + case CMD_MODCMDEX: + // No effect memory + if(param == 0x10 || param == 0x20 || param == 0xA0 || param == 0xB0) + command = CMD_NONE; + // This would turn into "Set Active Macro", so let's better remove it + if((param & 0xF0) == 0xF0) + command = CMD_NONE; + break; + case CMD_S3MCMDEX: if((param & 0xF0) == 0xF0) command = CMD_NONE; break; + default: + break; } } // End if(oldTypeIsMOD && newTypeIsXM) @@ -612,6 +639,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd case CMD_MODCMDEX: // This would turn into "Invert Loop", so let's better remove it if((param & 0xF0) == 0xF0) command = CMD_NONE; break; + + default: + break; } if(command == CMD_NONE) switch(volcmd) @@ -670,6 +700,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd command = CMD_VIBRATO; param = vol << 4; break; + + default: + break; } volcmd = VOLCMD_NONE; } // End if(newTypeIsMOD) @@ -745,6 +778,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd param = vol; volcmd = VOLCMD_NONE; break; + + default: + break; } } // End if(newTypeIsS3M) @@ -793,6 +829,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd param = ImpulseTrackerPortaVolCmd[vol & 0x0F]; volcmd = VOLCMD_NONE; break; + + default: + break; } } // End if(newTypeIsXM) @@ -826,6 +865,9 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd param = vol << 4; volcmd = VOLCMD_NONE; break; + + default: + break; } switch(volcmd) @@ -842,6 +884,8 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd case VOLCMD_OFFSET: vol = std::min(vol, VOL(9)); break; + default: + break; } } // End if(newTypeIsIT_MPT) @@ -885,6 +929,40 @@ void ModCommand::Convert(MODTYPE fromType, MODTYPE toType, const CSoundFile &snd } +bool ModCommand::IsAnyPitchSlide() const +{ + switch(command) + { + case CMD_PORTAMENTOUP: + case CMD_PORTAMENTODOWN: + case CMD_TONEPORTAMENTO: + case CMD_TONEPORTAVOL: + case CMD_NOTESLIDEUP: + case CMD_NOTESLIDEDOWN: + case CMD_NOTESLIDEUPRETRIG: + case CMD_NOTESLIDEDOWNRETRIG: + return true; + case CMD_MODCMDEX: + case CMD_XFINEPORTAUPDOWN: + if(param >= 0x10 && param <= 0x2F) + return true; + break; + default: + break; + } + switch(volcmd) + { + case VOLCMD_TONEPORTAMENTO: + case VOLCMD_PORTAUP: + case VOLCMD_PORTADOWN: + return true; + default: + break; + } + return false; +} + + bool ModCommand::IsContinousCommand(const CSoundFile &sndFile) const { switch(command) @@ -1016,6 +1094,39 @@ bool ModCommand::IsGlobalCommand(COMMAND command, PARAM param) } } + +bool ModCommand::CommandHasTwoNibbles(COMMAND command) +{ + switch(command) + { + case CMD_ARPEGGIO: + case CMD_VIBRATO: + case CMD_TONEPORTAVOL: + case CMD_VIBRATOVOL: + case CMD_TREMOLO: + case CMD_VOLUMESLIDE: + case CMD_RETRIG: + case CMD_TREMOR: + case CMD_MODCMDEX: + case CMD_S3MCMDEX: + case CMD_CHANNELVOLSLIDE: + case CMD_GLOBALVOLSLIDE: + case CMD_FINEVIBRATO: + case CMD_PANBRELLO: + case CMD_XFINEPORTAUPDOWN: + case CMD_PANNINGSLIDE: + case CMD_DELAYCUT: + case CMD_NOTESLIDEUP: + case CMD_NOTESLIDEDOWN: + case CMD_NOTESLIDEUPRETRIG: + case CMD_NOTESLIDEDOWNRETRIG: + return true; + default: + return false; + } +} + + // "Importance" of every FX command. Table is used for importing from formats with multiple effect colums // and is approximately the same as in SchismTracker. size_t ModCommand::GetEffectWeight(COMMAND cmd) @@ -1051,6 +1162,7 @@ size_t ModCommand::GetEffectWeight(COMMAND cmd) CMD_VOLUMESLIDE, CMD_VIBRATOVOL, CMD_VOLUME, + CMD_VOLUME8, CMD_DIGIREVERSESAMPLE, CMD_REVERSEOFFSET, CMD_OFFSETPERCENTAGE, @@ -1084,43 +1196,38 @@ size_t ModCommand::GetEffectWeight(COMMAND cmd) } -// Try to convert a fx column command (&effect) into a volume column command. -// Returns true if successful. +// Try to convert a fx column command into a volume column command. +// Returns the translated command if successful. // Some commands can only be converted by losing some precision. // If moving the command into the volume column is more important than accuracy, use force = true. // (Code translated from SchismTracker and mainly supposed to be used with loaders ported from this tracker) -bool ModCommand::ConvertVolEffect(uint8 &effect, uint8 ¶m, bool force) +std::pair ModCommand::ConvertToVolCommand(const EffectCommand effect, ModCommand::PARAM param, bool force) { switch(effect) { case CMD_NONE: - effect = VOLCMD_NONE; - return true; - case CMD_VOLUME: - effect = VOLCMD_VOLUME; - param = std::min(param, PARAM(64)); break; + case CMD_VOLUME: + return {VOLCMD_VOLUME, std::min(param, PARAM(64))}; + case CMD_VOLUME8: + if(!force && (param & 3)) + break; + return {VOLCMD_VOLUME, static_cast((param + 3u) / 4u)}; case CMD_PORTAMENTOUP: // if not force, reject when dividing causes loss of data in LSB, or if the final value is too // large to fit. (volume column Ex/Fx are four times stronger than effect column) if(!force && ((param & 3) || param >= 0xE0)) - return false; - param /= 4; - effect = VOLCMD_PORTAUP; - break; + break; + return {VOLCMD_PORTAUP, static_cast(param / 4u)}; case CMD_PORTAMENTODOWN: if(!force && ((param & 3) || param >= 0xE0)) - return false; - param /= 4; - effect = VOLCMD_PORTADOWN; - break; + break; + return {VOLCMD_PORTADOWN, static_cast(param / 4u)}; case CMD_TONEPORTAMENTO: if(param >= 0xF0) { // hack for people who can't type F twice :) - effect = VOLCMD_TONEPORTAMENTO; - param = 9; - return true; + return {VOLCMD_TONEPORTAMENTO, VOL(9)}; } for(uint8 n = 0; n < 10; n++) { @@ -1128,83 +1235,70 @@ bool ModCommand::ConvertVolEffect(uint8 &effect, uint8 ¶m, bool force) ? (param <= ImpulseTrackerPortaVolCmd[n]) : (param == ImpulseTrackerPortaVolCmd[n])) { - effect = VOLCMD_TONEPORTAMENTO; - param = n; - return true; + return {VOLCMD_TONEPORTAMENTO, n}; } } - return false; + break; case CMD_VIBRATO: if(force) param = std::min(static_cast(param & 0x0F), PARAM(9)); else if((param & 0x0F) > 9 || (param & 0xF0) != 0) - return false; - param &= 0x0F; - effect = VOLCMD_VIBRATODEPTH; - break; + break; + return {VOLCMD_VIBRATODEPTH, static_cast(param & 0x0F)}; case CMD_FINEVIBRATO: if(force) param = 0; else if(param) - return false; - effect = VOLCMD_VIBRATODEPTH; - break; + break; + return {VOLCMD_VIBRATODEPTH, param}; case CMD_PANNING8: if(param == 255) param = 64; else param /= 4; - effect = VOLCMD_PANNING; - break; + return {VOLCMD_PANNING, param}; case CMD_VOLUMESLIDE: if(param == 0) - return false; - if((param & 0xF) == 0) // Dx0 / Cx - { - param >>= 4; - effect = VOLCMD_VOLSLIDEUP; - } else if((param & 0xF0) == 0) // D0x / Dx - { - effect = VOLCMD_VOLSLIDEDOWN; - } else if((param & 0xF) == 0xF) // DxF / Ax - { - param >>= 4; - effect = VOLCMD_FINEVOLUP; - } else if((param & 0xF0) == 0xF0) // DFx / Bx - { - param &= 0xF; - effect = VOLCMD_FINEVOLDOWN; - } else // ??? - { - return false; - } + break; + if((param & 0x0F) == 0) // Dx0 / Cx + return {VOLCMD_VOLSLIDEUP, static_cast(param >> 4)}; + else if((param & 0xF0) == 0) // D0x / Dx + return {VOLCMD_VOLSLIDEDOWN, param}; + else if((param & 0x0F) == 0x0F) // DxF / Ax + return {VOLCMD_FINEVOLUP, static_cast(param >> 4)}; + else if((param & 0xF0) == 0xF0) // DFx / Bx + return {VOLCMD_FINEVOLDOWN, static_cast(param & 0x0F)}; break; case CMD_S3MCMDEX: - switch (param >> 4) + switch(param >> 4) { - case 8: - effect = VOLCMD_PANNING; - param = ((param & 0xF) << 2) + 2; - return true; - case 0: case 1: case 2: case 0xF: - if(force) - { - effect = param = 0; - return true; - } - break; + case 0x08: + return {VOLCMD_PANNING, static_cast(((param & 0x0F) << 2) + 2)}; default: break; } - return false; + break; + case CMD_MODCMDEX: + switch(param >> 4) + { + case 0x08: + return {VOLCMD_PANNING, static_cast(((param & 0x0F) << 2) + 2)}; + case 0x0A: + return {VOLCMD_FINEVOLUP, static_cast(param & 0x0F)}; + case 0x0B: + return {VOLCMD_FINEVOLDOWN, static_cast(param & 0x0F)}; + default: + break; + } + break; default: - return false; + break; } - return true; + return {VOLCMD_NONE, VOL(0)}; } // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. -bool ModCommand::CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 ¶m2) +bool ModCommand::CombineEffects(EffectCommand &eff1, uint8 ¶m1, EffectCommand &eff2, uint8 ¶m2) { if(eff1 == CMD_VOLUMESLIDE && (eff2 == CMD_VIBRATO || eff2 == CMD_TONEPORTAVOL) && param2 == 0) { @@ -1251,12 +1345,14 @@ bool ModCommand::CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 & } -std::pair ModCommand::TwoRegularCommandsToMPT(uint8 &effect1, uint8 ¶m1, uint8 &effect2, uint8 ¶m2) +std::pair ModCommand::FillInTwoCommands(EffectCommand effect1, uint8 param1, EffectCommand effect2, uint8 param2) { for(uint8 n = 0; n < 4; n++) { - if(ModCommand::ConvertVolEffect(effect1, param1, (n > 1))) + if(auto volCmd = ModCommand::ConvertToVolCommand(effect1, param1, (n > 1)); effect1 == CMD_NONE || volCmd.first != VOLCMD_NONE) { + SetVolumeCommand(volCmd); + SetEffectCommand(effect2, param2); return {CMD_NONE, ModCommand::PARAM(0)}; } std::swap(effect1, effect2); @@ -1264,15 +1360,14 @@ std::pair ModCommand::TwoRegularCommandsToMPT( } // Can only keep one command :( - if(GetEffectWeight(static_cast(effect1)) > GetEffectWeight(static_cast(effect2))) + if(GetEffectWeight(effect1) > GetEffectWeight(effect2)) { std::swap(effect1, effect2); std::swap(param1, param2); } - std::pair lostCommand = {static_cast(effect1), param1}; - effect1 = VOLCMD_NONE; - param1 = 0; - return lostCommand; + SetVolumeCommand(VOLCMD_NONE, 0); + SetEffectCommand(effect2, param2); + return {effect1, param1}; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.h b/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.h index bf9049a9b..6b5ce3ea2 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/modcommand.h @@ -108,18 +108,19 @@ enum EffectCommand : uint8 CMD_DBMECHO = 43, // DBM enable/disable echo CMD_OFFSETPERCENTAGE = 44, // PLM Percentage Offset CMD_DIGIREVERSESAMPLE = 45, // DIGI reverse sample + CMD_VOLUME8 = 46, // 8-bit volume MAX_EFFECTS }; -enum EffectType : uint8 +enum class EffectType : uint8 { - EFFECT_TYPE_NORMAL = 0, - EFFECT_TYPE_GLOBAL = 1, - EFFECT_TYPE_VOLUME = 2, - EFFECT_TYPE_PANNING = 3, - EFFECT_TYPE_PITCH = 4, - MAX_EFFECT_TYPE = 5 + Normal = 0, + Global = 1, + Volume = 2, + Panning = 3, + Pitch = 4, + NumTypes = 5 }; @@ -129,17 +130,14 @@ public: using NOTE = uint8; using INSTR = uint8; using VOL = uint8; - using VOLCMD = uint8; - using COMMAND = uint8; + using VOLCMD = VolumeCommand; + using COMMAND = EffectCommand; using PARAM = uint8; // Defines the maximum value for column data when interpreted as 2-byte value // (for example volcmd and vol). The valid value range is [0, maxColumnValue]. static constexpr int maxColumnValue = 999; - // Returns empty modcommand. - static ModCommand Empty() { return ModCommand(); } - bool operator==(const ModCommand &mc) const { return (note == mc.note) @@ -151,14 +149,21 @@ public: } bool operator!=(const ModCommand& mc) const { return !(*this == mc); } + MPT_FORCEINLINE void SetVolumeCommand(const VolumeCommand c, const VOL v) { volcmd = c; vol = v; } + MPT_FORCEINLINE void SetVolumeCommand(const std::pair cmd) { volcmd = cmd.first; vol = cmd.second; } + MPT_FORCEINLINE void SetVolumeCommand(const ModCommand &other) { volcmd = other.volcmd; vol = other. vol; } + MPT_FORCEINLINE void SetEffectCommand(const EffectCommand c, const PARAM p) { command = c; param = p; } + MPT_FORCEINLINE void SetEffectCommand(const std::pair cmd) { command = cmd.first; param = cmd.second; } + MPT_FORCEINLINE void SetEffectCommand(const ModCommand &other) { command = other.command; param = other.param; } + void Set(NOTE n, INSTR ins, uint16 volcol, uint16 effectcol) { note = n; instr = ins; SetValueVolCol(volcol); SetValueEffectCol(effectcol); } uint16 GetValueVolCol() const { return GetValueVolCol(volcmd, vol); } - static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return (volcmd << 8) + vol; } + static uint16 GetValueVolCol(uint8 volcmd, uint8 vol) { return static_cast(volcmd << 8) + vol; } void SetValueVolCol(const uint16 val) { volcmd = static_cast(val >> 8); vol = static_cast(val & 0xFF); } uint16 GetValueEffectCol() const { return GetValueEffectCol(command, param); } - static uint16 GetValueEffectCol(uint8 command, uint8 param) { return (command << 8) + param; } + static uint16 GetValueEffectCol(uint8 command, uint8 param) { return static_cast(command << 8) + param; } void SetValueEffectCol(const uint16 val) { command = static_cast(val >> 8); param = static_cast(val & 0xFF); } // Clears modcommand. @@ -188,6 +193,8 @@ public: static bool IsNoteOrEmpty(NOTE note) { return note == NOTE_NONE || IsNote(note); } // Returns true if any of the commands in this cell trigger a tone portamento. bool IsPortamento() const { return command == CMD_TONEPORTAMENTO || command == CMD_TONEPORTAVOL || volcmd == VOLCMD_TONEPORTAMENTO; } + // Returns true if any commands in this cell trigger any sort of pitch slide / portamento. + bool IsAnyPitchSlide() const; // Returns true if the cell contains a sliding or otherwise continuous effect command. bool IsContinousCommand(const CSoundFile &sndFile) const; bool IsContinousVolColCommand() const; @@ -196,6 +203,11 @@ public: // Returns true if the cell contains an effect command that may affect the global state of the module. bool IsGlobalCommand() const { return IsGlobalCommand(command, param); } static bool IsGlobalCommand(COMMAND command, PARAM param); + // Returns true if the cell contains an effect command whose parameter is divided into two nibbles + bool CommandHasTwoNibbles() const { return CommandHasTwoNibbles(command); } + static bool CommandHasTwoNibbles(COMMAND command); + // Returns true if the two commands' parameters have the same + bool IsNormalVolumeSlide() const { return command == CMD_VOLUMESLIDE || command == CMD_VIBRATOVOL || command == CMD_TONEPORTAVOL; } // Returns true if the note is inside the Amiga frequency range bool IsAmigaNote() const { return IsAmigaNote(note); } @@ -216,18 +228,18 @@ public: // "Importance" of every FX command. Table is used for importing from formats with multiple effect columns // and is approximately the same as in SchismTracker. static size_t GetEffectWeight(COMMAND cmd); - // Try to convert a an effect into a volume column effect. Returns true on success. - static bool ConvertVolEffect(uint8 &effect, uint8 ¶m, bool force); + // Try to convert a an effect into a volume column effect. Returns converted effect on success. + [[nodiscard]] static std::pair ConvertToVolCommand(const EffectCommand effect, PARAM param, bool force); // Takes two "normal" effect commands and converts them to volume column + effect column commands. Returns the dropped command + param (CMD_NONE if nothing had to be dropped). - static std::pair TwoRegularCommandsToMPT(uint8 &effect1, uint8 ¶m1, uint8 &effect2, uint8 ¶m2); + std::pair FillInTwoCommands(EffectCommand effect1, uint8 param1, EffectCommand effect2, uint8 param2); // Try to combine two commands into one. Returns true on success and the combined command is placed in eff1 / param1. - static bool CombineEffects(uint8 &eff1, uint8 ¶m1, uint8 &eff2, uint8 ¶m2); + static bool CombineEffects(EffectCommand &eff1, uint8 ¶m1, EffectCommand &eff2, uint8 ¶m2); public: uint8 note = NOTE_NONE; uint8 instr = 0; - uint8 volcmd = VOLCMD_NONE; - uint8 command = CMD_NONE; + VolumeCommand volcmd = VOLCMD_NONE; + EffectCommand command = CMD_NONE; uint8 vol = 0; uint8 param = 0; }; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp index b94b0ea95..68f155bda 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.cpp @@ -23,28 +23,27 @@ OPENMPT_NAMESPACE_BEGIN -CSoundFile& CPattern::GetSoundFile() { return m_rPatternContainer.GetSoundFile(); } -const CSoundFile& CPattern::GetSoundFile() const { return m_rPatternContainer.GetSoundFile(); } +CSoundFile& CPattern::GetSoundFile() noexcept { return m_rPatternContainer.GetSoundFile(); } +const CSoundFile& CPattern::GetSoundFile() const noexcept { return m_rPatternContainer.GetSoundFile(); } -CHANNELINDEX CPattern::GetNumChannels() const +CHANNELINDEX CPattern::GetNumChannels() const noexcept { return GetSoundFile().GetNumChannels(); } // Check if there is any note data on a given row. -bool CPattern::IsEmptyRow(ROWINDEX row) const +bool CPattern::IsEmptyRow(ROWINDEX row) const noexcept { if(m_ModCommands.empty() || !IsValidRow(row)) { return true; } - PatternRow data = GetRow(row); - for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, data++) + for(const auto &m : GetRow(row)) { - if(!data->IsEmpty()) + if(!m.IsEmpty()) { return false; } @@ -53,7 +52,7 @@ bool CPattern::IsEmptyRow(ROWINDEX row) const } -bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) +bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept { if(rowsPerBeat < 1 || rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax @@ -88,7 +87,7 @@ bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits, bool size_t count = ((newRowCount > m_Rows) ? (newRowCount - m_Rows) : (m_Rows - newRowCount)) * GetNumChannels(); if(newRowCount > m_Rows) - m_ModCommands.insert(resizeAtEnd ? m_ModCommands.end() : m_ModCommands.begin(), count, ModCommand::Empty()); + m_ModCommands.insert(resizeAtEnd ? m_ModCommands.end() : m_ModCommands.begin(), count, ModCommand{}); else if(resizeAtEnd) m_ModCommands.erase(m_ModCommands.end() - count, m_ModCommands.end()); else @@ -104,9 +103,9 @@ bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits, bool } -void CPattern::ClearCommands() +void CPattern::ClearCommands() noexcept { - std::fill(m_ModCommands.begin(), m_ModCommands.end(), ModCommand::Empty()); + std::fill(m_ModCommands.begin(), m_ModCommands.end(), ModCommand{}); } @@ -124,7 +123,7 @@ bool CPattern::AllocatePattern(ROWINDEX rows) } else { // Do this in two steps in order to keep the old pattern data in case of OOM - decltype(m_ModCommands) newPattern(newSize, ModCommand::Empty()); + decltype(m_ModCommands) newPattern(newSize, ModCommand{}); m_ModCommands = std::move(newPattern); } m_Rows = rows; @@ -142,18 +141,29 @@ void CPattern::Deallocate() CPattern& CPattern::operator= (const CPattern &pat) { + if(GetNumChannels() != pat.GetNumChannels()) + return *this; + m_ModCommands = pat.m_ModCommands; m_Rows = pat.m_Rows; m_RowsPerBeat = pat.m_RowsPerBeat; m_RowsPerMeasure = pat.m_RowsPerMeasure; m_tempoSwing = pat.m_tempoSwing; m_PatternName = pat.m_PatternName; + + if(GetSoundFile().GetType() != pat.GetSoundFile().GetType()) + { + for(ModCommand &m : m_ModCommands) + { + m.Convert(GetSoundFile().GetType(), pat.GetSoundFile().GetType(), GetSoundFile()); + } + } return *this; } -bool CPattern::operator== (const CPattern &other) const +bool CPattern::operator== (const CPattern &other) const noexcept { return GetNumRows() == other.GetNumRows() && GetNumChannels() == other.GetNumChannels() @@ -181,7 +191,7 @@ bool CPattern::Expand() decltype(m_ModCommands) newPattern; try { - newPattern.assign(m_ModCommands.size() * 2, ModCommand::Empty()); + newPattern.assign(m_ModCommands.size() * 2, ModCommand{}); } catch(mpt::out_of_memory e) { mpt::delete_out_of_memory(e); @@ -213,9 +223,9 @@ bool CPattern::Shrink() for(ROWINDEX y = 0; y < m_Rows; y++) { - const PatternRow srcRow = GetRow(y * 2); - const PatternRow nextSrcRow = GetRow(y * 2 + 1); - PatternRow destRow = GetRow(y); + const auto srcRow = GetRow(y * 2); + const auto nextSrcRow = GetRow(y * 2 + 1); + auto destRow = GetRow(y); for(CHANNELINDEX x = 0; x < nChns; x++) { @@ -358,9 +368,9 @@ bool CPattern::WriteEffect(EffectWriter &settings) m->command = settings.m_command; if(isS3M) - m->vol = (m->param + 1u) / 2u; + m->vol = static_cast((m->param + 1u) / 2u); else - m->vol = (m->param + 2u) / 4u; + m->vol = static_cast((m->param + 2u) / 4u); m->param = settings.m_param; return true; @@ -399,8 +409,8 @@ bool CPattern::WriteEffect(EffectWriter &settings) } else { // Convert normal effect to volume effect - ModCommand::VOLCMD newVolCmd = VOLCMD_NONE; - ModCommand::VOL newVol = settings.m_param; + VolumeCommand newVolCmd = VOLCMD_NONE; + ModCommand::VOL newVol = 0; if(settings.m_command == CMD_PANNING8 && isS3M) { // This needs some manual fixing. @@ -408,21 +418,16 @@ bool CPattern::WriteEffect(EffectWriter &settings) { // Can't have surround in volume column, only normal panning newVolCmd = VOLCMD_PANNING; - newVol /= 2u; + newVol = settings.m_param / 2u; } } else { - newVolCmd = settings.m_command; - if(!ModCommand::ConvertVolEffect(newVolCmd, newVol, true)) - { - // No Success :( - newVolCmd = VOLCMD_NONE; - } + std::tie(newVolCmd, newVol) = ModCommand::ConvertToVolCommand(settings.m_command, settings.m_param, true); } - if(newVolCmd != CMD_NONE) + if(newVolCmd != VOLCMD_NONE) { - settings.m_volcmd = static_cast(newVolCmd); + settings.m_volcmd = newVolCmd; settings.m_vol = newVol; settings.m_retry = false; } @@ -499,8 +504,10 @@ void ReadModPattern(std::istream& iStrm, CPattern& pat, const size_t) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdPattern, Version::Current().GetRawVersion()); - if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) + if(ssb.HasFailed()) + { return; + } ssb.ReadItem(pat, "data", &ReadData); // pattern time signature uint32 rpb = 0, rpm = 0; @@ -577,12 +584,12 @@ void WriteData(std::ostream& oStrm, const CPattern& pat) } -#define READITEM(itembit,id) \ +#define READITEM(itembit,id, type) \ if(diffmask & itembit) \ { \ mpt::IO::ReadIntLE(iStrm, temp); \ if(ch < chns) \ - lastChnMC[ch].id = temp; \ + lastChnMC[ch].id = static_cast(temp); \ } \ if(ch < chns) \ m.id = lastChnMC[ch].id; @@ -618,15 +625,15 @@ void ReadData(std::istream& iStrm, CPattern& pat, const size_t) mpt::IO::ReadIntLE(iStrm, diffmask); uint8 temp = 0; - ModCommand dummy = ModCommand::Empty(); - ModCommand& m = (ch < chns) ? *pat.GetpModCommand(row, ch) : dummy; + ModCommand dummy{}; + ModCommand &m = (ch < chns) ? *pat.GetpModCommand(row, ch) : dummy; - READITEM(noteBit, note); - READITEM(instrBit, instr); - READITEM(volcmdBit, volcmd); - READITEM(volBit, vol); - READITEM(commandBit, command); - READITEM(effectParamBit, param); + READITEM(noteBit, note, ModCommand::NOTE); + READITEM(instrBit, instr, ModCommand::INSTR); + READITEM(volcmdBit, volcmd, ModCommand::VOLCMD); + READITEM(volBit, vol, ModCommand::VOL); + READITEM(commandBit, command, ModCommand::COMMAND); + READITEM(effectParamBit, param, ModCommand::PARAM); if(diffmask & extraData) { //Ignore additional data. diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h index c5e98aad1..8e24191ad 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/pattern.h @@ -19,49 +19,47 @@ OPENMPT_NAMESPACE_BEGIN - class CPatternContainer; class CSoundFile; class EffectWriter; -typedef ModCommand* PatternRow; - - class CPattern { friend class CPatternContainer; public: + CPattern(CPatternContainer &patCont) : m_rPatternContainer{patCont} {} + CPattern(const CPattern &) = default; + CPattern(CPattern &&) noexcept = default; + CPattern& operator= (const CPattern &pat); - bool operator== (const CPattern &other) const; - bool operator!= (const CPattern &other) const { return !(*this == other); } + bool operator== (const CPattern &other) const noexcept; + bool operator!= (const CPattern &other) const noexcept { return !(*this == other); } public: ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) { return &m_ModCommands[r * GetNumChannels() + c]; } const ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) const { return &m_ModCommands[r * GetNumChannels() + c]; } - ROWINDEX GetNumRows() const { return m_Rows; } - ROWINDEX GetRowsPerBeat() const { return m_RowsPerBeat; } // pattern-specific rows per beat - ROWINDEX GetRowsPerMeasure() const { return m_RowsPerMeasure; } // pattern-specific rows per measure - bool GetOverrideSignature() const { return (m_RowsPerBeat + m_RowsPerMeasure > 0); } // override song time signature? + ROWINDEX GetNumRows() const noexcept { return m_Rows; } + ROWINDEX GetRowsPerBeat() const noexcept { return m_RowsPerBeat; } // pattern-specific rows per beat + ROWINDEX GetRowsPerMeasure() const noexcept { return m_RowsPerMeasure; } // pattern-specific rows per measure + bool GetOverrideSignature() const noexcept { return (m_RowsPerBeat + m_RowsPerMeasure > 0); } // override song time signature? // Returns true if pattern data can be accessed at given row, false otherwise. - bool IsValidRow(const ROWINDEX row) const { return (row < GetNumRows()); } + bool IsValidRow(const ROWINDEX row) const noexcept { return (row < GetNumRows()); } // Returns true if any pattern data is present. - bool IsValid() const { return !m_ModCommands.empty(); } + bool IsValid() const noexcept { return !m_ModCommands.empty(); } - // Return PatternRow object which has operator[] defined so that ModCommand - // at (iRow, iChn) can be accessed with GetRow(iRow)[iChn]. - PatternRow GetRow(const ROWINDEX row) { return GetpModCommand(row, 0); } - PatternRow GetRow(const ROWINDEX row) const { return const_cast(GetpModCommand(row, 0)); } + mpt::span GetRow(const ROWINDEX row) { return mpt::as_span(GetpModCommand(row, 0), GetNumChannels()); } + mpt::span GetRow(const ROWINDEX row) const { return mpt::as_span(GetpModCommand(row, 0), GetNumChannels()); } - CHANNELINDEX GetNumChannels() const; + CHANNELINDEX GetNumChannels() const noexcept; // Add or remove rows from the pattern. bool Resize(const ROWINDEX newRowCount, bool enforceFormatLimits = true, bool resizeAtEnd = true); // Check if there is any note data on a given row. - bool IsEmptyRow(ROWINDEX row) const; + bool IsEmptyRow(ROWINDEX row) const noexcept; // Allocate new pattern memory and replace old pattern data. bool AllocatePattern(ROWINDEX rows); @@ -69,23 +67,23 @@ public: void Deallocate(); // Removes all modcommands from the pattern. - void ClearCommands(); + void ClearCommands() noexcept; // Returns associated soundfile. - CSoundFile& GetSoundFile(); - const CSoundFile& GetSoundFile() const; + CSoundFile& GetSoundFile() noexcept; + const CSoundFile& GetSoundFile() const noexcept; const std::vector &GetData() const { return m_ModCommands; } void SetData(std::vector &&data) { MPT_ASSERT(data.size() == GetNumRows() * GetNumChannels()); m_ModCommands = std::move(data); } // Set pattern signature (rows per beat, rows per measure). Returns true on success. - bool SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure); - void RemoveSignature() { m_RowsPerBeat = m_RowsPerMeasure = 0; } + bool SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure) noexcept; + void RemoveSignature() noexcept { m_RowsPerBeat = m_RowsPerMeasure = 0; } - bool HasTempoSwing() const { return !m_tempoSwing.empty(); } - const TempoSwing& GetTempoSwing() const { return m_tempoSwing; } + bool HasTempoSwing() const noexcept { return !m_tempoSwing.empty(); } + const TempoSwing& GetTempoSwing() const noexcept { return m_tempoSwing; } void SetTempoSwing(const TempoSwing &swing) { m_tempoSwing = swing; m_tempoSwing.Normalize(); } - void RemoveTempoSwing() { m_tempoSwing.clear(); } + void RemoveTempoSwing() noexcept { m_tempoSwing.clear(); } // Pattern name functions - bool functions return true on success. bool SetName(const std::string &newName); @@ -109,20 +107,16 @@ public: // Write some kind of effect data to the pattern bool WriteEffect(EffectWriter &settings); - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; - iterator begin() { return m_ModCommands.begin(); } - const_iterator begin() const { return m_ModCommands.begin(); } - const_iterator cbegin() const { return m_ModCommands.cbegin(); } + iterator begin() noexcept { return m_ModCommands.begin(); } + const_iterator begin() const noexcept { return m_ModCommands.begin(); } + const_iterator cbegin() const noexcept { return m_ModCommands.cbegin(); } - iterator end() { return m_ModCommands.end(); } - const_iterator end() const { return m_ModCommands.end(); } - const_iterator cend() const { return m_ModCommands.cend(); } - - CPattern(CPatternContainer& patCont) : m_rPatternContainer(patCont) {} - CPattern(const CPattern &) = default; - CPattern(CPattern &&) noexcept = default; + iterator end() noexcept { return m_ModCommands.end(); } + const_iterator end() const noexcept { return m_ModCommands.end(); } + const_iterator cend() const noexcept { return m_ModCommands.cend(); } protected: ModCommand& GetModCommand(size_t i) { return m_ModCommands[i]; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.cpp index ace4406d7..3a30af78c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.cpp @@ -19,6 +19,24 @@ OPENMPT_NAMESPACE_BEGIN +CPatternContainer &CPatternContainer::operator=(const CPatternContainer &other) +{ + if(this == &other || m_rSndFile.GetNumChannels() != other.m_rSndFile.GetNumChannels()) + return *this; + m_Patterns = other.m_Patterns; + return *this; +} + + +CPatternContainer &CPatternContainer::operator=(CPatternContainer &&other) noexcept +{ + if(this == &other || m_rSndFile.GetNumChannels() != other.m_rSndFile.GetNumChannels()) + return *this; + m_Patterns = std::move(other.m_Patterns); + return *this; +} + + void CPatternContainer::ClearPatterns() { DestroyPatterns(); @@ -93,7 +111,7 @@ void CPatternContainer::Remove(const PATTERNINDEX ipat) } -bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const +bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const noexcept { if(!IsValidPat(nPat)) return false; @@ -131,7 +149,7 @@ void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/) } -PATTERNINDEX CPatternContainer::GetNumPatterns() const +PATTERNINDEX CPatternContainer::GetNumPatterns() const noexcept { for(PATTERNINDEX pat = Size(); pat > 0; pat--) { @@ -144,7 +162,7 @@ PATTERNINDEX CPatternContainer::GetNumPatterns() const } -PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const +PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const noexcept { if(Size() == 0) { @@ -152,7 +170,7 @@ PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const } for(PATTERNINDEX nPat = Size(); nPat > 0; nPat--) { - if(!m_Patterns[nPat - 1].GetName().empty()) + if(!m_Patterns[nPat - 1].m_PatternName.empty()) { return nPat; } @@ -182,12 +200,16 @@ void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t) { srlztn::SsbRead ssb(iStrm); ssb.BeginRead(FileIdPatterns, Version::Current().GetRawVersion()); - if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) + if(ssb.HasFailed()) + { return; + } PATTERNINDEX nPatterns = patc.Size(); uint16 nCount = uint16_max; - if (ssb.ReadItem(nCount, "num") != srlztn::SsbRead::EntryNotFound) + if(ssb.ReadItem(nCount, "num")) + { nPatterns = nCount; + } LimitMax(nPatterns, ModSpecs::mptm.patternsMax); if (nPatterns > patc.Size()) patc.ResizeArray(nPatterns); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.h b/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.h index c085cedcb..ee6f3860d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/patternContainer.h @@ -27,7 +27,11 @@ public: const CPattern& operator[](const int pat) const { return m_Patterns[pat]; } public: - CPatternContainer(CSoundFile& sndFile) : m_rSndFile(sndFile) { } + CPatternContainer(CSoundFile &sndFile) : m_rSndFile{sndFile} { } + CPatternContainer(const CPatternContainer &) = default; + CPatternContainer(CPatternContainer &&) noexcept = default; + CPatternContainer &operator=(const CPatternContainer &other); + CPatternContainer &operator=(CPatternContainer &&other) noexcept; // Empty and initialize all patterns. void ClearPatterns(); @@ -50,43 +54,42 @@ public: //'invisible' - the pattern data is cleared but the actual pattern object won't get removed. void Remove(const PATTERNINDEX index); - // Applies function object for modcommands in patterns in given range. - // Return: Copy of the function object. + // Applies function object for modcommands in all patterns. template - Func ForEachModCommand(PATTERNINDEX nStartPat, PATTERNINDEX nLastPat, Func func); + void ForEachModCommand(Func func); template - Func ForEachModCommand(Func func) { return ForEachModCommand(0, Size() - 1, func); } + void ForEachModCommand(Func func) const; - std::vector::iterator begin() { return m_Patterns.begin(); } - std::vector::const_iterator begin() const { return m_Patterns.begin(); } - std::vector::const_iterator cbegin() const { return m_Patterns.cbegin(); } - std::vector::iterator end() { return m_Patterns.end(); } - std::vector::const_iterator end() const { return m_Patterns.end(); } - std::vector::const_iterator cend() const { return m_Patterns.cend(); } + std::vector::iterator begin() noexcept { return m_Patterns.begin(); } + std::vector::const_iterator begin() const noexcept { return m_Patterns.begin(); } + std::vector::const_iterator cbegin() const noexcept { return m_Patterns.cbegin(); } + std::vector::iterator end() noexcept { return m_Patterns.end(); } + std::vector::const_iterator end() const noexcept { return m_Patterns.end(); } + std::vector::const_iterator cend() const noexcept { return m_Patterns.cend(); } - PATTERNINDEX Size() const { return static_cast(m_Patterns.size()); } + PATTERNINDEX Size() const noexcept { return static_cast(m_Patterns.size()); } - CSoundFile& GetSoundFile() { return m_rSndFile; } - const CSoundFile& GetSoundFile() const { return m_rSndFile; } + CSoundFile& GetSoundFile() noexcept { return m_rSndFile; } + const CSoundFile& GetSoundFile() const noexcept { return m_rSndFile; } // Return true if pattern can be accessed with operator[](iPat), false otherwise. - bool IsValidIndex(const PATTERNINDEX iPat) const { return (iPat < Size()); } + bool IsValidIndex(const PATTERNINDEX iPat) const noexcept { return (iPat < Size()); } // Return true if IsValidIndex() is true and the corresponding pattern has allocated modcommand array, false otherwise. - bool IsValidPat(const PATTERNINDEX iPat) const { return IsValidIndex(iPat) && m_Patterns[iPat].IsValid(); } + bool IsValidPat(const PATTERNINDEX iPat) const noexcept { return IsValidIndex(iPat) && m_Patterns[iPat].IsValid(); } // Returns true if the pattern is empty, i.e. there are no notes/effects in this pattern - bool IsPatternEmpty(const PATTERNINDEX nPat) const; + bool IsPatternEmpty(const PATTERNINDEX nPat) const noexcept; void ResizeArray(const PATTERNINDEX newSize); void OnModTypeChanged(const MODTYPE oldtype); // Returns index of last valid pattern + 1, zero if no such pattern exists. - PATTERNINDEX GetNumPatterns() const; + PATTERNINDEX GetNumPatterns() const noexcept; // Returns index of highest pattern with pattern named + 1. - PATTERNINDEX GetNumNamedPatterns() const; + PATTERNINDEX GetNumNamedPatterns() const noexcept; private: @@ -96,16 +99,20 @@ private: template -Func CPatternContainer::ForEachModCommand(PATTERNINDEX nStartPat, PATTERNINDEX nLastPat, Func func) +void CPatternContainer::ForEachModCommand(Func func) { - if (nStartPat > nLastPat || nLastPat >= Size()) - return func; - for (PATTERNINDEX nPat = nStartPat; nPat <= nLastPat; nPat++) if (m_Patterns[nPat].IsValid()) - std::for_each(m_Patterns[nPat].begin(), m_Patterns[nPat].end(), func); - return func; + for(auto &pattern : m_Patterns) + std::for_each(pattern.begin(), pattern.end(), func); } +template +void CPatternContainer::ForEachModCommand(Func func) const +{ + for(const auto &pattern : m_Patterns) + std::for_each(pattern.cbegin(), pattern.cend(), func); +} + const char FileIdPatterns[] = "mptPc"; void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t nSize = 0); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.cpp index 2ef25522b..bbc94ced3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.cpp @@ -16,19 +16,18 @@ OPENMPT_NAMESPACE_BEGIN -IMixPlugin* DigiBoosterEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* DigiBoosterEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) DigiBoosterEcho(factory, sndFile, mixStruct); } -DigiBoosterEcho::DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +DigiBoosterEcho::DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_sampleRate(sndFile.GetSampleRate()) , m_chunk(PluginChunk::Default()) { m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -222,12 +221,12 @@ void DigiBoosterEcho::RecalculateEchoParams() // The fallback value when the delay is 0 was determined experimentally from DBPro 2.21 output. // The C implementation of libdigibooster3 has no specific handling of this value and thus produces a delay with maximum length. m_delayTime = ((m_chunk.param[kEchoDelay] ? m_chunk.param[kEchoDelay] : 167u) * m_sampleRate + 250u) / 500u; - m_PMix = (m_chunk.param[kEchoMix]) * (1.0f / 256.0f); - m_NMix = (256 - m_chunk.param[kEchoMix]) * (1.0f / 256.0f); - m_PCrossPBack = (m_chunk.param[kEchoCross] * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); - m_PCrossNBack = (m_chunk.param[kEchoCross] * (256 - m_chunk.param[kEchoFeedback])) * (1.0f / 65536.0f); - m_NCrossPBack = ((m_chunk.param[kEchoCross] - 256) * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); - m_NCrossNBack = ((m_chunk.param[kEchoCross] - 256) * (m_chunk.param[kEchoFeedback] - 256)) * (1.0f / 65536.0f); + m_PMix = static_cast(m_chunk.param[kEchoMix]) * (1.0f / 256.0f); + m_NMix = static_cast(256 - m_chunk.param[kEchoMix]) * (1.0f / 256.0f); + m_PCrossPBack = static_cast(m_chunk.param[kEchoCross] * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); + m_PCrossNBack = static_cast(m_chunk.param[kEchoCross] * (256 - m_chunk.param[kEchoFeedback])) * (1.0f / 65536.0f); + m_NCrossPBack = static_cast((m_chunk.param[kEchoCross] - 256) * m_chunk.param[kEchoFeedback]) * (1.0f / 65536.0f); + m_NCrossNBack = static_cast((m_chunk.param[kEchoCross] - 256) * (m_chunk.param[kEchoFeedback] - 256)) * (1.0f / 65536.0f); } OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.h index 8d0de4d88..199e05882 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/DigiBoosterEcho.h @@ -65,10 +65,9 @@ protected: PluginChunk m_chunk; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + DigiBoosterEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } void SaveAllParameters() override; void RestoreAllParameters(int32 program) override; int32 GetUID() const override { int32le id; memcpy(&id, "Echo", 4); return id; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp index 52ca44841..0e4331bf4 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.cpp @@ -21,13 +21,13 @@ OPENMPT_NAMESPACE_BEGIN -IMixPlugin* LFOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* LFOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) LFOPlugin(factory, sndFile, mixStruct); } -LFOPlugin::LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +LFOPlugin::LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_PRNG(mpt::make_prng(mpt::global_prng())) { @@ -35,7 +35,6 @@ LFOPlugin::LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *m RecalculateIncrement(); m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -97,7 +96,7 @@ void LFOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames) if(m_polarity) value = -value; // Transform value from -1...+1 to 0...1 range and apply offset/amplitude - value = value * m_amplitude + m_offset; + value = value * static_cast(m_amplitude) + static_cast(m_offset); Limit(value, 0.0, 1.0); IMixPlugin *plugin = GetOutputPlugin(); @@ -105,7 +104,7 @@ void LFOPlugin::Process(float *pOutL, float *pOutR, uint32 numFrames) { if(m_outputToCC) { - plugin->MidiSend(MIDIEvents::CC(static_cast(m_outputParam & 0x7F), static_cast((m_outputParam >> 8) & 0x0F), mpt::saturate_round(value * 127.0f))); + plugin->MidiSend(MIDIEvents::CC(static_cast(m_outputParam & 0x7F), static_cast((m_outputParam >> 8) & 0x0F), mpt::saturate_round(value * 127.0))); } else { plugin->SetParameter(m_outputParam, static_cast(value)); @@ -164,7 +163,7 @@ void LFOPlugin::SetParameter(PlugParamIndex index, PlugParamValue value) // Enforce next random value for random LFOs NextRandom(); } - m_phase = value; + m_phase = static_cast(value); return; default: return; @@ -232,6 +231,15 @@ void LFOPlugin::MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackChann } +void LFOPlugin::MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackChannel) +{ + if(IMixPlugin *plugin = GetOutputPlugin()) + { + plugin->MidiTonePortamento(increment, newNote, pwd, trackChannel); + } +} + + void LFOPlugin::MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) { if(IMixPlugin *plugin = GetOutputPlugin()) @@ -458,13 +466,13 @@ CAbstractVstEditor *LFOPlugin::OpenEditor() void LFOPlugin::NextRandom() { m_random = m_nextRandom; - m_nextRandom = mpt::random(m_PRNG) / static_cast(int32_min); + m_nextRandom = mpt::random(m_PRNG) / static_cast(int32_min); } void LFOPlugin::RecalculateFrequency() { - m_computedFrequency = 0.25 * std::pow(2.0, m_frequency * 8.0) - 0.25; + m_computedFrequency = 0.25 * std::pow(2.0, static_cast(m_frequency) * 8.0) - 0.25; if(m_tempoSync) { if(m_computedFrequency > 0.00045) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h index 56b70e9a5..3ade76bda 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/LFOPlugin.h @@ -72,10 +72,9 @@ protected: #endif public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + LFOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { int32 id; memcpy(&id, "LFO ", 4); return id; } int32 GetVersion() const override { return 0; } void Idle() override { } @@ -90,6 +89,7 @@ public: bool MidiSysexSend(mpt::const_byte_span sysex) override; void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override; void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackChannel) override; + void MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackChannel) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackChannel) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; void HardAllNotesOff() override; @@ -148,7 +148,7 @@ protected: public: static LFOWaveform ParamToWaveform(float param) { return static_cast(std::clamp(mpt::saturate_round(param * 32.0f), 0, kNumWaveforms - 1)); } - static float WaveformToParam(LFOWaveform waveform) { return static_cast(waveform) / 32.0f; } + static float WaveformToParam(LFOWaveform waveform) { return static_cast(static_cast(waveform)) / 32.0f; } }; OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp index 7e524c7a3..0aef096c3 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.cpp @@ -22,9 +22,14 @@ // LoadProgram/SaveProgram #include "../../mptrack/FileDialog.h" #include "../../mptrack/VstPresets.h" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" +#include "mpt/io_file/outputfile.hpp" #include "../../common/mptFileIO.h" +#include "mpt/fs/fs.hpp" #include "../mod_specifications.h" #endif // MODPLUG_TRACKER +#include "../../soundlib/AudioCriticalSection.h" #include "mpt/base/aligned_array.hpp" #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" @@ -43,10 +48,10 @@ const CModDoc *IMixPlugin::GetModDoc() const { return m_SndFile.GetpModDoc(); } #endif // MODPLUG_TRACKER -IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin::IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : m_Factory(factory) , m_SndFile(sndFile) - , m_pMixStruct(mixStruct) + , m_pMixStruct(&mixStruct) { m_SndFile.m_loadedPlugins++; m_MixState.pMixBuffer = mpt::align_bytes<8, MIXBUFFERSIZE * 2>(m_MixBuffer); @@ -63,33 +68,9 @@ IMixPlugin::~IMixPlugin() CloseEditor(); CriticalSection cs; #endif // MODPLUG_TRACKER - - // First thing to do, if we don't want to hang in a loop - if (m_Factory.pPluginsList == this) m_Factory.pPluginsList = m_pNext; - if (m_pMixStruct) - { - m_pMixStruct->pMixPlugin = nullptr; - m_pMixStruct = nullptr; - } - - if (m_pNext) m_pNext->m_pPrev = m_pPrev; - if (m_pPrev) m_pPrev->m_pNext = m_pNext; - m_pPrev = nullptr; - m_pNext = nullptr; + m_pMixStruct->pMixPlugin = nullptr; m_SndFile.m_loadedPlugins--; -} - - -void IMixPlugin::InsertIntoFactoryList() -{ - m_pMixStruct->pMixPlugin = this; - - m_pNext = m_Factory.pPluginsList; - if(m_Factory.pPluginsList) - { - m_Factory.pPluginsList->m_pPrev = this; - } - m_Factory.pPluginsList = this; + m_pMixStruct = nullptr; } @@ -135,7 +116,6 @@ CString IMixPlugin::GetFormattedParamName(PlugParamIndex param) // Get a parameter's current value, represented by the plugin. CString IMixPlugin::GetFormattedParamValue(PlugParamIndex param) { - CString paramDisplay = GetParamDisplay(param); CString paramUnits = GetParamLabel(param); paramDisplay.Trim(); @@ -194,7 +174,7 @@ void IMixPlugin::RecalculateGain() if(IsInstrument()) { gain /= m_SndFile.GetPlayConfig().getVSTiAttenuation(); - gain = static_cast(gain * (m_SndFile.m_nVSTiVolume / m_SndFile.GetPlayConfig().getNormalVSTiVol())); + gain = gain * (static_cast(m_SndFile.m_nVSTiVolume) / m_SndFile.GetPlayConfig().getNormalVSTiVol()); } m_fGain = gain; } @@ -215,7 +195,7 @@ void IMixPlugin::Bypass(bool bypass) #ifdef MODPLUG_TRACKER if(m_SndFile.GetpModDoc()) - m_SndFile.GetpModDoc()->UpdateAllViews(nullptr, PluginHint(m_nSlot + 1).Info(), nullptr); + m_SndFile.GetpModDoc()->UpdateAllViews(PluginHint(m_nSlot + 1).Info()); #endif // MODPLUG_TRACKER } @@ -653,13 +633,13 @@ bool IMixPlugin::SaveProgram() { mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir(); const bool useDefaultDir = !defaultDir.empty(); - if(!useDefaultDir && m_Factory.dllPath.IsFile()) + if(!useDefaultDir && mpt::native_fs{}.is_file(m_Factory.dllPath)) { - defaultDir = m_Factory.dllPath.GetPath(); + defaultDir = m_Factory.dllPath.GetDirectoryWithDrive(); } CString progName = m_Factory.libraryName.ToCString() + _T(" - ") + GetCurrentProgramName(); - SanitizeFilename(progName); + progName = SanitizePathComponent(progName); FileDialog dlg = SaveFileDialog() .DefaultExtension("fxb") @@ -678,8 +658,8 @@ bool IMixPlugin::SaveProgram() try { - mpt::SafeOutputFile sf(dlg.GetFirstFile(), std::ios::binary, mpt::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); - mpt::ofstream &f = sf; + mpt::IO::SafeOutputFile sf(dlg.GetFirstFile(), std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); + mpt::IO::ofstream &f = sf; f.exceptions(f.exceptions() | std::ios::badbit | std::ios::failbit); if(f.good() && VSTPresets::SaveFile(f, *this, isBank)) return true; @@ -696,9 +676,9 @@ bool IMixPlugin::LoadProgram(mpt::PathString fileName) { mpt::PathString defaultDir = TrackerSettings::Instance().PathPluginPresets.GetWorkingDir(); bool useDefaultDir = !defaultDir.empty(); - if(!useDefaultDir && m_Factory.dllPath.IsFile()) + if(!useDefaultDir && mpt::native_fs{}.is_file(m_Factory.dllPath)) { - defaultDir = m_Factory.dllPath.GetPath(); + defaultDir = m_Factory.dllPath.GetDirectoryWithDrive(); } if(fileName.empty()) @@ -720,7 +700,7 @@ bool IMixPlugin::LoadProgram(mpt::PathString fileName) } const char *errorStr = nullptr; - InputFile f(fileName, SettingCacheCompleteFileBeforeLoading()); + mpt::IO::InputFile f(fileName, SettingCacheCompleteFileBeforeLoading()); if(f.IsValid()) { FileReader file = GetFileReader(f); @@ -752,7 +732,7 @@ bool IMixPlugin::LoadProgram(mpt::PathString fileName) // IMidiPlugin: Default implementation of plugins with MIDI input // //////////////////////////////////////////////////////////////////// -IMidiPlugin::IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMidiPlugin::IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_MidiCh{{}} { @@ -800,7 +780,7 @@ void IMidiPlugin::MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELIN //Error checking LimitMax(nController, MIDIEvents::MIDICC_end); LimitMax(nParam, uint8(127)); - auto midiCh = GetMidiChannel(trackChannel); + const auto midiCh = GetMidiChannel(trackChannel); if(m_SndFile.m_playBehaviour[kMIDICCBugEmulation]) MidiSend(MIDIEvents::Event(MIDIEvents::evControllerChange, midiCh, nParam, static_cast(nController))); // param and controller are swapped (old broken implementation) @@ -819,7 +799,7 @@ void IMidiPlugin::MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) // Bend MIDI pitch for given MIDI channel using fine tracker param (one unit = 1/64th of a note step) void IMidiPlugin::MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) { - auto midiCh = GetMidiChannel(trackerChn); + const auto midiCh = GetMidiChannel(trackerChn); if(m_SndFile.m_playBehaviour[kOldMIDIPitchBends]) { // OpenMPT Legacy: Old pitch slides never were really accurate, but setting the PWD to 13 in plugins would give the closest results. @@ -838,6 +818,29 @@ void IMidiPlugin::MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerC } +void IMidiPlugin::MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackerChn) +{ + const auto midiCh = GetMidiChannel(trackerChn); + + int32 targetBend = EncodePitchBendParam(64 * (newNote - static_cast(m_MidiCh[midiCh].lastNote))); + ApplyPitchWheelDepth(targetBend, pwd); + targetBend += EncodePitchBendParam(MIDIEvents::pitchBendCentre); + + if(targetBend < m_MidiCh[midiCh].midiPitchBendPos) + increment = -increment; + increment = EncodePitchBendParam(increment); + ApplyPitchWheelDepth(increment, pwd); + + int32 newPitchBendPos = (increment + m_MidiCh[midiCh].midiPitchBendPos) & kPitchBendMask; + if((newPitchBendPos > targetBend && increment > 0) || (newPitchBendPos < targetBend && increment < 0)) + newPitchBendPos = targetBend; + + Limit(newPitchBendPos, EncodePitchBendParam(MIDIEvents::pitchBendMin), EncodePitchBendParam(MIDIEvents::pitchBendMax)); + + SendMidiPitchBend(midiCh, newPitchBendPos); +} + + // Set MIDI pitch for given MIDI channel using fixed point pitch bend value (converted back to 0-16383 MIDI range) void IMidiPlugin::SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos) { @@ -850,7 +853,7 @@ void IMidiPlugin::SendMidiPitchBend(uint8 midiCh, int32 newPitchBendPos) // Apply vibrato effect through pitch wheel commands on a given MIDI channel. void IMidiPlugin::MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) { - auto midiCh = GetMidiChannel(trackerChn); + const auto midiCh = GetMidiChannel(trackerChn); depth = EncodePitchBendParam(depth); if(depth != 0 || (m_MidiCh[midiCh].midiPitchBendPos & kVibratoFlag)) { @@ -876,8 +879,9 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo if(trackChannel >= MAX_CHANNELS) return; - auto midiCh = GetMidiChannel(trackChannel); + const auto midiCh = GetMidiChannel(trackChannel); PlugInstrChannel &channel = m_MidiCh[midiCh]; + uint8 rawNote = static_cast(note & MIDI_NOTE_MASK); uint16 midiBank = instr.wMidiBank - 1; uint8 midiProg = instr.nMidiProgram - 1; @@ -911,10 +915,10 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo // Specific Note Off - if(note > NOTE_MAX_SPECIAL) + if(note & MIDI_NOTE_OFF) { - uint8 i = static_cast(note - NOTE_MAX_SPECIAL - NOTE_MIN); - if(channel.noteOnMap[i][trackChannel]) + uint8 i = rawNote - NOTE_MIN; + if(i < mpt::array_size::size && channel.noteOnMap[i][trackChannel]) { channel.noteOnMap[i][trackChannel]--; MidiSend(MIDIEvents::NoteOff(midiCh, i, 0)); @@ -924,7 +928,7 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo // "Hard core" All Sounds Off on this midi and tracker channel // This one doesn't check the note mask - just one note off per note. // Also less likely to cause a VST event buffer overflow. - else if(note == NOTE_NOTECUT) // ^^ + else if(note == NOTE_NOTECUT) // ^^ { MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_AllNotesOff, midiCh, 0)); MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_AllSoundOff, midiCh, 0)); @@ -940,7 +944,7 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo // All "active" notes off on this midi and tracker channel // using note mask. - else if(note == NOTE_KEYOFF || note == NOTE_FADE) // ==, ~~ + else if(note == NOTE_KEYOFF || note == NOTE_FADE) // ==, ~~ { for(uint8 i = 0; i < std::size(channel.noteOnMap); i++) { @@ -954,16 +958,20 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo } // Note On - else if(note >= NOTE_MIN && note < NOTE_MIN + mpt::array_size::size) + else if(rawNote >= NOTE_MIN && rawNote < NOTE_MIN + mpt::array_size::size) { - note -= NOTE_MIN; - - // Reset pitch bend on each new note, tracker style. - // This is done if the pitch wheel has been moved or there was a vibrato on the previous row (in which case the "vstVibratoFlag" bit of the pitch bend memory is set) - auto newPitchBendPos = EncodePitchBendParam(Clamp(m_SndFile.m_PlayState.Chn[trackChannel].GetMIDIPitchBend(), MIDIEvents::pitchBendMin, MIDIEvents::pitchBendMax)); - if(m_MidiCh[midiCh].midiPitchBendPos != newPitchBendPos) + if(!(note & MIDI_NOTE_ARPEGGIO)) { - SendMidiPitchBend(midiCh, newPitchBendPos); + m_MidiCh[midiCh].lastNote = rawNote; + m_SndFile.m_PlayState.Chn[trackChannel].lastMidiNoteWithoutArp = rawNote; + + // Reset pitch bend on each new note, tracker style. + // This is done if the pitch wheel has been moved or there was a vibrato on the previous row (in which case the "vstVibratoFlag" bit of the pitch bend memory is set) + auto newPitchBendPos = EncodePitchBendParam(Clamp(m_SndFile.m_PlayState.Chn[trackChannel].GetMIDIPitchBend(), MIDIEvents::pitchBendMin, MIDIEvents::pitchBendMax)); + if(m_MidiCh[midiCh].midiPitchBendPos != newPitchBendPos) + { + SendMidiPitchBend(midiCh, newPitchBendPos); + } } // count instances of active notes. @@ -971,12 +979,13 @@ void IMidiPlugin::MidiCommand(const ModInstrument &instr, uint16 note, uint16 vo // Problem: if a note dies out naturally and we never send a note off, this counter // will block at max until note off. Is this a problem? // Safe to assume we won't need more than 255 note offs max on a given note? - if(channel.noteOnMap[note][trackChannel] < uint8_max) + rawNote -= NOTE_MIN; + if(channel.noteOnMap[rawNote][trackChannel] < uint8_max) { - channel.noteOnMap[note][trackChannel]++; + channel.noteOnMap[rawNote][trackChannel]++; } - MidiSend(MIDIEvents::NoteOn(midiCh, static_cast(note), volume)); + MidiSend(MIDIEvents::NoteOn(midiCh, rawNote, volume)); } } @@ -1053,6 +1062,8 @@ void SNDMIXPLUGIN::Destroy() { if(pMixPlugin) { + CriticalSection cs; + pMixPlugin->GetPluginFactory().RemovePluginInstanceFromList(*pMixPlugin); pMixPlugin->Release(); pMixPlugin = nullptr; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h index 34cf31211..f96af635c 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PlugInterface.h @@ -57,6 +57,7 @@ struct SNDMIXPLUGINSTATE class IMixPlugin { friend class CAbstractVstEditor; + friend struct VSTPluginLib; protected: IMixPlugin *m_pNext = nullptr, *m_pPrev = nullptr; @@ -85,15 +86,21 @@ public: bool m_passKeypressesToPlug = false; bool m_recordMIDIOut = false; + // Combine with note value sent to IMixPlugin::MidiCommand + enum MidiNoteFlag : uint16 + { + MIDI_NOTE_MASK = 0x0FF, + MIDI_NOTE_OFF = 0x100, // Send note-off for a specific note + MIDI_NOTE_ARPEGGIO = 0x200, // Note is part of an arpeggio, don't store it as the last triggered note + }; + + protected: virtual ~IMixPlugin(); - // Insert plugin into list of loaded plugins. - void InsertIntoFactoryList(); - public: // Non-virtual part of the interface - IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + IMixPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); inline CSoundFile &GetSoundFile() { return m_SndFile; } inline const CSoundFile &GetSoundFile() const { return m_SndFile; } @@ -116,7 +123,7 @@ public: double GetOutputLatency() const; // Destroy the plugin - virtual void Release() = 0; + virtual void Release() { delete this; } virtual int32 GetUID() const = 0; virtual int32 GetVersion() const = 0; virtual void Idle() = 0; @@ -146,6 +153,7 @@ public: virtual void MidiCC(MIDIEvents::MidiCC /*nController*/, uint8 /*nParam*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiPitchBendRaw(int32 /*pitchbend*/, CHANNELINDEX /*trackChannel*/) {} virtual void MidiPitchBend(int32 /*increment*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { } + virtual void MidiTonePortamento(int32 /*increment*/, uint8 /*newNote*/, int8 /*pwd*/, CHANNELINDEX /*trackChannel*/) { } virtual void MidiVibrato(int32 /*depth*/, int8 /*pwd*/, CHANNELINDEX /*trackerChn*/) { } virtual void MidiCommand(const ModInstrument &/*instr*/, uint16 /*note*/, uint16 /*vol*/, CHANNELINDEX /*trackChannel*/) { } virtual void HardAllNotesOff() { } @@ -258,6 +266,7 @@ protected: int32 midiPitchBendPos = 0; // Current Pitch Wheel position, in 16.11 fixed point format. Lowest bit is used for indicating that vibrato was applied. Vibrato offset itself is not stored in this value. uint16 currentProgram = uint16_max; uint16 currentBank = uint16_max; + uint8 lastNote = 0 /* NOTE_NONE */; uint8 noteOnMap[128][MAX_CHANNELS]; void ResetProgram() { currentProgram = uint16_max; currentBank = uint16_max; } @@ -266,11 +275,12 @@ protected: std::array m_MidiCh; // MIDI channel state public: - IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + IMidiPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); void MidiCC(MIDIEvents::MidiCC nController, uint8 nParam, CHANNELINDEX trackChannel) override; void MidiPitchBendRaw(int32 pitchbend, CHANNELINDEX trackerChn) override; void MidiPitchBend(int32 increment, int8 pwd, CHANNELINDEX trackerChn) override; + void MidiTonePortamento(int32 increment, uint8 newNote, int8 pwd, CHANNELINDEX trackerChn) override; void MidiVibrato(int32 depth, int8 pwd, CHANNELINDEX trackerChn) override; void MidiCommand(const ModInstrument &instr, uint16 note, uint16 vol, CHANNELINDEX trackChannel) override; bool IsNotePlaying(uint8 note, CHANNELINDEX trackerChn) override; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp index ab4e4abe9..30db0e5f8 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.cpp @@ -16,7 +16,9 @@ #include "PluginManager.h" #include "PlugInterface.h" +#if defined(MPT_WITH_DMO) #include "mpt/uuid/guid.hpp" +#endif // MPT_WITH_DMO #include "mpt/uuid/uuid.hpp" // Built-in plugins @@ -44,6 +46,9 @@ #ifdef MPT_WITH_VST #include "../../mptrack/Vstplug.h" #include "../../pluginBridge/BridgeWrapper.h" +#ifdef MODPLUG_TRACKER +#include "mpt/fs/fs.hpp" +#endif // MODPLUG_TRACKER #endif // MPT_WITH_VST #if defined(MPT_WITH_DMO) @@ -248,6 +253,36 @@ void VSTPluginLib::WriteToCache() const #endif // MODPLUG_TRACKER +void VSTPluginLib::InsertPluginInstanceIntoList(IMixPlugin &pluginInstance) +{ + pluginInstance.m_pNext = pPluginsList; + if(pPluginsList) + { + pPluginsList->m_pPrev = &pluginInstance; + } + pPluginsList = &pluginInstance; +} + + +void VSTPluginLib::RemovePluginInstanceFromList(IMixPlugin &pluginInstance) +{ + if(pPluginsList == &pluginInstance) + { + pPluginsList = pluginInstance.m_pNext; + } + if(pluginInstance.m_pNext) + { + pluginInstance.m_pNext->m_pPrev = pluginInstance.m_pPrev; + } + if(pluginInstance.m_pPrev) + { + pluginInstance.m_pPrev->m_pNext = pluginInstance.m_pNext; + } + pluginInstance.m_pPrev = nullptr; + pluginInstance.m_pNext = nullptr; +} + + bool CreateMixPluginProc(SNDMIXPLUGIN &mixPlugin, CSoundFile &sndFile) { #ifdef MODPLUG_TRACKER @@ -341,7 +376,9 @@ CVstPluginManager::~CVstPluginManager() { while(plug->pPluginsList != nullptr) { - plug->pPluginsList->Release(); + IMixPlugin *pluginInstance = plug->pPluginsList; + plug->RemovePluginInstanceFromList(*pluginInstance); + pluginInstance->Release(); } delete plug; } @@ -497,17 +534,17 @@ static bool TryLoadPlugin(bool maskCrashes, VSTPluginLib *plug, HINSTANCE hLib, // Add a plugin to the list of known plugins. VSTPluginLib *CVstPluginManager::AddPlugin(const mpt::PathString &dllPath, bool maskCrashes, const mpt::ustring &tags, bool fromCache, bool *fileFound) { - const mpt::PathString fileName = dllPath.GetFileName(); + const mpt::PathString fileName = dllPath.GetFilenameBase(); // Check if this is already a known plugin. for(const auto &dupePlug : pluginList) { - if(!dllPath.CompareNoCase(dllPath, dupePlug->dllPath)) return dupePlug; + if(!mpt::PathCompareNoCase(dllPath, dupePlug->dllPath)) return dupePlug; } if(fileFound != nullptr) { - *fileFound = dllPath.IsFile(); + *fileFound = mpt::native_fs{}.is_file(dllPath); } // Look if the plugin info is stored in the PluginCache @@ -627,7 +664,9 @@ bool CVstPluginManager::RemovePlugin(VSTPluginLib *pFactory) while(plug->pPluginsList != nullptr) { - plug->pPluginsList->Release(); + IMixPlugin *pluginInstance = plug->pPluginsList; + plug->RemovePluginInstanceFromList(*pluginInstance); + pluginInstance->Release(); } pluginList.erase(p); delete plug; @@ -664,7 +703,7 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd const bool matchID = (plug->pluginId1 == mixPlugin.Info.dwPluginId1) && (plug->pluginId2 == mixPlugin.Info.dwPluginId2); #if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT - const bool matchName = !mpt::PathString::CompareNoCase(plug->libraryName, libraryName); + const bool matchName = !mpt::PathCompareNoCase(plug->libraryName, libraryName); #else const bool matchName = !mpt::CompareNoCaseAscii(plug->libraryName.ToUTF8(), libraryName); #endif @@ -693,7 +732,15 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd if(pFound != nullptr && pFound->Create != nullptr) { - IMixPlugin *plugin = pFound->Create(*pFound, sndFile, &mixPlugin); + IMixPlugin *plugin = pFound->Create(*pFound, sndFile, mixPlugin); + if(plugin) + { + pFound->InsertPluginInstanceIntoList(*plugin); + } +#ifdef MODPLUG_TRACKER + CriticalSection cs; +#endif + mixPlugin.pMixPlugin = plugin; return plugin != nullptr; } @@ -722,7 +769,7 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd if(!fullPath.empty()) { fullPath = theApp.PathInstallRelativeToAbsolute(fullPath); - if(fullPath.IsFile()) + if(mpt::native_fs{}.is_file(fullPath)) { pFound = AddPlugin(fullPath, maskCrashes); } @@ -742,18 +789,19 @@ bool CVstPluginManager::CreateMixPlugin(SNDMIXPLUGIN &mixPlugin, CSoundFile &snd if(pEffect != nullptr && pEffect->dispatcher != nullptr && pEffect->magic == Vst::kEffectMagic) { - validPlugin = true; - GetPluginInformation(maskCrashes, pEffect, *pFound); // Update cached information pFound->WriteToCache(); CVstPlugin *pVstPlug = new (std::nothrow) CVstPlugin(maskCrashes, hLibrary, *pFound, mixPlugin, *pEffect, sndFile); - if(pVstPlug == nullptr) + if(pVstPlug) { - validPlugin = false; + pFound->InsertPluginInstanceIntoList(*pVstPlug); } + validPlugin = (pVstPlug != nullptr); + CriticalSection cs; + mixPlugin.pMixPlugin = pVstPlug; } if(!validPlugin) diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.h index 84575ad64..4714f3c0e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/PluginManager.h @@ -53,9 +53,12 @@ public: }; public: - using CreateProc = IMixPlugin *(*)(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + using CreateProc = IMixPlugin *(*)(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); IMixPlugin *pPluginsList = nullptr; // Pointer to first plugin instance (this instance carries pointers to other instances) + void InsertPluginInstanceIntoList(IMixPlugin &pluginInstance); + void RemovePluginInstanceFromList(IMixPlugin &pluginInstance); + CreateProc Create; // Factory to call for this plugin mpt::PathString libraryName; // Display name mpt::PathString dllPath; // Full path name diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.cpp index 4f94155f4..5c1ff23c7 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.cpp @@ -16,18 +16,17 @@ OPENMPT_NAMESPACE_BEGIN -IMixPlugin *SymMODEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin *SymMODEcho::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) SymMODEcho(factory, sndFile, mixStruct); } -SymMODEcho::SymMODEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +SymMODEcho::SymMODEcho(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_chunk(PluginChunk::Default()) { m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); RecalculateEchoParams(); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.h index 4b54e0c8a..a8d29fa9d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/SymMODEcho.h @@ -65,10 +65,9 @@ public: PluginChunk m_chunk; public: - static IMixPlugin* Create(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN* mixStruct); - SymMODEcho(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN* mixStruct); + static IMixPlugin* Create(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); + SymMODEcho(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } void SaveAllParameters() override; void RestoreAllParameters(int32 program) override; int32 GetUID() const override { int32le id; memcpy(&id, "Echo", 4); return id; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.cpp index ba43b1fbd..5e6957c60 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.cpp @@ -23,13 +23,13 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* Chorus::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Chorus::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Chorus(factory, sndFile, mixStruct); } -Chorus::Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, bool isFlanger) +Chorus::Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, bool isFlanger) : IMixPlugin(factory, sndFile, mixStruct) , m_isFlanger(isFlanger) { @@ -42,7 +42,6 @@ Chorus::Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStru m_param[kChorusDelay] = 0.8f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -113,13 +112,13 @@ void Chorus::Process(float *pOutL, float *pOutR, uint32 numFrames) float left1 = m_bufferL[GetBufferIntOffset(m_bufPos + m_delayL)]; float left2 = m_bufferL[GetBufferIntOffset(m_bufPos + m_delayL + 4096)]; - float fracPos = (m_delayL & 0xFFF) * (1.0f / 4096.0f); + float fracPos = static_cast(m_delayL & 0xFFF) * (1.0f / 4096.0f); float leftOut = (left2 - left1) * fracPos + left1; *(out[0])++ = leftDelayIn + (leftOut - leftDelayIn) * wetDryMix; float right1 = bufferR[GetBufferIntOffset(m_bufPos + m_delayR)]; float right2 = bufferR[GetBufferIntOffset(m_bufPos + m_delayR + 4096)]; - fracPos = (m_delayR & 0xFFF) * (1.0f / 4096.0f); + fracPos = static_cast(m_delayR & 0xFFF) * (1.0f / 4096.0f); float rightOut = (right2 - right1) * fracPos + right1; *(out[1])++ = rightDelayIn + (rightOut - rightDelayIn) * wetDryMix; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.h index 62c1db6de..69476b814 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Chorus.h @@ -54,10 +54,9 @@ protected: int32 m_dryWritePos = 0; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, bool stereoBuffers = false); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + Chorus(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, bool stereoBuffers = false); - void Release() override { delete this; } int32 GetUID() const override { return 0xEFE6629C; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.cpp index 97d5cbcf0..62c961a79 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.cpp @@ -27,13 +27,13 @@ namespace DMO { -IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Compressor(factory, sndFile, mixStruct); } -Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kCompGain] = 0.5f; @@ -44,7 +44,6 @@ Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN m_param[kCompPredelay] = 1.0f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -93,7 +92,7 @@ void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames) readOffset /= 4096; readOffset %= m_bufSize; - float outGain = (compGainPow * (1.0f / 2147483648.0f)) * m_gain; + float outGain = (static_cast(compGainPow) * (1.0f / 2147483648.0f)) * m_gain; *(out[0])++ = m_buffer[readOffset * 2] * outGain; *(out[1])++ = m_buffer[readOffset * 2 + 1] * outGain; @@ -217,7 +216,7 @@ CString Compressor::GetParamDisplay(PlugParamIndex param) void Compressor::RecalculateCompressorParams() { - const float sampleRate = m_SndFile.GetSampleRate() / 1000.0f; + const float sampleRate = static_cast(m_SndFile.GetSampleRate()) / 1000.0f; m_gain = std::pow(10.0f, GainInDecibel() / 20.0f); m_attack = std::pow(10.0f, -1.0f / (AttackTime() * sampleRate)); m_release = std::pow(10.0f, -1.0f / (ReleaseTime() * sampleRate)); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.h index 7fc60f5a2..7c2cee766 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Compressor.h @@ -47,10 +47,9 @@ protected: float m_peak; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0xEF011F79; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.cpp index bb7df1810..4c6e8a7d0 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.cpp @@ -36,7 +36,7 @@ OPENMPT_NAMESPACE_BEGIN #endif -IMixPlugin* DMOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* DMOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { CLSID clsid; if(mpt::VerifyStringToCLSID(factory.dllPath.AsNative(), clsid)) @@ -70,7 +70,7 @@ IMixPlugin* DMOPlugin::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIX } -DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid) +DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid) : IMixPlugin(factory, sndFile, mixStruct) , m_pMediaObject(pMO) , m_pMediaProcess(pMOIP) @@ -85,7 +85,6 @@ DMOPlugin::DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *m m_pMediaParams = nullptr; m_alignedBuffer.f32 = mpt::align_bytes<16, MIXBUFFERSIZE * 2>(m_interleavedBuffer.f32); m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.h index 9dabc8777..6260cd135 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/DMOPlugin.h @@ -44,14 +44,13 @@ protected: bool m_useFloat; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); protected: - DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid); + DMOPlugin(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, IMediaObject *pMO, IMediaObjectInPlace *pMOIP, uint32 uid); ~DMOPlugin(); public: - void Release() override { delete this; } int32 GetUID() const override { return m_uid; } int32 GetVersion() const override { return 2; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.cpp index 26f405026..3e05a0882 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.cpp @@ -26,13 +26,13 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* Distortion::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Distortion::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Distortion(factory, sndFile, mixStruct); } -Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kDistGain] = 0.7f; @@ -42,7 +42,6 @@ Distortion::Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN m_param[kDistPostEQBandwidth] = 0.291f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -180,7 +179,7 @@ CString Distortion::GetParamDisplay(PlugParamIndex param) void Distortion::RecalculateDistortionParams() { // Pre-EQ - m_preEQb1 = std::sqrt((2.0f * std::cos(2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPreLowpassCutoff]) / m_SndFile.GetSampleRate(), 0.5f)) + 3.0f) / 5.0f); + m_preEQb1 = std::sqrt((2.0f * std::cos(2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPreLowpassCutoff]) / static_cast(m_SndFile.GetSampleRate()), 0.5f)) + 3.0f) / 5.0f); m_preEQa0 = std::sqrt(1.0f - m_preEQb1 * m_preEQb1); // Distortion @@ -198,8 +197,8 @@ void Distortion::RecalculateDistortionParams() // Post-EQ const float gain = std::pow(10.0f, GainInDecibel() / 20.0f); - const float postFreq = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQCenterFrequency]) / m_SndFile.GetSampleRate(), 0.5f); - const float postBw = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQBandwidth]) / m_SndFile.GetSampleRate(), 0.5f); + const float postFreq = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQCenterFrequency]) / static_cast(m_SndFile.GetSampleRate()), 0.5f); + const float postBw = 2.0f * mpt::numbers::pi_v * std::min(FreqInHertz(m_param[kDistPostEQBandwidth]) / static_cast(m_SndFile.GetSampleRate()), 0.5f); const float t = std::tan(5.0e-1f * postBw); m_postEQb1 = ((1.0f - t) / (1.0f + t)); m_postEQb0 = -std::cos(postFreq); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.h index 3c88e8e75..9d0d63ce0 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Distortion.h @@ -39,10 +39,9 @@ protected: uint8 m_edge, m_shift; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + Distortion(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0xEF114C90; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.cpp index 98251ccaf..79ac4e23d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.cpp @@ -22,13 +22,13 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* Echo::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Echo::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Echo(factory, sndFile, mixStruct); } -Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_bufferSize(0) , m_writePos(0) @@ -42,7 +42,6 @@ Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) m_param[kEchoPanDelay] = 0.0f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -192,8 +191,8 @@ CString Echo::GetParamDisplay(PlugParamIndex param) void Echo::RecalculateEchoParams() { m_initialFeedback = std::sqrt(1.0f - (m_param[kEchoFeedback] * m_param[kEchoFeedback])); - m_delayTime[0] = static_cast((1.0f + m_param[kEchoLeftDelay] * 1999.0f) / 1000.0f * m_sampleRate); - m_delayTime[1] = static_cast((1.0f + m_param[kEchoRightDelay] * 1999.0f) / 1000.0f * m_sampleRate); + m_delayTime[0] = static_cast((1.0f + m_param[kEchoLeftDelay] * 1999.0f) / 1000.0f * static_cast(m_sampleRate)); + m_delayTime[1] = static_cast((1.0f + m_param[kEchoRightDelay] * 1999.0f) / 1000.0f * static_cast(m_sampleRate)); m_crossEcho = (m_param[kEchoPanDelay]) > 0.5f; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.h index b56d6c95b..cffac15bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.h @@ -42,10 +42,9 @@ protected: bool m_crossEcho; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0xEF3E932C; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.cpp index 2da25110f..8e9eb8168 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.cpp @@ -22,18 +22,18 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* Flanger::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Flanger::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Flanger(factory, sndFile, mixStruct, false); } -IMixPlugin* Flanger::CreateLegacy(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Flanger::CreateLegacy(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new(std::nothrow) Flanger(factory, sndFile, mixStruct, true); } -Flanger::Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, const bool legacy) +Flanger::Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, const bool legacy) : Chorus(factory, sndFile, mixStruct, !legacy) { m_param[kFlangerWetDryMix] = 0.5f; @@ -46,7 +46,6 @@ Flanger::Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixSt // Already done in Chorus constructor //m_mixBuffer.Initialize(2, 2); - //InsertIntoFactoryList(); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.h index 1383028a9..a422e0e40 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Flanger.h @@ -37,11 +37,10 @@ protected: }; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - static IMixPlugin* CreateLegacy(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN* mixStruct); - Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct, const bool legacy); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + static IMixPlugin* CreateLegacy(VSTPluginLib& factory, CSoundFile& sndFile, SNDMIXPLUGIN &mixStruct); + Flanger(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct, const bool legacy); - void Release() override { delete this; } int32 GetUID() const override { return 0xEFCA3D92; } PlugParamIndex GetNumParameters() const override { return kFlangerNumParameters; } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.cpp index 91f5e145f..28eac073b 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.cpp @@ -22,20 +22,19 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* Gargle::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* Gargle::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) Gargle(factory, sndFile, mixStruct); } -Gargle::Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +Gargle::Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kGargleRate] = 0.02f; m_param[kGargleWaveShape] = 0.0f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -57,11 +56,11 @@ void Gargle::Process(float *pOutL, float *pOutR, uint32 numFrames) if(triangle) { const uint32 stop = m_counter + remain; - const float factor = 1.0f / m_periodHalf; + const float factor = 1.0f / static_cast(m_periodHalf); for(uint32 i = m_counter; i < stop; i++) { - *outL++ = *inL++ * i * factor; - *outR++ = *inR++ * i * factor; + *outL++ = *inL++ * static_cast(i) * factor; + *outR++ = *inR++ * static_cast(i) * factor; } } else { @@ -80,11 +79,11 @@ void Gargle::Process(float *pOutL, float *pOutR, uint32 numFrames) if(triangle) { const uint32 stop = m_period - m_counter - remain; - const float factor = 1.0f / m_periodHalf; + const float factor = 1.0f / static_cast(m_periodHalf); for(uint32 i = m_period - m_counter; i > stop; i--) { - *outL++ = *inL++ * i * factor; - *outR++ = *inR++ * i * factor; + *outL++ = *inL++ * static_cast(i) * factor; + *outR++ = *inR++ * static_cast(i) * factor; } } else { diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.h index c4a721c54..f2698335a 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Gargle.h @@ -32,10 +32,9 @@ protected: uint32 m_period, m_periodHalf, m_counter; // In frames public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + Gargle(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0xDAFD8210; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.cpp index 63f5b9c1c..30d69f7ca 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.cpp @@ -72,13 +72,13 @@ MPT_FORCEINLINE float I3DL2Reverb::DelayLine::Get() const } -IMixPlugin* I3DL2Reverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* I3DL2Reverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) I3DL2Reverb(factory, sndFile, mixStruct); } -I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kI3DL2ReverbRoom] = 0.9f; @@ -98,7 +98,6 @@ I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGI SetCurrentProgram(m_program); m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -613,7 +612,7 @@ float I3DL2Reverb::CalcDecayCoeffs(int32 index) if(decayHFRatio > 1.0f) hfRef = mpt::numbers::pi_v; - float c1 = std::pow(10.0f, ((m_delayTaps[index] / m_effectiveSampleRate) * -60.0f / DecayTime()) / 20.0f); + float c1 = std::pow(10.0f, ((static_cast(m_delayTaps[index]) / m_effectiveSampleRate) * -60.0f / DecayTime()) / 20.0f); float c2 = 0.0f; float c21 = (std::pow(c1, 2.0f - 2.0f / decayHFRatio) - 1.0f) / (1.0f - std::cos(hfRef)); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.h index ee3ea6907..cceffeba0 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/I3DL2Reverb.h @@ -91,10 +91,9 @@ protected: bool m_ok = false, m_recalcParams = true; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0xEF985E71; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.cpp index eb237d6f0..d1f35d4df 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.cpp @@ -23,13 +23,13 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* ParamEq::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* ParamEq::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) ParamEq(factory, sndFile, mixStruct); } -ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) , m_maxFreqParam(1.0f) { @@ -38,7 +38,6 @@ ParamEq::ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixSt m_param[kEqGain] = 0.5f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -102,7 +101,7 @@ void ParamEq::Resume() { m_isResumed = true; // Limit center frequency to a third of the sampling rate. - m_maxFreqParam = Clamp((m_SndFile.GetSampleRate() / 3.0f - 80.0f) / 15920.0f, 0.0f, 1.0f); + m_maxFreqParam = Clamp((static_cast(m_SndFile.GetSampleRate()) / 3.0f - 80.0f) / 15920.0f, 0.0f, 1.0f); RecalculateEqParams(); PositionChanged(); } @@ -170,7 +169,7 @@ CString ParamEq::GetParamDisplay(PlugParamIndex param) void ParamEq::RecalculateEqParams() { LimitMax(m_param[kEqCenter], m_maxFreqParam); - const float freq = FreqInHertz() / m_SndFile.GetSampleRate(); + const float freq = FreqInHertz() / static_cast(m_SndFile.GetSampleRate()); const float a = std::pow(10.0f, GainInDecibel() / 40.0f); const float w0 = 2.0f * mpt::numbers::pi_v * freq; const float sinW0 = std::sin(w0); diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.h index 6ad3e4f30..e59ce9967 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/ParamEq.h @@ -38,10 +38,9 @@ protected: float m_maxFreqParam; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + ParamEq(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0x120CED89; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.cpp index 3f8757a29..a9076378e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.cpp @@ -22,13 +22,13 @@ OPENMPT_NAMESPACE_BEGIN namespace DMO { -IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) { return new (std::nothrow) WavesReverb(factory, sndFile, mixStruct); } -WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) +WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct) : IMixPlugin(factory, sndFile, mixStruct) { m_param[kRvbInGain] = 1.0f; @@ -37,7 +37,6 @@ WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGI m_param[kRvbHighFreqRTRatio] = 0.0f; m_mixBuffer.Initialize(2, 2); - InsertIntoFactoryList(); } @@ -145,12 +144,12 @@ void WavesReverb::Resume() { m_isResumed = true; // Recalculate delays - uint32 delay0 = mpt::saturate_round(m_SndFile.GetSampleRate() * 0.045f); - uint32 delay1 = mpt::saturate_round(delay0 * 1.18920707f); // 2^0.25 - uint32 delay2 = mpt::saturate_round(delay1 * 1.18920707f); - uint32 delay3 = mpt::saturate_round(delay2 * 1.18920707f); - uint32 delay4 = mpt::saturate_round((delay0 + delay2) * 0.11546667f); - uint32 delay5 = mpt::saturate_round((delay1 + delay3) * 0.11546667f); + uint32 delay0 = mpt::saturate_round(static_cast(m_SndFile.GetSampleRate()) * 0.045f); + uint32 delay1 = mpt::saturate_round(static_cast(delay0) * 1.18920707f); // 2^0.25 + uint32 delay2 = mpt::saturate_round(static_cast(delay1) * 1.18920707f); + uint32 delay3 = mpt::saturate_round(static_cast(delay2) * 1.18920707f); + uint32 delay4 = mpt::saturate_round(static_cast(delay0 + delay2) * 0.11546667f); + uint32 delay5 = mpt::saturate_round(static_cast(delay1 + delay3) * 0.11546667f); // Comb delays m_delay[0] = delay0 - delay4; m_delay[1] = delay2 - delay4; @@ -227,8 +226,8 @@ CString WavesReverb::GetParamDisplay(PlugParamIndex param) void WavesReverb::RecalculateWavesReverbParams() { // Recalculate filters - const double ReverbTimeSmp = -3000.0 / (m_SndFile.GetSampleRate() * ReverbTime()); - const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / HighFreqRTRatio() - 1.0); + const double ReverbTimeSmp = -3000.0 / (static_cast(m_SndFile.GetSampleRate()) * static_cast(ReverbTime())); + const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / static_cast(HighFreqRTRatio()) - 1.0); m_coeffs[0] = static_cast(std::pow(10.0, m_delay[4] * ReverbTimeSmp)); m_coeffs[1] = static_cast(std::pow(10.0, m_delay[5] * ReverbTimeSmp)); @@ -238,15 +237,15 @@ void WavesReverb::RecalculateWavesReverbParams() { double gain1 = std::pow(10.0, m_delay[pair] * ReverbTimeSmp); double gain2 = (1.0 - std::pow(10.0, (m_delay[pair] + m_delay[4 + pair / 2]) * ReverbTimeSmpHF)) * 0.5; - double gain3 = gain1 * m_coeffs[pair / 2]; + double gain3 = gain1 * static_cast(m_coeffs[pair / 2]); double gain4 = gain3 * (((gain3 + 1.0) * gain3 + 1.0) * gain3 + 1.0) + 1.0; m_coeffs[2 + pair * 2] = static_cast(gain1 * (1.0 - gain2)); m_coeffs[3 + pair * 2] = static_cast(gain1 * gain2); sum += gain4 * gain4; } - double inGain = std::pow(10.0, GainInDecibel(m_param[kRvbInGain]) * 0.05); - double reverbMix = std::pow(10.0, GainInDecibel(m_param[kRvbReverbMix]) * 0.1); + double inGain = std::pow(10.0, static_cast(GainInDecibel(m_param[kRvbInGain])) * 0.05); + double reverbMix = std::pow(10.0, static_cast(GainInDecibel(m_param[kRvbReverbMix])) * 0.1); m_dryFactor = static_cast(std::sqrt(1.0 - reverbMix) * inGain); m_wetFactor = static_cast(std::sqrt(reverbMix) * (4.0 / std::sqrt(sum) * inGain)); } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.h b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.h index 13e9af1ed..5827a7212 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/WavesReverb.h @@ -47,10 +47,9 @@ protected: } m_state; public: - static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); - WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); + static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); + WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN &mixStruct); - void Release() override { delete this; } int32 GetUID() const override { return 0x87FC0268; } int32 GetVersion() const override { return 0; } void Idle() override { } diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp index 155620831..e101e7496 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/tuning.cpp @@ -74,7 +74,15 @@ CTuning::CTuning() { m_RatioTable.clear(); m_NoteMin = s_NoteMinDefault; +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109455 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif m_RatioTable.resize(s_RatioTableSizeDefault, 1); +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +#pragma GCC diagnostic pop +#endif m_GroupSize = 0; m_GroupRatio = 0; m_RatioTableFine.clear(); @@ -304,7 +312,7 @@ RATIOTYPE CTuning::GetRatio(const NOTEINDEXTYPE baseNote, const STEPINDEXTYPE ba } else { // Geometric finestepping - fineRatio = std::pow(GetRatio(note + 1) / GetRatio(note), static_cast(fineStep) / (fineStepCount + 1)); + fineRatio = std::pow(GetRatio(note + 1) / GetRatio(note), static_cast(fineStep) / static_cast(fineStepCount + 1)); } return m_RatioTable[note - m_NoteMin] * fineRatio; } @@ -368,7 +376,7 @@ void CTuning::UpdateFineStepTable() } m_RatioTableFine.resize(m_FineStepCount); const RATIOTYPE q = GetRatio(GetNoteRange().first + 1) / GetRatio(GetNoteRange().first); - const RATIOTYPE rFineStep = std::pow(q, static_cast(1)/(m_FineStepCount+1)); + const RATIOTYPE rFineStep = std::pow(q, static_cast(1) / static_cast(m_FineStepCount + 1)); for(USTEPINDEXTYPE i = 1; i<=m_FineStepCount; i++) m_RatioTableFine[i-1] = std::pow(rFineStep, static_cast(i)); return; @@ -390,8 +398,8 @@ void CTuning::UpdateFineStepTable() const NOTEINDEXTYPE startnote = GetRefNote(GetNoteRange().first); for(UNOTEINDEXTYPE i = 0; i(1)/(m_FineStepCount+1)); + const NOTEINDEXTYPE refnote = GetRefNote(static_cast(startnote + i)); + const RATIOTYPE rFineStep = std::pow(GetRatio(refnote+1) / GetRatio(refnote), static_cast(1) / static_cast(m_FineStepCount + 1)); for(UNOTEINDEXTYPE j = 1; j<=m_FineStepCount; j++) { m_RatioTableFine[m_FineStepCount * refnote + (j-1)] = std::pow(rFineStep, static_cast(j)); @@ -501,7 +509,7 @@ SerializationResult CTuning::InitDeserialize(std::istream &iStrm, mpt::Charset d } // If reader status is ok and m_NoteMin is somewhat reasonable, process data. - if(!((ssb.GetStatus() & srlztn::SNT_FAILURE) == 0 && m_NoteMin >= -300 && m_NoteMin <= 300)) + if(ssb.HasFailed() || (m_NoteMin < -300) || (m_NoteMin > 300)) { return SerializationResult::Failure; } @@ -576,7 +584,7 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars if(!inStrm.good()) return SerializationResult::Failure; - const std::streamoff startPos = inStrm.tellg(); + const std::streamoff startPos = static_cast(inStrm.tellg()); //First checking is there expected begin sequence. char begin[8]; @@ -585,7 +593,7 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars if(std::memcmp(begin, "CTRTI_B.", 8)) { //Returning stream position if beginmarker was not found. - inStrm.seekg(startPos); + inStrm.seekg(startPos, std::ios::beg); return SerializationResult::Failure; } @@ -757,10 +765,9 @@ SerializationResult CTuning::InitDeserializeOLD(std::istream &inStrm, mpt::Chars return SerializationResult::Failure; } - char end[8]; - MemsetZero(end); - inStrm.read(reinterpret_cast(&end), sizeof(end)); - if(std::memcmp(end, "CTRTI_E.", 8)) + std::array end = {}; + mpt::IO::Read(inStrm, end); + if(std::memcmp(end.data(), "CTRTI_E.", 8)) { return SerializationResult::Failure; } @@ -848,7 +855,7 @@ Tuning::SerializationResult CTuning::Serialize(std::ostream& outStrm) const ssb.FinishWrite(); - return ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0) ? Tuning::SerializationResult::Failure : Tuning::SerializationResult::Success; + return ssb.HasFailed() ? Tuning::SerializationResult::Failure : Tuning::SerializationResult::Success; } @@ -856,7 +863,7 @@ Tuning::SerializationResult CTuning::Serialize(std::ostream& outStrm) const bool CTuning::WriteSCL(std::ostream &f, const mpt::PathString &filename) const { - mpt::IO::WriteTextCRLF(f, MPT_AFORMAT("! {}")(mpt::ToCharset(mpt::Charset::ISO8859_1, (filename.GetFileName() + filename.GetFileExt()).ToUnicode()))); + mpt::IO::WriteTextCRLF(f, MPT_AFORMAT("! {}")(mpt::ToCharset(mpt::Charset::ISO8859_1, (filename.GetFilenameBase() + filename.GetFilenameExtension()).ToUnicode()))); mpt::IO::WriteTextCRLF(f, "!"); std::string name = mpt::ToCharset(mpt::Charset::ISO8859_1, GetName()); for(auto & c : name) { if(static_cast(c) < 32) c = ' '; } // remove control characters diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningCollection.cpp b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningCollection.cpp index f11260b28..322567d0f 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningCollection.cpp +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningCollection.cpp @@ -17,6 +17,8 @@ #include "../common/mptFileIO.h" #include "Loaders.h" #ifdef MODPLUG_TRACKER +#include "mpt/fs/fs.hpp" +#include "mpt/io_file/outputfile.hpp" #include "../mptrack/TrackerSettings.h" #endif //MODPLUG_TRACKER @@ -95,7 +97,7 @@ Tuning::SerializationResult CTuningCollection::Serialize(std::ostream& oStrm, co ssb.WriteItem(*m_Tunings[i], "2", &WriteTuning); ssb.FinishWrite(); - if(ssb.GetStatus() & srlztn::SNT_FAILURE) + if(ssb.HasFailed()) return Tuning::SerializationResult::Failure; else return Tuning::SerializationResult::Success; @@ -104,14 +106,14 @@ Tuning::SerializationResult CTuningCollection::Serialize(std::ostream& oStrm, co Tuning::SerializationResult CTuningCollection::Deserialize(std::istream &iStrm, mpt::ustring &name, mpt::Charset defaultCharset) { - std::istream::pos_type startpos = iStrm.tellg(); + std::streamoff startpos = static_cast(iStrm.tellg()); const Tuning::SerializationResult oldLoadingResult = DeserializeOLD(iStrm, name, defaultCharset); if(oldLoadingResult == Tuning::SerializationResult::NoMagic) { // An old version was not recognised - trying new version. iStrm.clear(); - iStrm.seekg(startpos); + iStrm.seekg(startpos, std::ios::beg); srlztn::SsbRead ssb(iStrm); ssb.BeginRead("TC", 3); // version int8 use_utf8 = 0; @@ -123,15 +125,15 @@ Tuning::SerializationResult CTuningCollection::Deserialize(std::istream &iStrm, for(srlztn::SsbRead::ReadIterator iter = iterBeg; iter != iterEnd; iter++) { uint16 dummyEditMask = 0xffff; - if (ssb.CompareId(iter, "0") == srlztn::SsbRead::IdMatch) + if(ssb.MatchesId(iter, "0")) ssb.ReadIterItem(iter, name, [charset](std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy){ return ReadStr(iStrm, ustr, dummy, charset); }); - else if (ssb.CompareId(iter, "1") == srlztn::SsbRead::IdMatch) + else if(ssb.MatchesId(iter, "1")) ssb.ReadIterItem(iter, dummyEditMask); - else if (ssb.CompareId(iter, "2") == srlztn::SsbRead::IdMatch) + else if(ssb.MatchesId(iter, "2")) ssb.ReadIterItem(iter, *this, [charset](std::istream &iStrm, CTuningCollection &Tc, const std::size_t dummy){ return ReadTuning(iStrm, Tc, dummy, charset); }); } - if(ssb.GetStatus() & srlztn::SNT_FAILURE) + if(ssb.HasFailed()) return Tuning::SerializationResult::Failure; else return Tuning::SerializationResult::Success; @@ -281,7 +283,7 @@ CTuning* CTuningCollection::AddTuning(std::istream &inStrm, mpt::Charset default bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix) { bool error = false; - auto numberFmt = mpt::FormatSpec().Dec().FillNul().Width(1 + static_cast(std::log10(tc.GetNumTunings()))); + auto numberFmt = mpt::format_simple_spec().Dec().FillNul().Width(1 + static_cast(std::log10(tc.GetNumTunings()))); for(std::size_t i = 0; i < tc.GetNumTunings(); ++i) { const CTuning & tuning = *(tc.GetTuning(i)); @@ -292,15 +294,14 @@ bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString & { tuningName = U_("untitled"); } - SanitizeFilename(tuningName); - fn += mpt::PathString::FromUnicode(MPT_UFORMAT("{} - {}")(mpt::ufmt::fmt(i + 1, numberFmt), tuningName)); + fn += mpt::PathString::FromUnicode(MPT_UFORMAT("{} - {}")(mpt::ufmt::fmt(i + 1, numberFmt), tuningName)).AsSanitizedComponent(); fn += mpt::PathString::FromUTF8(CTuning::s_FileExtension); - if(fn.FileOrDirectoryExists()) + if(mpt::native_fs{}.exists(fn)) { error = true; } else { - mpt::SafeOutputFile sfout(fn, std::ios::binary, mpt::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); + mpt::IO::SafeOutputFile sfout(fn, std::ios::binary, mpt::IO::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave)); if(tuning.Serialize(sfout) != Tuning::SerializationResult::Success) { error = true; diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningbase.h b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningbase.h index 49988136f..e72146a2d 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningbase.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningbase.h @@ -74,7 +74,7 @@ class CTuning; } // namespace Tuning -typedef Tuning::CTuning CTuning; +using CTuning = Tuning::CTuning; OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningcollection.h b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningcollection.h index bf0b3327a..3208bd76e 100644 --- a/Frameworks/OpenMPT/OpenMPT/soundlib/tuningcollection.h +++ b/Frameworks/OpenMPT/OpenMPT/soundlib/tuningcollection.h @@ -106,7 +106,7 @@ bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString & } // namespace Tuning -typedef Tuning::CTuningCollection CTuningCollection; +using CTuningCollection = Tuning::CTuningCollection; OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/arch.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/arch.hpp new file mode 100644 index 000000000..e5c99868b --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/arch.hpp @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_ARCH_ARCH_HPP +#define MPT_ARCH_ARCH_HPP + + +#include "mpt/arch/feature_flags.hpp" +#include "mpt/arch/x86_amd64.hpp" +#include "mpt/base/detect.hpp" +#include "mpt/base/integer.hpp" +#include "mpt/base/macros.hpp" +#include "mpt/base/namespace.hpp" + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace arch { + + + +namespace unknown { + +template +struct no_flags { + constexpr no_flags() noexcept = default; + constexpr no_flags operator~() noexcept { + return no_flags{}; + } + constexpr no_flags & operator&=(no_flags) noexcept { + return *this; + } + constexpr no_flags & operator|=(no_flags) noexcept { + return *this; + } + constexpr no_flags & operator^=(no_flags) noexcept { + return *this; + } + friend constexpr no_flags operator&(no_flags, no_flags) noexcept { + return no_flags{}; + } + friend constexpr no_flags operator|(no_flags, no_flags) noexcept { + return no_flags{}; + } + friend constexpr no_flags operator^(no_flags, no_flags) noexcept { + return no_flags{}; + } + friend constexpr bool operator==(no_flags, no_flags) noexcept { + return true; + } + friend constexpr bool operator!=(no_flags, no_flags) noexcept { + return false; + } + constexpr bool supports(no_flags) noexcept { + return true; + } + explicit constexpr operator bool() const noexcept { + return true; + } + constexpr bool operator!() const noexcept { + return false; + } +}; + +struct no_feature_flags_tag { +}; + +struct no_mode_flags_tag { +}; + +using feature_flags = mpt::arch::basic_feature_flags>; +using mode_flags = mpt::arch::basic_feature_flags>; + +namespace feature { +inline constexpr feature_flags none = feature_flags{}; +} // namespace feature + +namespace mode { +inline constexpr mode_flags none = mode_flags{}; +} // namespace mode + +struct cpu_info { +public: + cpu_info() = default; +public: + MPT_CONSTEXPRINLINE bool operator[](feature_flags) const noexcept { + return true; + } + MPT_CONSTEXPRINLINE bool has_features(feature_flags) const noexcept { + return true; + } + MPT_CONSTEXPRINLINE feature_flags get_features() const noexcept { + return {}; + } + MPT_CONSTEXPRINLINE bool operator[](mode_flags) const noexcept { + return true; + } + MPT_CONSTEXPRINLINE bool enabled_modes(mode_flags) const noexcept { + return true; + } + MPT_CONSTEXPRINLINE mode_flags get_modes() const noexcept { + return {}; + } +}; + +[[nodiscard]] MPT_CONSTEVAL feature_flags assumed_features() noexcept { + return {}; +} + +[[nodiscard]] MPT_CONSTEVAL mode_flags assumed_modes() noexcept { + return {}; +} + +} // namespace unknown + + + +#if MPT_ARCH_X86 +namespace current = x86; +#elif MPT_ARCH_AMD64 +namespace current = amd64; +#else +namespace current = unknown; +#endif + +using cpu_info = mpt::arch::current::cpu_info; + +inline const cpu_info & get_cpu_info() { + static cpu_info info; + return info; +} + +namespace detail { + +struct info_initializer { + inline info_initializer() noexcept { + get_cpu_info(); + } +}; + +inline info_initializer g_info_initializer; + +} // namespace detail + +struct flags_cache { +private: + const mpt::arch::current::feature_flags Features; + const mpt::arch::current::mode_flags Modes; +public: + MPT_CONSTEXPRINLINE flags_cache(const mpt::arch::cpu_info & info) noexcept + : Features(info.get_features()) + , Modes(info.get_modes()) { + return; + } + [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mpt::arch::current::feature_flags query_features) const noexcept { + return ((Features & query_features) == query_features); + } + [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(mpt::arch::current::feature_flags query_features) const noexcept { + return ((Features & query_features) == query_features); + } + [[nodiscard]] MPT_CONSTEXPRINLINE mpt::arch::current::feature_flags get_features() const noexcept { + return Features; + } + [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mpt::arch::current::mode_flags query_modes) const noexcept { + return ((Modes & query_modes) == query_modes); + } + [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(mpt::arch::current::mode_flags query_modes) const noexcept { + return ((Modes & query_modes) == query_modes); + } + [[nodiscard]] MPT_CONSTEXPRINLINE mpt::arch::current::mode_flags get_modes() const noexcept { + return Modes; + } +}; + + + +} // namespace arch + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_ARCH_ARCH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/feature_flags.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/feature_flags.hpp new file mode 100644 index 000000000..52e60b16c --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/feature_flags.hpp @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_ARCH_FEATURE_FLAGS_HPP +#define MPT_ARCH_FEATURE_FLAGS_HPP + + +#include "mpt/base/namespace.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace arch { + + + +template +struct [[nodiscard]] basic_feature_flags { +private: + bitset m_flags{}; +public: + constexpr basic_feature_flags() noexcept = default; + explicit constexpr basic_feature_flags(bitset flags) noexcept + : m_flags(flags) { + return; + } + [[nodiscard]] constexpr basic_feature_flags operator~() noexcept { + return basic_feature_flags{~m_flags}; + } + constexpr basic_feature_flags & operator&=(basic_feature_flags o) noexcept { + m_flags &= o.m_flags; + return *this; + } + constexpr basic_feature_flags & operator|=(basic_feature_flags o) noexcept { + m_flags |= o.m_flags; + return *this; + } + constexpr basic_feature_flags & operator^=(basic_feature_flags o) noexcept { + m_flags ^= o.m_flags; + return *this; + } + [[nodiscard]] friend constexpr basic_feature_flags operator&(basic_feature_flags a, basic_feature_flags b) noexcept { + return basic_feature_flags{static_cast(a.m_flags & b.m_flags)}; + } + [[nodiscard]] friend constexpr basic_feature_flags operator|(basic_feature_flags a, basic_feature_flags b) noexcept { + return basic_feature_flags{static_cast(a.m_flags | b.m_flags)}; + } + [[nodiscard]] friend constexpr basic_feature_flags operator^(basic_feature_flags a, basic_feature_flags b) noexcept { + return basic_feature_flags{static_cast(a.m_flags ^ b.m_flags)}; + } + [[nodiscard]] friend constexpr bool operator==(basic_feature_flags a, basic_feature_flags b) noexcept { + return a.m_flags == b.m_flags; + } + [[nodiscard]] friend constexpr bool operator!=(basic_feature_flags a, basic_feature_flags b) noexcept { + return a.m_flags != b.m_flags; + } + [[nodiscard]] constexpr bool supports(basic_feature_flags query) noexcept { + return (m_flags & query.m_flags) == query.m_flags; + } + [[nodiscard]] explicit constexpr operator bool() const noexcept { + return m_flags ? true : false; + } + [[nodiscard]] constexpr bool operator!() const noexcept { + return m_flags ? false : true; + } +}; + + + +} // namespace arch + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_ARCH_FEATURE_FLAGS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/x86_amd64.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/x86_amd64.hpp new file mode 100644 index 000000000..1dbb13b07 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/arch/x86_amd64.hpp @@ -0,0 +1,2147 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_ARCH_X86_AMD64_HPP +#define MPT_ARCH_X86_AMD64_HPP + + +#include "mpt/arch/feature_flags.hpp" +#include "mpt/base/bit.hpp" +#include "mpt/base/detect.hpp" +#include "mpt/base/integer.hpp" +#include "mpt/base/macros.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/base/utility.hpp" +#include "mpt/osinfo/windows_version.hpp" + +#include +#include +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 +#if MPT_COMPILER_GCC +#include +#endif +#endif +#include +#include +#include + +#include + +#if MPT_OS_DJGPP +#include +#include +#endif + +#if MPT_OS_WINDOWS +#include +#endif + +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 +#if MPT_COMPILER_MSVC +#include +#include +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG +#include +#include +#endif +#endif + +// skip assumed features for amd64 +#define MPT_ARCH_X86_AMD64_FAST_DETECT 0 + + + +// clang-format off + +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 + +#if MPT_COMPILER_MSVC + +#if defined(_M_X64) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #define MPT_ARCH_X86_I486 + #define MPT_ARCH_X86_CPUID + #define MPT_ARCH_X86_TSC + #define MPT_ARCH_X86_CX8 + #define MPT_ARCH_X86_CMOV + #define MPT_ARCH_X86_MMX + #define MPT_ARCH_X86_3DNOWPREFETCH + #define MPT_ARCH_X86_FXSR + #define MPT_ARCH_X86_SSE + #define MPT_ARCH_X86_SSE2 +#elif defined(_M_IX86) && defined(_M_IX86_FP) + #if (_M_IX86_FP >= 2) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #define MPT_ARCH_X86_I486 + #define MPT_ARCH_X86_CPUID + #define MPT_ARCH_X86_TSC + #define MPT_ARCH_X86_CX8 + #define MPT_ARCH_X86_CMOV + #define MPT_ARCH_X86_MMX + #define MPT_ARCH_X86_3DNOWPREFETCH + #define MPT_ARCH_X86_FXSR + #define MPT_ARCH_X86_SSE + #define MPT_ARCH_X86_SSE2 + #elif (_M_IX86_FP == 1) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #define MPT_ARCH_X86_I486 + #define MPT_ARCH_X86_CPUID + #define MPT_ARCH_X86_TSC + #define MPT_ARCH_X86_CX8 + #define MPT_ARCH_X86_CMOV + #define MPT_ARCH_X86_MMX + #define MPT_ARCH_X86_3DNOWPREFETCH + #define MPT_ARCH_X86_FXSR + #define MPT_ARCH_X86_SSE + #elif MPT_MSVC_AT_LEAST(2008, 0) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #define MPT_ARCH_X86_I486 + #define MPT_ARCH_X86_CPUID + #define MPT_ARCH_X86_TSC + #define MPT_ARCH_X86_CX8 + #elif MPT_MSVC_AT_LEAST(2005, 0) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #define MPT_ARCH_X86_I486 + #elif MPT_MSVC_AT_LEAST(1998, 0) + #define MPT_ARCH_X86_I386 + #define MPT_ARCH_X86_FPU + #define MPT_ARCH_X86_FSIN + #else + #define MPT_ARCH_X86_I386 + #endif +#endif +#if defined(__AVX__) + #ifndef MPT_ARCH_X86_XSAVE + #define MPT_ARCH_X86_XSAVE + #endif + #define MPT_ARCH_X86_AVX +#endif +#if defined(__AVX2__) + #ifndef MPT_ARCH_X86_XSAVE + #define MPT_ARCH_X86_XSAVE + #endif + #define MPT_ARCH_X86_AVX2 + #define MPT_ARCH_X86_FMA + #define MPT_ARCH_X86_BMI1 +#endif + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + +#define MPT_ARCH_X86_I386 +#if !defined(_SOFT_FLOAT) + #define MPT_ARCH_X86_FPU + // GCC does not provide a macro for FSIN. Deduce it from 486 later. +#endif +#if defined(__i486__) + // GCC does not consistently provide i486, deduce it later from cpuid. + #define MPT_ARCH_X86_I486 +#endif +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + // GCC does not provide TSC or CPUID. + // Imply it by CX8. + #define MPT_ARCH_X86_CX8 + #define MPT_ARCH_X86_TSC + #define MPT_ARCH_X86_CPUID +#endif +#if defined(__i686__) || defined(__athlon__) + // GCC is broken here and does not set __i686__ for various non-Intel and even modern Intel CPUs + // Imply __i686__ by __SSE__ as a work-around. + #define MPT_ARCH_X86_CMOV +#endif +#if defined(MPT_ARCH_X86_CPUID) + #ifndef MPT_ARCH_X86_I486 + #define MPT_ARCH_X86_I486 + #endif +#endif +#if defined(MPT_ARCH_X86_I486) && defined(MPT_ARCH_X86_FPU) + #define MPT_ARCH_X86_FSIN +#endif +#ifdef __MMX__ + #define MPT_ARCH_X86_MMX +#endif +#ifdef __3dNOW__ + #define MPT_ARCH_X86_MMXEXT + #define MPT_ARCH_X86_3DNOW +#endif +#ifdef __3dNOW_A__ + #define MPT_ARCH_X86_3DNOWEXT +#endif +#ifdef __FXSR__ + #define MPT_ARCH_X86_FXSR +#endif +#ifdef __SSE__ + #define MPT_ARCH_X86_3DNOWPREFETCH + #define MPT_ARCH_X86_SSE + #ifndef MPT_ARCH_X86_CMOV + #define MPT_ARCH_X86_CMOV + #endif +#endif +#ifdef __SSE2__ + #define MPT_ARCH_X86_SSE2 +#endif +#ifdef __SSE3__ + #define MPT_ARCH_X86_SSE3 +#endif +#ifdef __SSSE3__ + #define MPT_ARCH_X86_SSSE3 +#endif +#ifdef __SSE4_1__ + #define MPT_ARCH_X86_SSE4_1 +#endif +#ifdef __SSE4_2__ + #define MPT_ARCH_X86_SSE4_2 +#endif +#ifdef __XSAVE__ + #define MPT_ARCH_X86_XSAVE +#endif +#ifdef __AVX__ + #define MPT_ARCH_X86_AVX +#endif +#ifdef __AVX2__ + #define MPT_ARCH_X86_AVX2 +#endif +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 + #define MPT_ARCH_X86_CX16 +#endif +#ifdef __LAHF_SAHF__ + #define MPT_ARCH_X86_LAHF +#endif +#ifdef __POPCNT__ + #define MPT_ARCH_X86_POPCNT +#endif +#ifdef __BMI__ + #define MPT_ARCH_X86_BMI1 +#endif +#ifdef __BMI2__ + #define MPT_ARCH_X86_BMI2 +#endif +#ifdef __F16C__ + #define MPT_ARCH_X86_F16C +#endif +#ifdef __FMA__ + #define MPT_ARCH_X86_FMA +#endif +#ifdef __LZCNT__ + #define MPT_ARCH_X86_LZCNT +#endif +#ifdef __MOVBE__ + #define MPT_ARCH_X86_MOVBE +#endif + +#endif // MPT_COMPILER + +#endif // MPT_ARCH + +// clang-format on + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace arch { + + + +namespace x86 { + + + +using feature_flags = mpt::arch::basic_feature_flags; + + +using mode_flags = mpt::arch::basic_feature_flags; + + + +// clang-format off + +namespace feature { +inline constexpr feature_flags none = feature_flags{}; +inline constexpr feature_flags intel386 = feature_flags{ 0x0000'0001 }; +inline constexpr feature_flags fpu = feature_flags{ 0x0000'0002 }; +inline constexpr feature_flags fsin = feature_flags{ 0x0000'0004 }; +inline constexpr feature_flags intel486 = feature_flags{ 0x0000'0008 }; // XADD, BSWAP, CMPXCHG +inline constexpr feature_flags cpuid = feature_flags{ 0x0000'0010 }; +inline constexpr feature_flags tsc = feature_flags{ 0x0000'0020 }; +inline constexpr feature_flags cx8 = feature_flags{ 0x0000'0040 }; +inline constexpr feature_flags cmov = feature_flags{ 0x0000'0080 }; +inline constexpr feature_flags mmx = feature_flags{ 0x0000'0100 }; +inline constexpr feature_flags mmxext = feature_flags{ 0x0000'0200 }; +inline constexpr feature_flags x3dnow = feature_flags{ 0x0000'0400 }; +inline constexpr feature_flags x3dnowext = feature_flags{ 0x0000'0800 }; +inline constexpr feature_flags x3dnowprefetch = feature_flags{ 0x0000'1000 }; +inline constexpr feature_flags fxsr = feature_flags{ 0x0000'2000 }; +inline constexpr feature_flags sse = feature_flags{ 0x0000'4000 }; +inline constexpr feature_flags sse2 = feature_flags{ 0x0000'8000 }; +inline constexpr feature_flags sse3 = feature_flags{ 0x0001'0000 }; +inline constexpr feature_flags ssse3 = feature_flags{ 0x0002'0000 }; +inline constexpr feature_flags sse4_1 = feature_flags{ 0x0004'0000 }; +inline constexpr feature_flags sse4_2 = feature_flags{ 0x0008'0000 }; +inline constexpr feature_flags xsave = feature_flags{ 0x0010'0000 }; +inline constexpr feature_flags avx = feature_flags{ 0x0020'0000 }; +inline constexpr feature_flags avx2 = feature_flags{ 0x0040'0000 }; +inline constexpr feature_flags cx16 = feature_flags{ 0x0080'0000 }; +inline constexpr feature_flags lahf = feature_flags{ 0x0100'0000 }; +inline constexpr feature_flags popcnt = feature_flags{ 0x0200'0000 }; +inline constexpr feature_flags bmi1 = feature_flags{ 0x0400'0000 }; +inline constexpr feature_flags bmi2 = feature_flags{ 0x0800'0000 }; +inline constexpr feature_flags f16c = feature_flags{ 0x1000'0000 }; +inline constexpr feature_flags fma = feature_flags{ 0x2000'0000 }; +inline constexpr feature_flags lzcnt = feature_flags{ 0x4000'0000 }; +inline constexpr feature_flags movbe = feature_flags{ 0x8000'0000 }; +} // namespace feature + +namespace mode { +inline constexpr mode_flags base = mode_flags{ 0x00 }; +inline constexpr mode_flags xmm128sse = mode_flags{ 0x01 }; +inline constexpr mode_flags ymm256avx = mode_flags{ 0x02 }; +} // namespace mode + +namespace featureset { +inline constexpr feature_flags intel386 = feature::intel386; +inline constexpr feature_flags intel486SX = featureset::intel386 | feature::intel486; +inline constexpr feature_flags intel486DX = featureset::intel486SX | feature::fpu | feature::fsin; +inline constexpr feature_flags intel586 = featureset::intel486DX | feature::cpuid | feature::tsc | feature::cx8; +inline constexpr feature_flags intel586_mmx = featureset::intel586 | feature::mmx; +inline constexpr feature_flags intel686 = featureset::intel586 | feature::cmov; +inline constexpr feature_flags intel686_mmx = featureset::intel686 | feature::mmx; +inline constexpr feature_flags intel686_sse = featureset::intel686_mmx | feature::fxsr | feature::sse | feature::x3dnowprefetch; +inline constexpr feature_flags intel686_sse2 = featureset::intel686_sse | feature::sse2; +inline constexpr feature_flags intel786 = featureset::intel686_sse2; +inline constexpr feature_flags amd64 = featureset::intel686_sse2; +inline constexpr feature_flags amd64_v2 = featureset::amd64 | feature::cx16 | feature::lahf | feature::popcnt | feature::sse3 | feature::ssse3 | feature::sse4_1 | feature::sse4_2; +inline constexpr feature_flags amd64_v3 = featureset::amd64_v2 | feature::xsave | feature::avx | feature::avx2 | feature::bmi1 | feature::bmi2 | feature::f16c | feature::fma | feature::lzcnt | feature::movbe; +inline constexpr feature_flags msvc_x86_1998 = featureset::intel386 | feature::fpu | feature::fsin; +inline constexpr feature_flags msvc_x86_2005 = featureset::intel486DX; +inline constexpr feature_flags msvc_x86_2008 = featureset::intel586; +inline constexpr feature_flags msvc_x86_sse = featureset::intel686_sse; +inline constexpr feature_flags msvc_x86_sse2 = featureset::intel686_sse2; +inline constexpr feature_flags msvc_x86_avx = featureset::intel686_sse2 | feature::xsave | feature::avx; +inline constexpr feature_flags msvc_x86_avx2 = featureset::intel686_sse2 | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1; +inline constexpr feature_flags msvc_amd64 = featureset::amd64; +inline constexpr feature_flags msvc_amd64_avx = featureset::amd64 | feature::xsave | feature::avx; +inline constexpr feature_flags msvc_amd64_avx2 = featureset::amd64 | feature::xsave | feature::avx | feature::avx2 | feature::fma | feature::bmi1; +} // namespace featureset + +namespace modeset { +inline constexpr mode_flags intel386 = mode::base; +inline constexpr mode_flags intel486SX = mode::base; +inline constexpr mode_flags intel486DX = mode::base; +inline constexpr mode_flags intel586 = mode::base; +inline constexpr mode_flags intel586_mmx = mode::base; +inline constexpr mode_flags intel686 = mode::base; +inline constexpr mode_flags intel686_mmx = mode::base; +inline constexpr mode_flags intel686_sse = mode::base | mode::xmm128sse; +inline constexpr mode_flags intel686_sse2 = mode::base | mode::xmm128sse; +inline constexpr mode_flags intel786 = mode::base | mode::xmm128sse; +inline constexpr mode_flags amd64 = mode::base | mode::xmm128sse; +inline constexpr mode_flags amd64_v2 = mode::base | mode::xmm128sse; +inline constexpr mode_flags amd64_v3 = mode::base | mode::xmm128sse | mode::ymm256avx; +inline constexpr mode_flags msvc_x86_1998 = mode::base; +inline constexpr mode_flags msvc_x86_2005 = mode::base; +inline constexpr mode_flags msvc_x86_2008 = mode::base; +inline constexpr mode_flags msvc_x86_sse = mode::base | mode::xmm128sse; +inline constexpr mode_flags msvc_x86_sse2 = mode::base | mode::xmm128sse; +inline constexpr mode_flags msvc_x86_avx = mode::base | mode::xmm128sse | mode::ymm256avx; +inline constexpr mode_flags msvc_x86_avx2 = mode::base | mode::xmm128sse | mode::ymm256avx; +inline constexpr mode_flags msvc_amd64 = mode::base | mode::xmm128sse; +inline constexpr mode_flags msvc_amd64_avx = mode::base | mode::xmm128sse | mode::ymm256avx; +inline constexpr mode_flags msvc_amd64_avx2 = mode::base | mode::xmm128sse | mode::ymm256avx; +} // namespace featureset + +// clang-format on + + +enum class vendor : uint8 { + unknown = 0, + AMD, + Centaur, + Cyrix, + Intel, + Transmeta, + NSC, + NexGen, + Rise, + SiS, + UMC, + VIA, + DMnP, + Zhaoxin, + Hygon, + Elbrus, + MiSTer, + bhyve, + KVM, + QEMU, + HyperV, + Parallels, + VMWare, + Xen, + ACRN, + QNX, +}; // enum class vendor + + + +// clang-format off +[[nodiscard]] MPT_CONSTEVAL feature_flags assumed_features() noexcept { + feature_flags flags{}; +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 + #ifdef MPT_ARCH_X86_I386 + flags |= feature::intel386; + #endif + #ifdef MPT_ARCH_X86_FPU + flags |= feature::fpu; + #endif + #ifdef MPT_ARCH_X86_FSIN + flags |= feature::fsin; + #endif + #ifdef MPT_ARCH_X86_CPUID + flags |= feature::cpuid; + #endif + #ifdef MPT_ARCH_X86_TSC + flags |= feature::tsc; + #endif + #ifdef MPT_ARCH_X86_CX8 + flags |= feature::cx8; + #endif + #ifdef MPT_ARCH_X86_CMOV + flags |= feature::cmov; + #endif + #ifdef MPT_ARCH_X86_MMX + flags |= feature::mmx; + #endif + #ifdef MPT_ARCH_X86_MMXEXT + flags |= feature::mmxext; + #endif + #ifdef MPT_ARCH_X86_3DNOW + flags |= feature::x3dnow; + #endif + #ifdef MPT_ARCH_X86_3DNOWEXT + flags |= feature::x3dnowext; + #endif + #ifdef MPT_ARCH_X86_3DNOWPREFETCH + flags |= feature::x3dnowprefetch; + #endif + #ifdef MPT_ARCH_X86_FXSR + flags |= feature::fxsr; + #endif + #ifdef MPT_ARCH_X86_SSE + flags |= feature::sse; + #endif + #ifdef MPT_ARCH_X86_SSE2 + flags |= feature::sse2; + #endif + #ifdef MPT_ARCH_X86_SSE3 + flags |= feature::sse3; + #endif + #ifdef MPT_ARCH_X86_SSSE3 + flags |= feature::ssse3; + #endif + #ifdef MPT_ARCH_X86_SSE4_1 + flags |= feature::sse4_1; + #endif + #ifdef MPT_ARCH_X86_SSE4_2 + flags |= feature::sse4_2; + #endif + #ifdef MPT_ARCH_X86_XSAVE + flags |= feature::xsave; + #endif + #ifdef MPT_ARCH_X86_AVX + flags |= feature::avx; + #endif + #ifdef MPT_ARCH_X86_AVX2 + flags |= feature::avx2; + #endif + #ifdef MPT_ARCH_X86_CX16 + flags |= feature::cx16; + #endif + #ifdef MPT_ARCH_X86_LAHF + flags |= feature::lahf; + #endif + #ifdef MPT_ARCH_X86_POPCNT + flags |= feature::popcnt; + #endif + #ifdef MPT_ARCH_X86_BMI1 + flags |= feature::bmi1; + #endif + #ifdef MPT_ARCH_X86_BMI2 + flags |= feature::bmi2; + #endif + #ifdef MPT_ARCH_X86_F16C + flags |= feature::f16c; + #endif + #ifdef MPT_ARCH_X86_FMA + flags |= feature::fma; + #endif + #ifdef MPT_ARCH_X86_LZCNT + flags |= feature::lzcnt; + #endif + #ifdef MPT_ARCH_X86_MOVBE + flags |= feature::movbe; + #endif +#endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 + return flags; +} +// clang-format on + + +// clang-format off +[[nodiscard]] MPT_CONSTEVAL mode_flags assumed_modes() noexcept { + mode_flags flags{}; +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 + #ifdef MPT_ARCH_X86_SSE + flags |= mode::xmm128sse; + #endif + #ifdef MPT_ARCH_X86_AVX + flags |= mode::ymm256avx; + #endif +#endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 + return flags; +} +// clang-format on + + + +template +struct fixed_string { + std::array m_data = {}; + [[nodiscard]] constexpr const char & operator[](std::size_t i) const noexcept { + return m_data[i]; + } + [[nodiscard]] constexpr char & operator[](std::size_t i) noexcept { + return m_data[i]; + } + [[nodiscard]] constexpr std::size_t size() const noexcept { + return m_data.size(); + } + [[nodiscard]] constexpr const char * data() const noexcept { + return m_data.data(); + } + [[nodiscard]] constexpr char * data() noexcept { + return m_data.data(); + } + [[nodiscard]] constexpr const char * begin() const noexcept { + return m_data.data(); + } + [[nodiscard]] constexpr char * begin() noexcept { + return m_data.data(); + } + [[nodiscard]] constexpr const char * end() const noexcept { + return m_data.data() + m_data.size(); + } + [[nodiscard]] constexpr char * end() noexcept { + return m_data.data() + m_data.size(); + } + [[nodiscard]] constexpr operator std::string_view() const noexcept { +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_COMPILER_QUIRK_NO_STRING_VIEW_ITERATOR_CTOR) + return std::string_view(m_data.begin(), std::find(m_data.begin(), m_data.end(), '\0')); +#else + return std::string_view(m_data.data(), std::find(m_data.begin(), m_data.end(), '\0') - m_data.begin()); +#endif + } + template + [[nodiscard]] friend MPT_CONSTEXPR20_FUN auto operator+(fixed_string a, fixed_string b) -> fixed_string { + fixed_string result; + std::copy(a.begin(), a.end(), result.data() + 0); + std::copy(b.begin(), b.end(), result.data() + N); + return result; + } + [[nodiscard]] inline explicit operator std::string() const { + return std::string(m_data.begin(), std::find(m_data.begin(), m_data.end(), '\0')); + } +}; + + +struct cpu_info { + +private: + + feature_flags Features{}; + mode_flags Modes{}; + uint32 CPUID = 0; + vendor Vendor = vendor::unknown; + uint16 Family = 0; + uint8 Model = 0; + uint8 Stepping = 0; + fixed_string<12> VendorID; + fixed_string<48> BrandID; + bool Virtualized = false; + fixed_string<12> HypervisorVendor; + fixed_string<4> HypervisorInterface; +#if !MPT_ARCH_AMD64 + bool LongMode = false; +#endif // !MPT_ARCH_AMD64 + +public: + + [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](feature_flags query_features) const noexcept { + return ((Features & query_features) == query_features); + } + + [[nodiscard]] MPT_CONSTEXPRINLINE bool has_features(feature_flags query_features) const noexcept { + return ((Features & query_features) == query_features); + } + + [[nodiscard]] MPT_CONSTEXPRINLINE feature_flags get_features() const noexcept { + return Features; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE bool operator[](mode_flags query_modes) const noexcept { + return ((Modes & query_modes) == query_modes); + } + + [[nodiscard]] MPT_CONSTEXPRINLINE bool enabled_modes(mode_flags query_modes) const noexcept { + return ((Modes & query_modes) == query_modes); + } + + [[nodiscard]] MPT_CONSTEXPRINLINE mode_flags get_modes() const noexcept { + return Modes; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE uint32 get_cpuid() const noexcept { + return CPUID; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE vendor get_vendor() const noexcept { + return Vendor; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE uint16 get_family() const noexcept { + return Family; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE uint8 get_model() const noexcept { + return Model; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE uint8 get_stepping() const noexcept { + return Stepping; + } + + [[nodiscard]] inline std::string get_vendor_string() const { + return std::string(VendorID); + } + + [[nodiscard]] inline std::string get_brand_string() const { + return std::string(BrandID); + } + + [[nodiscard]] MPT_CONSTEXPRINLINE bool is_virtual() const noexcept { + return Virtualized; + } + + [[nodiscard]] MPT_CONSTEXPRINLINE bool can_long_mode() const noexcept { +#if !MPT_ARCH_AMD64 + return LongMode; +#else // MPT_ARCH_AMD64 + return true; +#endif // !MPT_ARCH_AMD64 + } + +private: + +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 + + struct cpuid_result { + + uint32 a = 0; + uint32 b = 0; + uint32 c = 0; + uint32 d = 0; + + [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<4> as_text4() const noexcept { + fixed_string<4> result; + result[0 + 0] = static_cast((a >> 0) & 0xff); + result[0 + 1] = static_cast((a >> 8) & 0xff); + result[0 + 2] = static_cast((a >> 16) & 0xff); + result[0 + 3] = static_cast((a >> 24) & 0xff); + return result; + } + + [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<12> as_text12bcd() const noexcept { + fixed_string<12> result; + result[0 + 0] = static_cast((b >> 0) & 0xff); + result[0 + 1] = static_cast((b >> 8) & 0xff); + result[0 + 2] = static_cast((b >> 16) & 0xff); + result[0 + 3] = static_cast((b >> 24) & 0xff); + result[4 + 0] = static_cast((c >> 0) & 0xff); + result[4 + 1] = static_cast((c >> 8) & 0xff); + result[4 + 2] = static_cast((c >> 16) & 0xff); + result[4 + 3] = static_cast((c >> 24) & 0xff); + result[8 + 0] = static_cast((d >> 0) & 0xff); + result[8 + 1] = static_cast((d >> 8) & 0xff); + result[8 + 2] = static_cast((d >> 16) & 0xff); + result[8 + 3] = static_cast((d >> 24) & 0xff); + return result; + } + + [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<12> as_text12bdc() const noexcept { + fixed_string<12> result; + result[0 + 0] = static_cast((b >> 0) & 0xff); + result[0 + 1] = static_cast((b >> 8) & 0xff); + result[0 + 2] = static_cast((b >> 16) & 0xff); + result[0 + 3] = static_cast((b >> 24) & 0xff); + result[4 + 0] = static_cast((d >> 0) & 0xff); + result[4 + 1] = static_cast((d >> 8) & 0xff); + result[4 + 2] = static_cast((d >> 16) & 0xff); + result[4 + 3] = static_cast((d >> 24) & 0xff); + result[8 + 0] = static_cast((c >> 0) & 0xff); + result[8 + 1] = static_cast((c >> 8) & 0xff); + result[8 + 2] = static_cast((c >> 16) & 0xff); + result[8 + 3] = static_cast((c >> 24) & 0xff); + return result; + } + + [[nodiscard]] MPT_CONSTEXPR20_FUN fixed_string<16> as_text16() const noexcept { + fixed_string<16> result; + result[0 + 0] = static_cast((a >> 0) & 0xff); + result[0 + 1] = static_cast((a >> 8) & 0xff); + result[0 + 2] = static_cast((a >> 16) & 0xff); + result[0 + 3] = static_cast((a >> 24) & 0xff); + result[4 + 0] = static_cast((b >> 0) & 0xff); + result[4 + 1] = static_cast((b >> 8) & 0xff); + result[4 + 2] = static_cast((b >> 16) & 0xff); + result[4 + 3] = static_cast((b >> 24) & 0xff); + result[8 + 0] = static_cast((c >> 0) & 0xff); + result[8 + 1] = static_cast((c >> 8) & 0xff); + result[8 + 2] = static_cast((c >> 16) & 0xff); + result[8 + 3] = static_cast((c >> 24) & 0xff); + result[12 + 0] = static_cast((d >> 0) & 0xff); + result[12 + 1] = static_cast((d >> 8) & 0xff); + result[12 + 2] = static_cast((d >> 16) & 0xff); + result[12 + 3] = static_cast((d >> 24) & 0xff); + return result; + } + }; + +#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + [[nodiscard]] static cpuid_result cpuid(uint32 function) noexcept { + +#if MPT_COMPILER_MSVC + + cpuid_result result; + int CPUInfo[4]{}; + __cpuid(CPUInfo, function); + result.a = CPUInfo[0]; + result.b = CPUInfo[1]; + result.c = CPUInfo[2]; + result.d = CPUInfo[3]; + return result; + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + cpuid_result result; + unsigned int regeax{}; + unsigned int regebx{}; + unsigned int regecx{}; + unsigned int regedx{}; + __cpuid(function, regeax, regebx, regecx, regedx); + result.a = regeax; + result.b = regebx; + result.c = regecx; + result.d = regedx; + return result; + +#elif 0 + + cpuid_result result; + unsigned int a{}; + unsigned int b{}; + unsigned int c{}; + unsigned int d{}; + // clang-format off + __asm__ __volatile__ ( + "cpuid \n\t" + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) + : "0" (function)); + // clang-format on + result.a = a; + result.b = b; + result.c = c; + result.d = d; + return result; + +#else // MPT_COMPILER + + return cpuid_result result{}; + +#endif // MPT_COMPILER + } + + [[nodiscard]] static cpuid_result cpuidex(uint32 function_a, uint32 function_c) noexcept { + +#if MPT_COMPILER_MSVC + + cpuid_result result; + int CPUInfo[4]{}; + __cpuidex(CPUInfo, function_a, function_c); + result.a = CPUInfo[0]; + result.b = CPUInfo[1]; + result.c = CPUInfo[2]; + result.d = CPUInfo[3]; + return result; + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + cpuid_result result; + unsigned int regeax{}; + unsigned int regebx{}; + unsigned int regecx{}; + unsigned int regedx{}; + __cpuid_count(function_a, function_c, regeax, regebx, regecx, regedx); + result.a = regeax; + result.b = regebx; + result.c = regecx; + result.d = regedx; + return result; + +#elif 0 + + cpuid_result result; + unsigned int a{}; + unsigned int b{}; + unsigned int c{}; + unsigned int d{}; + // clang-format off + __asm__ __volatile__ ( + "cpuid \n\t" + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) + : "0" (function_a), "2" (function_c)); + // clang-format on + result.a = a; + result.b = b; + result.c = c; + result.d = d; + return result; + +#else // MPT_COMPILER + + return cpuid_result result{}; + +#endif // MPT_COMPILER + } + +#if MPT_MODE_KERNEL + + [[nodiscard]] static uint32 read_cr4() noexcept { + return __readcr4(); + } + +#endif // MPT_MODE_KERNEL + + [[nodiscard]] static uint64 read_xcr(uint32 num) noexcept { + +#if MPT_COMPILER_MSVC + + return _xgetbv(num); + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + uint32 param_ecx = num; + uint32 result_eax = 0; + uint32 result_edx = 0; + // clang-format off + __asm__ __volatile__("xgetbv" : "=a" (result_eax), "=d" (result_edx) : "c" (param_ecx)); + // clang-format on + return static_cast(result_eax) + (static_cast(result_edx) << 32); + +#else + + return _xgetbv(num); + +#endif + } + +#endif // MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + +private: + +#if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT + +#if MPT_OS_DJGPP + + [[nodiscard]] static uint8 detect_cpu_level() noexcept { + +#if 0 + uint8 result = 0; + __dpmi_version_ret dpmi_version{}; + if (__dpmi_get_version(&dpmi_version) == 0) { + result = dpmi_version.cpu; + } + return result; +#else + uint8 result = 0; + __dpmi_regs regs{}; + regs.x.ax = 0x0400; + if (__dpmi_int(0x31, ®s) == 0) { + unsigned int cf = (regs.x.flags >> 0) & 1u; + if (cf == 0) { + result = regs.h.cl; + } + } + return result; +#endif + } + +#endif // MPT_OS_DJGPP + + [[nodiscard]] static uint8 detect_fpu_level() noexcept { + +#if MPT_OS_DJGPP + +#if 1 + uint8 result = 0; + int coprocessor_status = __dpmi_get_coprocessor_status(); + if (coprocessor_status == -1) { + // error = __dpmi_error + return 0; + } + result = (static_cast(coprocessor_status) & 0x00f0u) >> 4; + return result; +#else + uint8 result = 0; + __dpmi_regs regs{}; + regs.x.ax = 0x0e00; + if (__dpmi_int(0x31, ®s) == 0) { + unsigned int cf = (regs.x.flags >> 0) & 1u; + if (cf == 0) { + result = (regs.x.ax & 0x00f0u) >> 4; + } + } + return result; +#endif + +#elif MPT_OS_WINDOWS + + uint8 result = 0; +#if MPT_WINNT_AT_LEAST(MPT_WIN_NT4) + if (mpt::osinfo::windows::Version::Current().IsAtLeast(mpt::osinfo::windows::Version::Win2000)) { + if (IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED) == 0) { + result = 3; + } + } else { + // logic is inverted on NT4 + if (IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED) != 0) { + result = 3; + } + } +#else + if ((assumed_features() & feature::fpu) && (assumed_features() & feature::fsin)) { + result = 3; + } else if (assumed_features() & feature::fpu) { + result = 2; + } else { + result = 0; + } +#endif + return result; + +#elif MPT_COMPILER_MSVC && MPT_MODE_KERNEL + + uint8 result = 0; + const std::size_t cr0 = __readcr0(); + if (!(cr0 & (1u << 2))) { // EM + result = 2; + if (cr0 & (1u << 4)) { // ET + result = 3; + } + } + return result; + +#else + + uint8 result = 0; + if ((assumed_features() & feature::fpu) && (assumed_features() & feature::fsin)) { + result = 3; + } else if (assumed_features() & feature::fpu) { + result = 2; + } else { + result = 0; + } + return result; + +#endif + } + +#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + [[nodiscard]] static bool can_toggle_eflags(std::size_t mask) noexcept { + std::size_t eflags_old = __readeflags(); + std::size_t eflags_flipped = eflags_old ^ mask; + __writeeflags(eflags_flipped); + std::size_t eflags_testchanged = __readeflags(); + __writeeflags(eflags_old); + return ((eflags_testchanged ^ eflags_old) & mask) == mask; + } + +#endif + + [[nodiscard]] static bool can_toggle_eflags_ac() noexcept { +#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + return can_toggle_eflags(0x0004'0000); +#else // MPT_COMPILER + return (assumed_features() & feature::intel486) != 0; +#endif // MPT_COMPILER + } + + [[nodiscard]] static bool can_toggle_eflags_id() noexcept { +#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + return can_toggle_eflags(0x0020'0000); +#else // MPT_COMPILER + return (assumed_features() & feature::tsc) != 0; +#endif // MPT_COMPILER + } + + [[nodiscard]] static bool detect_nexgen() noexcept { + +#if MPT_ARCH_X86 && MPT_COMPILER_MSVC + + uint8 result = 0; + // clang-format off + _asm { + mov eax, 0x5555 + xor edx, edx + mov ecx, 2 + clc + div ecx + jz found + jmp done + found: + mov result, 1 + jmp done + done: + } + // clang-format on + return (result != 0); + +#elif MPT_ARCH_X86 && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) + + unsigned int result = 0; + // clang-format off + __asm__ __volatile( + "movl $0x5555, %%eax\n" + "xorl %%edx, %%edx\n" + "movl $2, %%ecx\n" + "clc\n" + "divl %%ecx\n" + "jz detect_nexgen_found\n" + "movl $0, %%eax\n" + "jmp detect_nexgen_done\n" + "detect_nexgen_found:\n" + "movl $0, %%eax\n" + "jmp detect_nexgen_done\n" + "detect_nexgen_done:\n" + : "=a" (result) + : + : "%ebx", "%ecx" + ); + // clang-format on + return (result != 0); + +#else + + // assume false + return false; + +#endif + } + + [[nodiscard]] static bool detect_cyrix() noexcept { + +#if MPT_ARCH_X86 && MPT_COMPILER_MSVC + + uint8 result = 0; + // clang-format off + _asm { + xor ax, ax + sahf + mov ax, 5 + mov bx, 2 + div bl + lahf + cmp ah, 2 + jne not_cyrix + mov result, 1 + not_cyrix: + } + // clang-format on + return (result != 0); + +#elif MPT_ARCH_X86 && (MPT_COMPILER_GCC || MPT_COMPILER_CLANG) + + unsigned int result = 0; + // clang-format off + __asm__ __volatile( + "xor %%ax, %%ax\n" + "sahf\n" + "movw $5, %%ax\n" + "movw $2, %%bx\n" + "divb %%bl\n" + "lahf\n" + "cmpb $2, %%ah\n" + "jne detect_cyrix_done_not_cyrix\n" + "movl $1, %%eax\n" + "jmp detect_cyrix_done\n" + "detect_cyrix_done_not_cyrix:\n" + "movl $0, %%eax\n" + "jmp detect_cyrix_done\n" + "detect_cyrix_done:\n" + : "=a" (result) + : + : "%ebx" + ); + // clang-format on + return (result != 0); + +#else + + // assume false + return false; + +#endif + } + + [[nodiscard]] static uint16 read_cyrix_id() noexcept { + +#if MPT_OS_DJGPP + + uint16 result = 0; + outportb(0x22, 0x00); + result |= static_cast(inportb(0x23)) << 8; + outportb(0x22, 0x01); + result |= static_cast(inportb(0x23)) << 0; + outportb(0x22, 0x00); + inportb(0x23); + return result; + +#elif MPT_COMPILER_MSVC && MPT_MODE_KERNEL + + uint16 result = 0; + __outbyte(0x22, 0x00); + result |= static_cast(__inbyte(0x23)) << 8; + __outbyte(0x22, 0x01); + result |= static_cast(__inbyte(0x23)) << 0; + __outbyte(0x22, 0x00); + __inbyte(0x23); + return result; + +#else + + return 0x00'00; + +#endif + } + +#endif // MPT_ARCH_X86 + +#endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 + +public: + + cpu_info() noexcept { + +#if MPT_ARCH_X86 || MPT_ARCH_AMD64 + +#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG + +#if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT + + Features |= featureset::intel386; + + if (can_toggle_eflags_ac()) { + Features |= feature::intel486; + } + if (can_toggle_eflags_id()) { + Features |= feature::cpuid; + } + if (!Features.supports(feature::cpuid)) { + // without cpuid + if (!Features.supports(feature::intel486)) { + // 386 + const uint8 fpu_level = detect_fpu_level(); + if (fpu_level >= 2) { + Features |= feature::fpu; + } + if (fpu_level >= 3) { + Features |= feature::fsin; + } + if (detect_nexgen()) { + Vendor = vendor::NexGen; + } else { + Vendor = vendor::unknown; + } + } else { + // 486+ + const uint8 fpu_level = detect_fpu_level(); + if (fpu_level >= 2) { + Features |= feature::fpu; + } + if (fpu_level >= 3) { + Features |= feature::fsin; + } + if (detect_cyrix()) { + Vendor = vendor::Cyrix; + uint16 id = read_cyrix_id(); + if (id <= 0x07'00) { + // Cx486SLC / Cx486DLC + Family = 3; + Model = static_cast((id & 0xff'00) >> 8); + Stepping = static_cast(id & 0x00'ff); + } else if ((0x10'00 <= id) && (id <= 0x13'00)) { + // Cx486S + Family = 4; + Model = static_cast((id & 0xff'00) >> 8); + Stepping = static_cast(id & 0x00'ff); + } else if ((0x1a'00 <= id) && (id <= 0x1f'00)) { + // Cx486DX + Family = 4; + Model = static_cast((id & 0xff'00) >> 8); + Stepping = static_cast(id & 0x00'ff); + } else if ((0x28'00 <= id) && (id <= 0x2e'00)) { + // Cx5x86 + Family = 4; + Model = static_cast((id & 0xff'00) >> 8); + Stepping = static_cast(id & 0x00'ff); + } else if ((0x40'00 <= id) && (id <= 0x4f'00)) { + // MediaGx / MediaGXm + Family = 4; + Model = 4; + Stepping = static_cast(id & 0x00'ff); + } else if ((0x30'00 <= id) && (id <= 0x34'00)) { + // Cx6x86 / Cx6x86L + Family = 5; + Model = 2; + Stepping = static_cast(id & 0x00'ff); + if ((id & 0x00'ff) > 0x21) { + // Cx6x86L + Features |= feature::cx8; + } + } else if ((0x50'00 <= id) && (id <= 0x5f'00)) { + // Cx6x86MX + Family = 6; + Model = 0; + Stepping = static_cast(id & 0x00'ff); + Features |= feature::cx8; + Features |= feature::tsc; + Features |= feature::mmx; + Features |= feature::cmov; + } + } else { + Vendor = vendor::unknown; + } + } + } + +#elif MPT_ARCH_AMD64 + + Features |= featureset::amd64; + Modes |= modeset::amd64; + +#endif // MPT_ARCH + + bool have_osxsave = false; + + if (Features.supports(feature::cpuid)) { + // with cpuid + cpuid_result VendorString = cpuid(0x0000'0000u); + VendorID = VendorString.as_text12bdc(); + if (VendorID == std::string_view(" ")) { + Vendor = vendor::unknown; + } else if (VendorID == std::string_view("AMDisbetter!")) { + Vendor = vendor::AMD; + } else if (VendorID == std::string_view("AuthenticAMD")) { + Vendor = vendor::AMD; + } else if (VendorID == std::string_view("CentaurHauls")) { + Vendor = vendor::Centaur; + } else if (VendorID == std::string_view("CyrixInstead")) { + Vendor = vendor::Cyrix; + } else if (VendorID == std::string_view("GenuineIntel")) { + Vendor = vendor::Intel; + } else if (VendorID == std::string_view("TransmetaCPU")) { + Vendor = vendor::Transmeta; + } else if (VendorID == std::string_view("GenuineTMx86")) { + Vendor = vendor::Transmeta; + } else if (VendorID == std::string_view("Geode by NSC")) { + Vendor = vendor::NSC; + } else if (VendorID == std::string_view("NexGenDriven")) { + Vendor = vendor::NexGen; + } else if (VendorID == std::string_view("RiseRiseRise")) { + Vendor = vendor::Rise; + } else if (VendorID == std::string_view("SiS SiS SiS ")) { + Vendor = vendor::SiS; + } else if (VendorID == std::string_view("UMC UMC UMC ")) { + Vendor = vendor::UMC; + } else if (VendorID == std::string_view("VIA VIA VIA ")) { + Vendor = vendor::VIA; + } else if (VendorID == std::string_view("Vortex86 SoC")) { + Vendor = vendor::DMnP; + } else if (VendorID == std::string_view(" Shanghai ")) { + Vendor = vendor::Zhaoxin; + } else if (VendorID == std::string_view("HygonGenuine")) { + Vendor = vendor::Hygon; + } else if (VendorID == std::string_view("E2K MACHINE")) { + Vendor = vendor::Elbrus; + } else if (VendorID == std::string_view("MiSTer AO486")) { + Vendor = vendor::MiSTer; + } else if (VendorID == std::string_view("bhyve bhyve ")) { + Vendor = vendor::bhyve; + } else if (VendorID == std::string_view(" KVMKVMKVM ")) { + Vendor = vendor::KVM; + } else if (VendorID == std::string_view("TCGTCGTCGTCG")) { + Vendor = vendor::QEMU; + } else if (VendorID == std::string_view("Microsoft Hv")) { + Vendor = vendor::HyperV; + } else if (VendorID == std::string_view(" lrpepyh vr")) { + Vendor = vendor::Parallels; + } else if (VendorID == std::string_view("VMwareVMware")) { + Vendor = vendor::VMWare; + } else if (VendorID == std::string_view("XenVMMXenVMM")) { + Vendor = vendor::Xen; + } else if (VendorID == std::string_view("ACRNACRNACRN")) { + Vendor = vendor::ACRN; + } else if (VendorID == std::string_view(" QNXQVMBSQG ")) { + Vendor = vendor::QNX; + } + // Cyrix 6x86 and 6x86MX do not specify the value returned in eax. + // They both support 0x00000001u however. + if ((VendorString.a >= 0x0000'0001u) || (Vendor == vendor::Cyrix)) { + cpuid_result StandardFeatureFlags = cpuid(0x0000'0001u); + CPUID = StandardFeatureFlags.a; + // clang-format off + uint32 BaseStepping = (StandardFeatureFlags.a >> 0) & 0x0f; + uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f; + uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f; + uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f; + uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff; + // clang-format on + if (BaseFamily == 0xf) { + Family = static_cast(ExtFamily + BaseFamily); + } else { + Family = static_cast(BaseFamily); + } + if ((Vendor == vendor::AMD) && (BaseFamily == 0xf)) { + Model = static_cast((ExtModel << 4) | (BaseModel << 0)); + } else if ((Vendor == vendor::Centaur) && (BaseFamily >= 0x6)) { + // Newer Zhaoxin CPUs use extended family also with BaseFamily=7. + Model = static_cast((ExtModel << 4) | (BaseModel << 0)); + } else if ((BaseFamily == 0x6) || (BaseFamily == 0xf)) { + Model = static_cast((ExtModel << 4) | (BaseModel << 0)); + } else { + Model = static_cast(BaseModel); + } + Stepping = static_cast(BaseStepping); + // clang-format off + Features |= (StandardFeatureFlags.d & (1u << 0)) ? (feature::fpu | feature::fsin) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 4)) ? (feature::tsc) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 8)) ? (feature::cx8) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 15)) ? (feature::cmov) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 23)) ? (feature::mmx) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 24)) ? (feature::fxsr) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 25)) ? (feature::sse | feature::x3dnowprefetch) : feature::none; + Features |= (StandardFeatureFlags.d & (1u << 26)) ? (feature::sse2) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 0)) ? (feature::sse3) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 9)) ? (feature::ssse3) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 12)) ? (feature::fma) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 13)) ? (feature::cx16) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 19)) ? (feature::sse4_1) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 20)) ? (feature::sse4_2) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 22)) ? (feature::movbe) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 23)) ? (feature::popcnt) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 26)) ? (feature::xsave) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 28)) ? (feature::avx) : feature::none; + Features |= (StandardFeatureFlags.c & (1u << 29)) ? (feature::f16c) : feature::none; + // clang-format on + if (StandardFeatureFlags.c & (1u << 27)) { + have_osxsave = true; + } + if (StandardFeatureFlags.c & (1u << 31)) { + Virtualized = true; + } + } + if (VendorString.a >= 0x0000'0007u) { + cpuid_result ExtendedFeatures = cpuidex(0x0000'0007u, 0x0000'0000u); + // clang-format off + Features |= (ExtendedFeatures.b & (1u << 3)) ? (feature::bmi1) : feature::none; + Features |= (ExtendedFeatures.b & (1u << 5)) ? (feature::avx2) : feature::none; + Features |= (ExtendedFeatures.b & (1u << 8)) ? (feature::bmi2) : feature::none; + // clang-format on + } + // 3DNow! manual recommends to just execute 0x8000'0000u. + // It is totally unknown how earlier CPUs from other vendors + // would behave. + // Thus we only execute 0x80000000u on other vendors CPUs for the earliest + // that we found it documented for and that actually supports 3DNow!. + bool ecpuid = false; + bool x3dnowknown = false; + if (Vendor == vendor::Intel) { + ecpuid = true; + } else if (Vendor == vendor::AMD) { + if ((Family > 5) || ((Family == 5) && (Model >= 8))) { + // >= K6-2 (K6 = Family 5, K6-2 = Model 8) + // Not sure if earlier AMD CPUs support 0x80000000u. + // AMD 5k86 and AMD K5 manuals do not mention it. + ecpuid = true; + x3dnowknown = true; + } + } else if (Vendor == vendor::Centaur) { + // Centaur (IDT WinChip or VIA C3) + if (Family == 5) { + // IDT + if (Model >= 8) { + // >= WinChip 2 + ecpuid = true; + x3dnowknown = true; + } + } else if (Family >= 6) { + // VIA + if ((Family >= 7) || ((Family == 6) && (Model >= 7))) { + // >= C3 Samuel 2 + ecpuid = true; + x3dnowknown = true; + } + } + } else if (Vendor == vendor::Cyrix) { + // Cyrix + // 6x86 : 5.2.x + // 6x86L : 5.2.x + // MediaGX : 4.4.x + // 6x86MX : 6.0.x + // MII : 6.0.x + // MediaGXm: 5.4.x + // well, doh ... + if ((Family == 5) && (Model >= 4)) { + // Cyrix MediaGXm + ecpuid = true; + x3dnowknown = true; + } + } else if (Vendor == vendor::NSC) { + // National Semiconductor + if ((Family > 5) || ((Family == 5) && (Model >= 5))) { + // >= Geode GX2 + ecpuid = true; + x3dnowknown = true; + } + } else { + // Intel specification allows 0x8000'0000u on earlier CPUs, + // thus we execute it on unknown vendors. + ecpuid = true; + } + if (ecpuid) { + cpuid_result ExtendedVendorString = cpuid(0x8000'0000u); + if ((ExtendedVendorString.a & 0xffff'0000u) == 0x8000'0000u) { + if (ExtendedVendorString.a >= 0x8000'0001u) { + // clang-format off + cpuid_result ExtendedFeatureFlags = cpuid(0x8000'0001u); +#if !MPT_ARCH_AMD64 + if (ExtendedFeatureFlags.d & (1u << 29)) { + LongMode = true; + } +#endif // !MPT_ARCH_AMD64 + Features |= (ExtendedFeatureFlags.c & (1u << 0)) ? (feature::lahf) : feature::none; + Features |= (ExtendedFeatureFlags.c & (1u << 5)) ? (feature::lzcnt) : feature::none; + if (x3dnowknown) { + Features |= (ExtendedFeatureFlags.d & (1u << 31)) ? (feature::x3dnow) : feature::none; + } + if (Vendor == vendor::AMD) { + Features |= (ExtendedFeatureFlags.d & (1u << 22)) ? (feature::mmxext) : feature::none; + Features |= (ExtendedFeatureFlags.d & (1u << 30)) ? (feature::x3dnowext) : feature::none; + Features |= (ExtendedFeatureFlags.c & (1u << 5)) ? (feature::popcnt) : feature::none; + Features |= (ExtendedFeatureFlags.c & (1u << 8)) ? (feature::x3dnowprefetch) : feature::none; + } + // clang-format on + } + if (ExtendedVendorString.a >= 0x8000'0004u) { + BrandID = cpuid(0x8000'0002u).as_text16() + cpuid(0x8000'0003u).as_text16() + cpuid(0x8000'0004u).as_text16(); + } + } + } + +#if MPT_ARCH_AMD64 + + // clang-format off + Modes |= mode::xmm128sse; + const bool have_xsave = +#ifdef MPT_ARCH_X86_XSAVE + true; +#else + Features.supports(feature::xsave); +#endif + MPT_MAYBE_CONSTANT_IF (have_xsave && have_osxsave) { + const uint64 xcr0 = read_xcr(0x0000'0000u); + Modes |= (xcr0 & (1ull << 2)) ? mode::ymm256avx : mode::base; + } + // clang-format on + +#else // !MPT_ARCH_AMD64 + + // clang-format off + const bool have_xsave = +#ifdef MPT_ARCH_X86_XSAVE + true; +#else + Features.supports(feature::xsave); +#endif + MPT_MAYBE_CONSTANT_IF (have_xsave && have_osxsave) { + const uint64 xcr0 = read_xcr(0x0000'0000u); + Modes |= (xcr0 & (1ull << 1)) ? mode::xmm128sse : mode::base; + Modes |= (xcr0 & (1ull << 2)) ? mode::ymm256avx : mode::base; + } else { + const bool have_fxsr = +#ifdef MPT_ARCH_X86_FXSR + true; +#else + Features.supports(feature::fxsr); +#endif + MPT_MAYBE_CONSTANT_IF (have_fxsr) { +#if MPT_MODE_KERNEL + const uint32 cr4 = read_cr4(); + Modes |= (cr4 & (1u << 9)) ? mode::xmm128sse : mode::base; +#else // !MPT_MODE_KERNEL + // There is no way for user-mode code to check for SSE enabled in CR4. + // Assume based on FXSR and SSE and platform heuristics. + // Avoid assumption on DOS. +#if MPT_OS_WINDOWS + // get from platform API +#if MPT_OS_WINDOWS_WINNT +#ifdef PF_XMMI_INSTRUCTIONS_AVAILABLE + Modes |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; +#endif +#elif MPT_WIN9X_AT_LEAST(MPT_WIN_WIN98) + const bool have_sse = +#ifdef MPT_ARCH_X86_SSE + true; +#else + Features.supports(feature::sse); +#endif + MPT_MAYBE_CONSTANT_IF (have_sse) { + Modes |= mode::xmm128sse; + } +#else // MPT_OS_WINDOWS + // nothing +#endif // MPT_OS_WINDOWS +#elif MPT_OS_DJGPP || MPT_OS_UNKNOWN + // avoid SSE on DOS and unknown systems, + // however if we directly targeting >= SSE, then assume it's activated because the process will crash otherwise anyway +#ifdef MPT_ARCH_X86_SSE + Modes |= mode::xmm128sse; +#endif +#else // MPT_OS + // assume based on FXSR and SSE + const bool have_sse = +#ifdef MPT_ARCH_X86_SSE + true; +#else + Features.supports(feature::sse); +#endif + MPT_MAYBE_CONSTANT_IF (have_sse) { + Modes |= mode::xmm128sse; + } +#endif // MPT_OS +#endif // MPT_MODE_KERNEL + } + } + // clang-format on + +#endif // MPT_ARCH_AMD64 + + if (Virtualized) { + cpuid_result HypervisorVendorID = cpuid(0x4000'0000u); + if (HypervisorVendorID.a >= 0x4000'0000u) { + HypervisorVendor = HypervisorVendorID.as_text12bcd(); + if (HypervisorVendor == std::string_view("Microsoft Hv")) { + if (HypervisorVendorID.a >= 0x4000'0001u) { + cpuid_result HypervisorInterfaceID = cpuid(0x4000'0001u); + HypervisorInterface = HypervisorInterfaceID.as_text4(); + } + } else if (HypervisorVendor == std::string_view("KVMKVMKVM")) { + // nothing + } + } + } + } + +#elif MPT_OS_WINDOWS + +#if MPT_ARCH_X86 || !MPT_ARCH_X86_AMD64_FAST_DETECT + + SYSTEM_INFO si = {}; + GetSystemInfo(&si); + switch (si.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + case PROCESSOR_ARCHITECTURE_AMD64: + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: + switch (si.dwProcessorType) { + case PROCESSOR_INTEL_386: + Family = si.wProcessorLevel; + if (((si.wProcessorRevision & 0xff00) >> 8) == 0xff) { + Model = ((si.wProcessorRevision & 0x00f0) >> 4) - 0xa; + Stepping = ((si.wProcessorRevision & 0x000f) >> 0); + } else { + Model = ((si.wProcessorRevision & 0xff00) >> 8) + static_cast('A'); + Stepping = ((si.wProcessorRevision & 0x00ff) >> 0); + } + Model = (si.wProcessorRevision & 0xff00) >> 8; + Stepping = (si.wProcessorRevision & 0x00ff) >> 0; + Features |= featureset::intel386; + break; + case PROCESSOR_INTEL_486: + Family = si.wProcessorLevel; + if (((si.wProcessorRevision & 0xff00) >> 8) == 0xff) { + Model = ((si.wProcessorRevision & 0x00f0) >> 4) - 0xa; + Stepping = ((si.wProcessorRevision & 0x000f) >> 0); + } else { + Model = ((si.wProcessorRevision & 0xff00) >> 8) + static_cast('A'); + Stepping = ((si.wProcessorRevision & 0x00ff) >> 0); + } + Model = (si.wProcessorRevision & 0xff00) >> 8; + Stepping = (si.wProcessorRevision & 0x00ff) >> 0; + Features |= featureset::intel486SX; + break; + case PROCESSOR_INTEL_PENTIUM: + Family = si.wProcessorLevel; + Model = (si.wProcessorRevision & 0xff00) >> 8; + Stepping = (si.wProcessorRevision & 0x00ff) >> 0; + // rely on IsProcessorFeaturePresent() for > 486 features + // Features |= featureset::intel586; + Features |= featureset::intel486SX; + break; + } + break; + } + Features |= featureset::intel386; + const uint8 fpu_level = detect_fpu_level(); + if (fpu_level >= 2) { + Features |= feature::fpu; + } + if (fpu_level >= 3) { + Features |= feature::fsin; + } + +#elif MPT_ARCH_AMD64 + + Features |= featureset::amd64; + +#endif // MPT_ARCH + +#if MPT_OS_WINDOWS_WINNT + // clang-format off + Features |= (IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE) != 0) ? (feature::tsc | feature::intel486) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_COMPARE_EXCHANGE_DOUBLE) != 0) ? (feature::cx8 | feature::intel486) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::mmx | feature::intel486) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::x3dnow) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse | feature::fxsr | feature::x3dnowprefetch | feature::cmov) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse2) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse3) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::ssse3) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse4_1) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::sse4_1) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_AVX_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::avx | feature::xsave) : feature::none; + Features |= (IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE) != 0) ? (feature::avx2 | feature::fma | feature::bmi1) : feature::none; + Modes |= (IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_AVX_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse | mode::ymm256avx) : mode::base; + Modes |= (IsProcessorFeaturePresent(PF_AVX2_INSTRUCTIONS_AVAILABLE) != 0) ? (mode::xmm128sse | mode::ymm256avx) : mode::base; + // clang-format on +#endif + +#elif MPT_OS_DJGPP + + const uint8 cpu_level = detect_cpu_level(); + Features |= (cpu_level >= 3) ? featureset::intel386 : feature::none; + Features |= (cpu_level >= 4) ? featureset::intel486SX : feature::none; + const uint8 fpu_level = detect_fpu_level(); + Features |= (fpu_level >= 2) ? feature::fpu : feature::none; + Features |= (fpu_level >= 3) ? feature::fsin : feature::none; + +#endif + +#endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 + } +}; + + + +struct floating_point { + +public: + + static inline constexpr uint16 FCW_IM = (1 << 0); + static inline constexpr uint16 FCW_DM = (1 << 1); + static inline constexpr uint16 FCW_ZM = (1 << 2); + static inline constexpr uint16 FCW_OM = (1 << 3); + static inline constexpr uint16 FCW_UM = (1 << 4); + static inline constexpr uint16 FCW_PM = (1 << 5); + static inline constexpr uint16 FCW_PC = 0x0300; + static inline constexpr uint16 FCW_RC = 0x0c00; + static inline constexpr uint16 FCW_X = (1 << 12); + + static inline constexpr uint32 MXCSR_IE = (1 << 0); + static inline constexpr uint32 MXCSR_DE = (1 << 1); + static inline constexpr uint32 MXCSR_ZE = (1 << 2); + static inline constexpr uint32 MXCSR_OE = (1 << 3); + static inline constexpr uint32 MXCSR_UE = (1 << 4); + static inline constexpr uint32 MXCSR_PE = (1 << 5); + static inline constexpr uint32 MXCSR_DAZ = (1 << 6); + static inline constexpr uint32 MXCSR_IM = (1 << 7); + static inline constexpr uint32 MXCSR_DM = (1 << 8); + static inline constexpr uint32 MXCSR_ZM = (1 << 9); + static inline constexpr uint32 MXCSR_OM = (1 << 10); + static inline constexpr uint32 MXCSR_UM = (1 << 11); + static inline constexpr uint32 MXCSR_PM = (1 << 12); + static inline constexpr uint32 MXCSR_RC = (1 << 13) | (1 << 14); + static inline constexpr uint32 MXCSR_FTZ = (1 << 15); + + enum class precision : uint8 { + single24 = 0, + reserved = 1, + double53 = 2, + extended64 = 3, + }; + + enum class rounding : uint8 { + nearest = 0, + down = 1, + up = 2, + zero = 3, + }; + + struct alignas(16) fxsave_state { + uint16 fcw; + uint16 fsw; + uint16 ftw; + uint16 fop; + uint32 fip; + uint32 fcs; + uint32 foo; + uint32 fos; + uint32 mxcsr; + uint32 mxcsr_mask; + uint32 st_space[32]; + uint32 xmm_space[32]; + uint8 padding[224]; + }; + static_assert(sizeof(fxsave_state) == 512); + + struct control_state { + uint8 x87_level = 0; + uint16 x87fcw = 0; // default 0x37f (glibc) / 0x27f (msvc) + uint32 mxcsr_mask = 0; + uint32 mxcsr = 0; // default: 0x00001f80 + }; + +#if MPT_ARCH_X86 + +#if MPT_COMPILER_MSVC + + [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { + uint16 tmp = 0; + // clang-format off + _asm { + fwait + fnstcw tmp + } + // clang-format on + return tmp; + } + + static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { + // clang-format off + _asm { + fldcw fcw + } + // clang-format on + } + + [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { + return _mm_getcsr(); + } + + static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { + _mm_setcsr(csr); + } + + static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { + _fxsave(state); + } + + static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { + _fxrstor(state); + } + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { + typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); + fpu_control_t tmp = 0; + // clang-format off + __asm__ __volatile__("fwait" "\n" "fnstcw %0" : "=m" (*&tmp)); + // clang-format on + return static_cast(tmp); + } + + static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { + typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); + fpu_control_t tmp = fcw; + // clang-format off + __asm__ __volatile__("fldcw %0" : : "m" (*&tmp)); + // clang-format on + } + + [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { +#ifdef MPT_ARCH_X86_SSE + return __builtin_ia32_stmxcsr(); +#else + uint32 csr = 0; + // clang-format off + __asm__ __volatile__("stmxcsr %0" : "=m" (csr)); + // clang-format on + return csr; +#endif + } + + static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { +#ifdef MPT_ARCH_X86_SSE +#if MPT_COMPILER_GCC + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif + __builtin_ia32_ldmxcsr(csr); +#if MPT_COMPILER_GCC + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif +#else + // clang-format off + __asm__ __volatile__("ldmxcsr %0" : : "m" (csr)); + // clang-format on +#endif + } + + static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { +#ifdef MPT_ARCH_X86_FXSR + __builtin_ia32_fxsave(state); +#else + // clang-format off + __asm__ __volatile__("fxsave %0" : : "m" (*state)); + // clang-format on +#endif + } + + static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { +#ifdef MPT_ARCH_X86_FXSR + __builtin_ia32_fxrstor(const_cast(state)); +#else + // clang-format off + __asm__ __volatile__("fxrstor %0" : : "m" (*state)); + // clang-format on +#endif + } + +#endif // MPT_COMPILER + + static MPT_FORCEINLINE bool have_fxsr() noexcept { +#ifdef MPT_ARCH_X86_FXSR + return true; +#else + return cpu_info{}[mpt::arch::x86::feature::fxsr]; +#endif + } + + static MPT_FORCEINLINE bool have_sse() noexcept { +#ifdef MPT_ARCH_X86_SSE + return true; +#else + const cpu_info cpu_info; + return cpu_info[mpt::arch::x86::feature::sse] && cpu_info[mpt::arch::x86::mode::xmm128sse]; +#endif + } + + static MPT_FORCEINLINE uint8 get_fpu_level() noexcept { +#ifdef MPT_ARCH_X86_FSIN + return 3; +#elif defined(MPT_ARCH_X86_FPU) + return cpu_info{}[mpt::arch::x86::feature::fsin] ? 3 : 2; +#else + cpu_info tmp{}; + return tmp[mpt::arch::x86::feature::fsin] ? 3 : tmp[mpt::arch::x86::feature::fpu] ? 2 + : 0; +#endif + } + + static MPT_FORCEINLINE control_state get_state() noexcept { + control_state result; +#ifdef MPT_ARCH_X86_FXSR + fxsave_state tmp = {}; + fxsave(&tmp); + result.x87_level = 3; + result.x87fcw = tmp.fcw; + result.mxcsr_mask = tmp.mxcsr_mask; + result.mxcsr = tmp.mxcsr; +#else + if (have_fxsr()) { + fxsave_state tmp = {}; + fxsave(&tmp); + result.x87_level = 3; + result.x87fcw = tmp.fcw; + result.mxcsr_mask = tmp.mxcsr_mask; + result.mxcsr = tmp.mxcsr; + } else { + result.x87_level = get_fpu_level(); + if (result.x87_level > 0) { + result.x87fcw = get_x87fcw(); + } + } +#endif + return result; + } + + static MPT_FORCEINLINE void set_state(control_state state) noexcept { +#ifdef MPT_ARCH_X86_SSE + if (state.x87_level) { + set_x87fcw(state.x87fcw); + } + if (state.mxcsr_mask) { + set_mxcsr(state.mxcsr); + } +#else + if (have_sse()) { + if (state.x87_level) { + set_x87fcw(state.x87fcw); + } + if (state.mxcsr_mask) { + set_mxcsr(state.mxcsr); + } + } else { +#ifdef MPT_ARCH_X86_FXSR + fxsave_state tmp = {}; + fxsave(&tmp); + if (state.x87_level) { + tmp.fcw = state.x87fcw; + } + if (state.mxcsr_mask) { + tmp.mxcsr = state.mxcsr; + } + fxrstor(&tmp); +#else + if (have_fxsr()) { + fxsave_state tmp = {}; + fxsave(&tmp); + if (state.x87_level) { + tmp.fcw = state.x87fcw; + } + if (state.mxcsr_mask) { + tmp.mxcsr = state.mxcsr; + } + fxrstor(&tmp); + } else { + if (state.x87_level) { + set_x87fcw(state.x87fcw); + } + } +#endif + } +#endif + } + +#elif MPT_ARCH_AMD64 + +#if MPT_COMPILER_MSVC + + [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { + fxsave_state state = {}; + fxsave(&state); + return state.fcw; + } + + static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { + fxsave_state state = {}; + fxsave(&state); + state.fcw = fcw; + fxrstor(&state); + } + + [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { + return _mm_getcsr(); + } + + static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { + _mm_setcsr(csr); + } + + static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { + _fxsave(state); + } + + static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { + _fxrstor(state); + } + + static MPT_FORCEINLINE bool have_fxsr() noexcept { + return true; + } + + static MPT_FORCEINLINE control_state get_state() noexcept { + control_state result; + fxsave_state tmp = {}; + fxsave(&tmp); + result.x87_level = 3; + result.x87fcw = tmp.fcw; + result.mxcsr_mask = tmp.mxcsr_mask; + result.mxcsr = tmp.mxcsr; + return result; + } + + static MPT_FORCEINLINE void set_state(control_state state) noexcept { + fxsave_state tmp = {}; + fxsave(&tmp); + tmp.fcw = state.x87fcw; + tmp.mxcsr_mask = state.mxcsr_mask; + tmp.mxcsr = state.mxcsr; + fxrstor(&tmp); + } + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + [[nodiscard]] static MPT_FORCEINLINE uint16 get_x87fcw() noexcept { + typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); + fpu_control_t tmp = 0; + // clang-format off + __asm__ __volatile__("fwait" "\n" "fnstcw %0" : "=m" (*&tmp)); + // clang-format on + return static_cast(tmp); + } + + static MPT_FORCEINLINE void set_x87fcw(uint16 fcw) noexcept { + typedef unsigned int fpu_control_t __attribute__((__mode__(__HI__))); + fpu_control_t tmp = fcw; + // clang-format off + __asm__ __volatile__("fldcw %0" : : "m" (*&tmp)); + // clang-format on + } + + [[nodiscard]] static MPT_FORCEINLINE uint32 get_mxcsr() noexcept { + return __builtin_ia32_stmxcsr(); + } + + static MPT_FORCEINLINE void set_mxcsr(uint32 csr) noexcept { +#if MPT_COMPILER_GCC + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif + __builtin_ia32_ldmxcsr(csr); +#if MPT_COMPILER_GCC + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55752 + std::atomic_thread_fence(std::memory_order_seq_cst); +#endif + } + + static MPT_FORCEINLINE void fxsave(fxsave_state * state) noexcept { + __builtin_ia32_fxsave(state); + } + + static MPT_FORCEINLINE void fxrstor(const fxsave_state * state) noexcept { + __builtin_ia32_fxrstor(const_cast(state)); + } + + static MPT_FORCEINLINE bool have_fxsr() noexcept { + return true; + } + + static MPT_FORCEINLINE control_state get_state() noexcept { + control_state result; + result.x87_level = 3; + result.x87fcw = get_x87fcw(); + result.mxcsr_mask = 0x0000'ffff; + result.mxcsr = get_mxcsr(); + return result; + } + + static MPT_FORCEINLINE void set_state(control_state state) noexcept { + set_x87fcw(state.x87fcw); + set_mxcsr(state.mxcsr); + } + +#endif // MPT_COMPILER + + class guard { + + private: + + const control_state m_oldstate; + + public: + + MPT_FORCEINLINE guard(std::optional rounding, std::optional denormals_as_zero, std::optional precision, std::optional infinity_projective) noexcept + : m_oldstate(get_state()) { + control_state state = m_oldstate; + if (rounding) { + if (state.x87_level) { + state.x87fcw = (state.x87fcw & ~FCW_RC) | (mpt::to_underlying(*rounding) << mpt::countr_zero(FCW_RC)); + } + if ((state.mxcsr_mask & MXCSR_RC) == MXCSR_RC) { + state.mxcsr = (state.mxcsr & ~MXCSR_RC) | (mpt::to_underlying(*rounding) << mpt::countr_zero(MXCSR_RC)); + } + } + if (denormals_as_zero) { + if (state.mxcsr_mask) { + state.mxcsr = (state.mxcsr & ~(MXCSR_FTZ | MXCSR_DAZ)) | ((*denormals_as_zero) ? ((MXCSR_FTZ | MXCSR_DAZ) & state.mxcsr_mask) : 0); + } + } + if (precision) { + if (state.x87_level) { + state.x87fcw = (state.x87fcw & ~FCW_PC) | (mpt::to_underlying(*precision) << mpt::countr_zero(FCW_PC)); + } + } + if (infinity_projective) { + if (state.x87_level <= 2) { + state.x87fcw = (state.x87fcw & ~FCW_X) | ((*infinity_projective) ? 0 : FCW_X); + } + } + set_state(state); + } + + MPT_FORCEINLINE ~guard() { + set_state(m_oldstate); + } + }; + +#endif // MPT_ARCH +}; + + + +} // namespace x86 + +namespace amd64 = x86; + + + +} // namespace arch + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_ARCH_X86_AMD64_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/audio/span.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/audio/span.hpp index 5653f8d8f..b9f59c410 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/audio/span.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/audio/span.hpp @@ -8,6 +8,9 @@ #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" +#include +#include + #include #include @@ -18,6 +21,180 @@ inline namespace MPT_INLINE_NS { +// LRLRLRLRLR + +template +struct audio_span_interleaved { +public: + using sample_type = SampleType; + +private: + sample_type * const m_buffer; + std::size_t m_channels; + std::size_t m_frames; + +public: + MPT_CONSTEXPRINLINE audio_span_interleaved(sample_type * buffer, std::size_t channels, std::size_t frames) noexcept + : m_buffer(buffer) + , m_channels(channels) + , m_frames(frames) { + return; + } + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { + return nullptr; + } + MPT_FORCEINLINE sample_type * data() const noexcept { + return m_buffer; + } + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { + return m_buffer[m_channels * frame + channel]; + } + MPT_FORCEINLINE bool is_contiguous() const noexcept { + return true; + } + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { + return false; + } + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { + return true; + } + MPT_FORCEINLINE std::size_t size_channels() const noexcept { + return m_channels; + } + MPT_FORCEINLINE std::size_t size_frames() const noexcept { + return m_frames; + } + MPT_FORCEINLINE std::size_t size_samples() const noexcept { + return m_channels * m_frames; + } + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { + return m_channels; + } +}; + +struct audio_span_frames_are_contiguous_t { +}; + +inline constexpr audio_span_frames_are_contiguous_t audio_span_frames_are_contiguous; + + + +// LLLLLRRRRR + +template +struct audio_span_contiguous { +public: + using sample_type = SampleType; + +private: + sample_type * const m_buffer; + std::size_t m_channels; + std::size_t m_frames; + +public: + MPT_CONSTEXPRINLINE audio_span_contiguous(sample_type * buffer, std::size_t channels, std::size_t frames) noexcept + : m_buffer(buffer) + , m_channels(channels) + , m_frames(frames) { + return; + } + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { + return nullptr; + } + MPT_FORCEINLINE sample_type * data() const noexcept { + return m_buffer; + } + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { + return m_buffer[(m_frames * channel) + frame]; + } + MPT_FORCEINLINE bool is_contiguous() const noexcept { + return true; + } + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { + return true; + } + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { + return false; + } + MPT_FORCEINLINE std::size_t size_channels() const noexcept { + return m_channels; + } + MPT_FORCEINLINE std::size_t size_frames() const noexcept { + return m_frames; + } + MPT_FORCEINLINE std::size_t size_samples() const noexcept { + return m_channels * m_frames; + } + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { + return 1; + } +}; + +struct audio_span_channels_are_contiguous_t { +}; + +inline constexpr audio_span_channels_are_contiguous_t audio_span_channels_are_contiguous; + + + +// LLLLL RRRRR + +template +struct audio_span_planar { +public: + using sample_type = SampleType; + +private: + sample_type * const * m_buffers; + std::size_t m_channels; + std::size_t m_frames; + +public: + MPT_CONSTEXPRINLINE audio_span_planar(sample_type * const * buffers, std::size_t channels, std::size_t frames) noexcept + : m_buffers(buffers) + , m_channels(channels) + , m_frames(frames) { + return; + } + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { + return m_buffers; + } + MPT_FORCEINLINE sample_type * data() const noexcept { + return nullptr; + } + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { + return m_buffers[channel][frame]; + } + MPT_FORCEINLINE bool is_contiguous() const noexcept { + return false; + } + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { + return true; + } + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { + return false; + } + MPT_FORCEINLINE std::size_t size_channels() const noexcept { + return m_channels; + } + MPT_FORCEINLINE std::size_t size_frames() const noexcept { + return m_frames; + } + MPT_FORCEINLINE std::size_t size_samples() const noexcept { + return m_channels * m_frames; + } + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { + return 1; + } +}; + +struct audio_span_channels_are_planar_t { +}; + +inline constexpr audio_span_channels_are_planar_t audio_span_channels_are_planar; + + + // LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx template struct audio_span_planar_strided { @@ -25,220 +202,58 @@ public: using sample_type = SampleType; private: - SampleType * const * m_buffers; + sample_type * const * m_buffers; std::ptrdiff_t m_frame_stride; std::size_t m_channels; std::size_t m_frames; public: - constexpr audio_span_planar_strided(SampleType * const * buffers, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride) noexcept + MPT_CONSTEXPRINLINE audio_span_planar_strided(sample_type * const * buffers, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride) noexcept : m_buffers(buffers) , m_frame_stride(frame_stride) , m_channels(channels) , m_frames(frames) { return; } - SampleType * const * data_planar() const noexcept { + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return m_buffers; } - SampleType * data() const noexcept { + MPT_FORCEINLINE sample_type * data() const noexcept { return nullptr; } - SampleType & operator()(std::size_t channel, std::size_t frame) const { + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffers[channel][static_cast(frame) * m_frame_stride]; } - bool is_contiguous() const noexcept { + MPT_FORCEINLINE bool is_contiguous() const noexcept { return false; } - bool channels_are_contiguous() const noexcept { + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return false; } - bool frames_are_contiguous() const noexcept { + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return false; } - std::size_t size_channels() const noexcept { + MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } - std::size_t size_frames() const noexcept { + MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } - std::size_t size_samples() const noexcept { + MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } - std::ptrdiff_t frame_stride() const noexcept { + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { return m_frame_stride; } }; - -// LLLLL RRRRR -template -struct audio_span_planar { -public: - using sample_type = SampleType; - -private: - SampleType * const * m_buffers; - std::size_t m_channels; - std::size_t m_frames; - -public: - constexpr audio_span_planar(SampleType * const * buffers, std::size_t channels, std::size_t frames) noexcept - : m_buffers(buffers) - , m_channels(channels) - , m_frames(frames) { - return; - } - SampleType * const * data_planar() const noexcept { - return m_buffers; - } - SampleType * data() const noexcept { - return nullptr; - } - SampleType & operator()(std::size_t channel, std::size_t frame) const { - return m_buffers[channel][frame]; - } - bool is_contiguous() const noexcept { - return false; - } - bool channels_are_contiguous() const noexcept { - return false; - } - bool frames_are_contiguous() const noexcept { - return false; - } - std::size_t size_channels() const noexcept { - return m_channels; - } - std::size_t size_frames() const noexcept { - return m_frames; - } - std::size_t size_samples() const noexcept { - return m_channels * m_frames; - } -}; - - -// LLLLLRRRRR -template -struct audio_span_contiguous { -public: - using sample_type = SampleType; - -private: - SampleType * const m_buffer; - std::size_t m_channels; - std::size_t m_frames; - -public: - constexpr audio_span_contiguous(SampleType * buffer, std::size_t channels, std::size_t frames) noexcept - : m_buffer(buffer) - , m_channels(channels) - , m_frames(frames) { - return; - } - SampleType * const * data_planar() const noexcept { - return nullptr; - } - SampleType * data() const noexcept { - return m_buffer; - } - SampleType & operator()(std::size_t channel, std::size_t frame) const { - return m_buffer[(m_frames * channel) + frame]; - } - bool is_contiguous() const noexcept { - return true; - } - bool channels_are_contiguous() const noexcept { - return true; - } - bool frames_are_contiguous() const noexcept { - return false; - } - std::size_t size_channels() const noexcept { - return m_channels; - } - std::size_t size_frames() const noexcept { - return m_frames; - } - std::size_t size_samples() const noexcept { - return m_channels * m_frames; - } -}; - - -// LRLRLRLRLR -template -struct audio_span_interleaved { -public: - using sample_type = SampleType; - -private: - SampleType * const m_buffer; - std::size_t m_channels; - std::size_t m_frames; - -public: - constexpr audio_span_interleaved(SampleType * buffer, std::size_t channels, std::size_t frames) noexcept - : m_buffer(buffer) - , m_channels(channels) - , m_frames(frames) { - return; - } - SampleType * const * data_planar() const noexcept { - return nullptr; - } - SampleType * data() const noexcept { - return m_buffer; - } - SampleType & operator()(std::size_t channel, std::size_t frame) const { - return m_buffer[m_channels * frame + channel]; - } - bool is_contiguous() const noexcept { - return true; - } - bool channels_are_contiguous() const noexcept { - return false; - } - bool frames_are_contiguous() const noexcept { - return true; - } - std::size_t size_channels() const noexcept { - return m_channels; - } - std::size_t size_frames() const noexcept { - return m_frames; - } - std::size_t size_samples() const noexcept { - return m_channels * m_frames; - } -}; - - -struct audio_span_frames_are_contiguous_t { -}; - -struct audio_span_channels_are_contiguous_t { -}; - -struct audio_span_channels_are_planar_t { -}; - struct audio_span_channels_are_planar_and_strided_t { }; -// LRLRLRLRLR -inline constexpr audio_span_frames_are_contiguous_t audio_span_frames_are_contiguous; - -// LLLLLRRRRR -inline constexpr audio_span_channels_are_contiguous_t audio_span_channels_are_contiguous; - -// LLLLL RRRRR -inline constexpr audio_span_channels_are_planar_t audio_span_channels_are_planar; - -// LxxxLxxxLxxxLxxxLxxx xRxxxRxxxRxxxRxxxRxx inline constexpr audio_span_channels_are_planar_and_strided_t audio_span_channels_are_planar_and_strided; + + template struct audio_span { public: @@ -246,8 +261,8 @@ public: private: union { - SampleType * const contiguous; - SampleType * const * const planes; + sample_type * const contiguous; + sample_type * const * const planes; } m_buffer; std::ptrdiff_t m_frame_stride; std::ptrdiff_t m_channel_stride; @@ -255,92 +270,96 @@ private: std::size_t m_frames; public: - constexpr audio_span(audio_span_interleaved buffer) noexcept + MPT_CONSTEXPRINLINE audio_span(audio_span_interleaved buffer) noexcept : m_frame_stride(static_cast(buffer.size_channels())) , m_channel_stride(1) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } - constexpr audio_span(SampleType * buffer, std::size_t channels, std::size_t frames, audio_span_frames_are_contiguous_t) noexcept + MPT_CONSTEXPRINLINE audio_span(sample_type * buffer, std::size_t channels, std::size_t frames, audio_span_frames_are_contiguous_t) noexcept : m_frame_stride(static_cast(channels)) , m_channel_stride(1) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } - constexpr audio_span(audio_span_contiguous buffer) noexcept + MPT_CONSTEXPRINLINE audio_span(audio_span_contiguous buffer) noexcept : m_frame_stride(1) , m_channel_stride(buffer.size_frames()) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.contiguous = buffer.data(); } - constexpr audio_span(SampleType * buffer, std::size_t channels, std::size_t frames, audio_span_channels_are_contiguous_t) noexcept + MPT_CONSTEXPRINLINE audio_span(sample_type * buffer, std::size_t channels, std::size_t frames, audio_span_channels_are_contiguous_t) noexcept : m_frame_stride(1) , m_channel_stride(static_cast(frames)) , m_channels(channels) , m_frames(frames) { m_buffer.contiguous = buffer; } - constexpr audio_span(audio_span_planar buffer) noexcept + MPT_CONSTEXPRINLINE audio_span(audio_span_planar buffer) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } - constexpr audio_span(SampleType * const * planes, std::size_t channels, std::size_t frames, audio_span_channels_are_planar_t) noexcept + MPT_CONSTEXPRINLINE audio_span(sample_type * const * planes, std::size_t channels, std::size_t frames, audio_span_channels_are_planar_t) noexcept : m_frame_stride(1) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } - constexpr audio_span(audio_span_planar_strided buffer) noexcept + MPT_CONSTEXPRINLINE audio_span(audio_span_planar_strided buffer) noexcept : m_frame_stride(static_cast(buffer.frame_stride())) , m_channel_stride(0) , m_channels(buffer.size_channels()) , m_frames(buffer.size_frames()) { m_buffer.planes = buffer.data_planar(); } - constexpr audio_span(SampleType * const * planes, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride, audio_span_channels_are_planar_and_strided_t) noexcept + MPT_CONSTEXPRINLINE audio_span(sample_type * const * planes, std::size_t channels, std::size_t frames, std::ptrdiff_t frame_stride, audio_span_channels_are_planar_and_strided_t) noexcept : m_frame_stride(frame_stride) , m_channel_stride(0) , m_channels(channels) , m_frames(frames) { m_buffer.planes = planes; } - bool is_contiguous() const noexcept { + MPT_FORCEINLINE bool is_contiguous() const noexcept { return (m_channel_stride != 0); } - SampleType * const * data_planar() const noexcept { + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { return (!is_contiguous()) ? m_buffer.planes : nullptr; } - SampleType * data() const noexcept { + MPT_FORCEINLINE sample_type * data() const noexcept { return is_contiguous() ? m_buffer.contiguous : nullptr; } - SampleType & operator()(std::size_t channel, std::size_t frame) const { + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return is_contiguous() ? m_buffer.contiguous[(m_channel_stride * static_cast(channel)) + (m_frame_stride * static_cast(frame))] : m_buffer.planes[channel][frame * static_cast(m_frame_stride)]; } - bool channels_are_contiguous() const noexcept { - return (m_channel_stride == static_cast(m_frames)); + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { + return (m_frame_stride == 1); } - bool frames_are_contiguous() const noexcept { - return (m_frame_stride == static_cast(m_channels)); + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { + return (m_channel_stride == 1); } - std::size_t size_channels() const noexcept { + MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_channels; } - std::size_t size_frames() const noexcept { + MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_frames; } - std::size_t size_samples() const noexcept { + MPT_FORCEINLINE std::size_t size_samples() const noexcept { return m_channels * m_frames; } + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { + return m_frame_stride; + } }; + template struct audio_span_with_offset { public: @@ -351,42 +370,66 @@ private: std::size_t m_offset; public: - constexpr audio_span_with_offset(Taudio_span buffer, std::size_t offsetFrames) noexcept + MPT_CONSTEXPRINLINE audio_span_with_offset(Taudio_span buffer, std::size_t offsetFrames) noexcept : m_buffer(buffer) , m_offset(offsetFrames) { return; } - sample_type * data() const noexcept { + MPT_FORCEINLINE sample_type * const * data_planar() const noexcept { + return nullptr; + } + MPT_FORCEINLINE sample_type * data() const noexcept { if (!is_contiguous()) { return nullptr; } return m_buffer.data() + (size_channels() * m_offset); } - sample_type & operator()(std::size_t channel, std::size_t frame) const { + MPT_FORCEINLINE sample_type & operator()(std::size_t channel, std::size_t frame) const { return m_buffer(channel, m_offset + frame); } - bool is_contiguous() const noexcept { + MPT_FORCEINLINE bool is_contiguous() const noexcept { return m_buffer.is_contiguous() && m_buffer.frames_are_contiguous(); } - bool channels_are_contiguous() const noexcept { + MPT_FORCEINLINE bool channels_are_contiguous() const noexcept { return m_buffer.channels_are_contiguous(); } - bool frames_are_contiguous() const noexcept { + MPT_FORCEINLINE bool frames_are_contiguous() const noexcept { return m_buffer.frames_are_contiguous(); } - std::size_t size_channels() const noexcept { + MPT_FORCEINLINE std::size_t size_channels() const noexcept { return m_buffer.size_channels(); } - std::size_t size_frames() const noexcept { + MPT_FORCEINLINE std::size_t size_frames() const noexcept { return m_buffer.size_frames() - m_offset; } - std::size_t size_samples() const noexcept { + MPT_FORCEINLINE std::size_t size_samples() const noexcept { return size_channels() * size_frames(); } + MPT_FORCEINLINE std::ptrdiff_t frame_stride() const noexcept { + return m_buffer.frame_stride(); + } }; +template +MPT_FORCEINLINE auto audio_span_optimized_visit(Tspan span, Tfunc && f) -> decltype(std::forward(f)(span)) const { + using sample_type = typename Tspan::sample_type; + std::variant, audio_span_contiguous, audio_span_planar, audio_span_planar_strided> v{span}; + if (span.data() && span.is_contiguous() && span.frames_are_contiguous()) { + v = audio_span_interleaved{span.data(), span.size_channels(), span.size_frames()}; + } else if (span.data() && span.is_contiguous() && span.channels_are_contiguous()) { + v = audio_span_contiguous{span.data(), span.size_channels(), span.size_frames()}; + } else if (span.data_planar() && span.channels_are_contiguous()) { + v = audio_span_planar{span.data_planar(), span.size_channels(), span.size_frames()}; + } else if (span.data_planar()) { + v = audio_span_planar_strided{span.data_planar(), span.size_channels(), span.size_frames(), span.frame_stride()}; + } + return std::visit(std::forward(f), v); +} + + + template inline audio_span_with_offset make_audio_span_with_offset(BufferType buf, std::size_t offsetFrames) noexcept { assert(offsetFrames <= buf.size_frames()); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/alloc.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/alloc.hpp index 436ded8a9..1eddf9f89 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/alloc.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/alloc.hpp @@ -123,7 +123,7 @@ struct buffer_cast_impl { // casts between vector<->string of byte-castable types template -inline Tdst buffer_cast(Tsrc src) { +inline Tdst buffer_cast(const Tsrc & src) { return buffer_cast_impl()(src); } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp index 65a6951fe..70308a259 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/arithmetic_shift.hpp @@ -21,7 +21,7 @@ inline namespace MPT_INLINE_NS { // Does the same thing as MSVC would do. This is verified by the test suite. template -constexpr auto rshift_signed_standard(T x, int y) noexcept -> decltype(x >> y) { +constexpr auto rshift_signed_portable(T x, int y) noexcept -> decltype(x >> y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); using result_type = decltype(x >> y); @@ -36,7 +36,7 @@ constexpr auto rshift_signed_standard(T x, int y) noexcept -> decltype(x >> y) { } template -constexpr auto lshift_signed_standard(T x, int y) noexcept -> decltype(x << y) { +constexpr auto lshift_signed_portable(T x, int y) noexcept -> decltype(x << y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); using result_type = decltype(x << y); @@ -50,42 +50,58 @@ constexpr auto lshift_signed_standard(T x, int y) noexcept -> decltype(x << y) { return static_cast(urx); } -#if MPT_COMPILER_SHIFT_SIGNED +#if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED template -constexpr auto rshift_signed_undefined(T x, int y) noexcept -> decltype(x >> y) { +constexpr auto rshift_signed_cxx20(T x, int y) noexcept -> decltype(x >> y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); +#if MPT_COMPILER_GCC +// +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-negative-value" +#endif // MPT_COMPILER_GCC return x >> y; +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC } template -constexpr auto lshift_signed_undefined(T x, int y) noexcept -> decltype(x << y) { +constexpr auto lshift_signed_cxx20(T x, int y) noexcept -> decltype(x << y) { static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_signed); +#if MPT_COMPILER_GCC +// +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-negative-value" +#endif // MPT_COMPILER_GCC return x << y; +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC } template constexpr auto rshift_signed(T x, int y) noexcept -> decltype(x >> y) { - return mpt::rshift_signed_undefined(x, y); + return mpt::rshift_signed_cxx20(x, y); } template constexpr auto lshift_signed(T x, int y) noexcept -> decltype(x << y) { - return mpt::lshift_signed_undefined(x, y); + return mpt::lshift_signed_cxx20(x, y); } #else template constexpr auto rshift_signed(T x, int y) noexcept -> decltype(x >> y) { - return mpt::rshift_signed_standard(x, y); + return mpt::rshift_signed_portable(x, y); } template constexpr auto lshift_signed(T x, int y) noexcept -> decltype(x << y) { - return mpt::lshift_signed_standard(x, y); + return mpt::lshift_signed_portable(x, y); } #endif diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/bit.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/bit.hpp index fad90af4d..c37c88ac7 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/bit.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/bit.hpp @@ -10,19 +10,25 @@ #include "mpt/base/namespace.hpp" #include "mpt/base/macros.hpp" +#if MPT_CXX_BEFORE(20) +#include +#endif // !C++20 #if MPT_CXX_AT_LEAST(20) #include -#else // !C++20 -#include -#include #endif // C++20 +#if MPT_CXX_BEFORE(23) || MPT_COMPILER_MSVC || MPT_LIBCXX_GNU_BEFORE(10) || MPT_LIBCXX_LLVM_BEFORE(12000) +#include +#endif // !C++23 #include -#include -#if MPT_CXX_BEFORE(20) +#if MPT_CXX_BEFORE(20) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM_BEFORE(14000) #include #endif // !C++20 +#if MPT_CXX_BEFORE(23) && MPT_COMPILER_MSVC +#include +#endif // !C++23 + namespace mpt { @@ -30,7 +36,7 @@ inline namespace MPT_INLINE_NS { -#if MPT_CXX_AT_LEAST(20) && !MPT_CLANG_BEFORE(14, 0, 0) +#if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_GNU_BEFORE(11) && !MPT_LIBCXX_LLVM_BEFORE(14000) using std::bit_cast; #else // !C++20 // C++2a compatible bit_cast. @@ -69,63 +75,30 @@ constexpr bool endian_is_weird() noexcept { #else // !C++20 -#if !MPT_COMPILER_GENERIC - #if MPT_COMPILER_MSVC -#define MPT_PLATFORM_LITTLE_ENDIAN -#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define MPT_PLATFORM_BIG_ENDIAN -#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define MPT_PLATFORM_LITTLE_ENDIAN -#endif -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__) -#if __ORDER_BIG_ENDIAN__ != __ORDER_LITTLE_ENDIAN__ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define MPT_PLATFORM_BIG_ENDIAN -#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define MPT_PLATFORM_LITTLE_ENDIAN -#endif -#endif -#endif - -// fallback: -#if !defined(MPT_PLATFORM_BIG_ENDIAN) && !defined(MPT_PLATFORM_LITTLE_ENDIAN) -#if (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) \ - || (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ - || (defined(_STLP_BIG_ENDIAN) && !defined(_STLP_LITTLE_ENDIAN)) -#define MPT_PLATFORM_BIG_ENDIAN -#elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) \ - || (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ - || (defined(_STLP_LITTLE_ENDIAN) && !defined(_STLP_BIG_ENDIAN)) -#define MPT_PLATFORM_LITTLE_ENDIAN -#elif defined(__hpux) || defined(__hppa) \ - || defined(_MIPSEB) \ - || defined(__s390__) -#define MPT_PLATFORM_BIG_ENDIAN -#elif defined(__i386__) || defined(_M_IX86) \ - || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \ - || defined(__bfin__) -#define MPT_PLATFORM_LITTLE_ENDIAN -#endif -#endif - -#endif // !MPT_COMPILER_GENERIC - +// same definition as VS2022 C++20 in order to be compatible with debugvis +enum class endian { + little = 0, + big = 1, + weird = -1, + native = little, +}; +#else // !MPT_COMPILER_MSVC enum class endian { little = 0x78563412u, big = 0x12345678u, weird = 1u, #if MPT_COMPILER_GENERIC native = 0u, -#elif defined(MPT_PLATFORM_LITTLE_ENDIAN) +#elif defined(MPT_ARCH_LITTLE_ENDIAN) native = little, -#elif defined(MPT_PLATFORM_BIG_ENDIAN) +#elif defined(MPT_ARCH_BIG_ENDIAN) native = big, #else native = 0u, #endif }; +#endif // MPT_COMPILER_MSVC static_assert(mpt::endian::big != mpt::endian::little, "platform with all scalar types having size 1 is not supported"); @@ -184,7 +157,7 @@ MPT_FORCEINLINE bool endian_is_weird() noexcept { -#if MPT_CXX_AT_LEAST(20) && MPT_MSVC_AT_LEAST(2022, 1) && !MPT_CLANG_BEFORE(12, 0, 0) +#if MPT_CXX_AT_LEAST(20) && MPT_MSVC_AT_LEAST(2022, 1) && !MPT_LIBCXX_GNU_BEFORE(10) && !MPT_LIBCXX_LLVM_BEFORE(12000) // Disabled for VS2022.0 because of // @@ -368,6 +341,147 @@ constexpr T rotr(T x, int s) noexcept { +#if MPT_CXX_AT_LEAST(23) && !MPT_COMPILER_MSVC + +using std::byteswap; + +#else // !C++23 + +constexpr inline uint16 byteswap_impl_constexpr16(uint16 x) noexcept { +#if MPT_COMPILER_GCC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif // MPT_COMPILER_GCC + return uint16(0) + | ((x >> 8) & 0x00FFu) + | ((x << 8) & 0xFF00u); +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC +} + +constexpr inline uint32 byteswap_impl_constexpr32(uint32 x) noexcept { + return uint32(0) + | ((x & 0x000000FFu) << 24) + | ((x & 0x0000FF00u) << 8) + | ((x & 0x00FF0000u) >> 8) + | ((x & 0xFF000000u) >> 24); +} + +constexpr inline uint64 byteswap_impl_constexpr64(uint64 x) noexcept { + return uint64(0) + | (((x >> 0) & 0xffull) << 56) + | (((x >> 8) & 0xffull) << 48) + | (((x >> 16) & 0xffull) << 40) + | (((x >> 24) & 0xffull) << 32) + | (((x >> 32) & 0xffull) << 24) + | (((x >> 40) & 0xffull) << 16) + | (((x >> 48) & 0xffull) << 8) + | (((x >> 56) & 0xffull) << 0); +} + +#if MPT_COMPILER_GCC +// Clang also supports these, +// however . +#define MPT_byteswap_impl16 __builtin_bswap16 +#define MPT_byteswap_impl32 __builtin_bswap32 +#define MPT_byteswap_impl64 __builtin_bswap64 +#elif MPT_COMPILER_MSVC +#define MPT_byteswap_impl16 _byteswap_ushort +#define MPT_byteswap_impl32 _byteswap_ulong +#define MPT_byteswap_impl64 _byteswap_uint64 +#endif + +// No intrinsics available +#ifndef MPT_byteswap_impl16 +#define MPT_byteswap_impl16(x) byteswap_impl_constexpr16(x) +#endif +#ifndef MPT_byteswap_impl32 +#define MPT_byteswap_impl32(x) byteswap_impl_constexpr32(x) +#endif +#ifndef MPT_byteswap_impl64 +#define MPT_byteswap_impl64(x) byteswap_impl_constexpr64(x) +#endif + +MPT_CONSTEXPR20_FUN uint64 byteswap_impl(uint64 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr64(value); + } else { + return MPT_byteswap_impl64(value); + } +} + +MPT_CONSTEXPR20_FUN uint32 byteswap_impl(uint32 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr32(value); + } else { + return MPT_byteswap_impl32(value); + } +} + +MPT_CONSTEXPR20_FUN uint16 byteswap_impl(uint16 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr16(value); + } else { + return MPT_byteswap_impl16(value); + } +} + +MPT_CONSTEXPR20_FUN int64 byteswap_impl(int64 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr64(value); + } else { + return MPT_byteswap_impl64(value); + } +} + +MPT_CONSTEXPR20_FUN int32 byteswap_impl(int32 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr32(value); + } else { + return MPT_byteswap_impl32(value); + } +} + +MPT_CONSTEXPR20_FUN int16 byteswap_impl(int16 value) noexcept { + MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { + return byteswap_impl_constexpr16(value); + } else { + return MPT_byteswap_impl16(value); + } +} + +// Do NOT remove these overloads, even if they seem useless. +// We do not want risking to extend 8bit integers to int and then +// endian-converting and casting back to int. +// Thus these overloads. + +constexpr inline uint8 byteswap_impl(uint8 value) noexcept { + return value; +} + +constexpr inline int8 byteswap_impl(int8 value) noexcept { + return value; +} + +constexpr inline char byteswap_impl(char value) noexcept { + return value; +} + +#undef MPT_byteswap_impl16 +#undef MPT_byteswap_impl32 +#undef MPT_byteswap_impl64 + +template +constexpr T byteswap(T x) noexcept { + static_assert(std::numeric_limits::is_integer); + return byteswap_impl(x); +} + +#endif // C++23 + + + template constexpr int lower_bound_entropy_bits(T x_) { typename std::make_unsigned::type x = static_cast::type>(x_); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/check_platform.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/check_platform.hpp index 04f7f53b4..e797325c5 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/check_platform.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/check_platform.hpp @@ -11,9 +11,14 @@ #include +#include #include #include +#if MPT_LIBC_DJGPP +#include +#endif // MPT_LIBC_DJGPP + namespace mpt { inline namespace MPT_INLINE_NS { @@ -30,6 +35,60 @@ static_assert(alignof(std::byte) == 1); static_assert(mpt::arch_bits == static_cast(mpt::pointer_size) * 8); +#if MPT_LIBC_DJGPP + +namespace platform { + +namespace detail { + +struct libc_checker { +private: + bool m_libc_check_failure = false; + bool m_libc_has_implicit_code_locking = false; +public: + [[nodiscard]] inline libc_checker() { + assert(((_crt0_startup_flags & _CRT0_FLAG_NONMOVE_SBRK) == _CRT0_FLAG_NONMOVE_SBRK) && ((_crt0_startup_flags & _CRT0_FLAG_UNIX_SBRK) == 0)); + if (((_crt0_startup_flags & _CRT0_FLAG_NONMOVE_SBRK) == _CRT0_FLAG_NONMOVE_SBRK) && ((_crt0_startup_flags & _CRT0_FLAG_UNIX_SBRK) != 0)) { + m_libc_check_failure = true; + } + assert((_crt0_startup_flags & _CRT0_DISABLE_SBRK_ADDRESS_WRAP) == _CRT0_DISABLE_SBRK_ADDRESS_WRAP); + if ((_crt0_startup_flags & _CRT0_DISABLE_SBRK_ADDRESS_WRAP) != _CRT0_DISABLE_SBRK_ADDRESS_WRAP) { + m_libc_check_failure = true; + } + if ((_crt0_startup_flags & _CRT0_FLAG_LOCK_MEMORY) == _CRT0_FLAG_LOCK_MEMORY) { + m_libc_has_implicit_code_locking = true; + } + } + libc_checker(const libc_checker &) = delete; + libc_checker & operator=(const libc_checker &) = delete; + [[nodiscard]] inline bool is_ok() const noexcept { + return !m_libc_check_failure; + } + [[nodiscard]] inline bool has_implicit_code_locking() const noexcept { + return m_libc_has_implicit_code_locking; + } +}; + +#if MPT_COMPILER_CLANG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +#endif // MPT_COMPILER_CLANG +inline const libc_checker g_libc_checker; +#if MPT_COMPILER_CLANG +#pragma clang diagnostic pop +#endif // MPT_COMPILER_CLANG + +} // namespace detail + +[[nodiscard]] inline const mpt::platform::detail::libc_checker & libc() noexcept { + return mpt::platform::detail::g_libc_checker; +} + +} // namespace platform + +#endif // MPT_LIBC_DJGPP + + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect.hpp index c7b1c15c1..22e1a8d13 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect.hpp @@ -5,6 +5,7 @@ +#include "mpt/base/detect_arch.hpp" #include "mpt/base/detect_compiler.hpp" #include "mpt/base/detect_libc.hpp" #include "mpt/base/detect_libcxx.hpp" diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp new file mode 100644 index 000000000..d066593df --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_arch.hpp @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_BASE_DETECT_ARCH_HPP +#define MPT_BASE_DETECT_ARCH_HPP + + + +#include "mpt/base/detect_compiler.hpp" + + + +// The order of the checks matters! + + + +#if MPT_COMPILER_GENERIC + + + +#define MPT_ARCH_GENERIC 1 + + + +#elif MPT_COMPILER_MSVC + + + +#if defined(_M_ARM64) +#define MPT_ARCH_AARCH64 1 + +#elif defined(_M_ARM) +#define MPT_ARCH_ARM 1 + +#elif defined(_M_AMD64) || defined(_M_X64) +#define MPT_ARCH_AMD64 1 + +#elif defined(_M_IX86) +#define MPT_ARCH_X86 1 + +#endif + + + +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG + + + +#if defined(__wasm64__) || defined(__wasm64) +#define MPT_ARCH_WASM64 1 + +#elif defined(__wasm32__) || defined(__wasm32) +#define MPT_ARCH_WASM32 1 + +#elif defined(__aarch64__) +#define MPT_ARCH_AARCH64 1 + +#elif defined(__arm__) +#define MPT_ARCH_ARM 1 + +#elif defined(__amd64__) || defined(__x86_64__) +#define MPT_ARCH_AMD64 1 + +#elif defined(__i386__) || defined(_X86_) +#define MPT_ARCH_X86 1 + +#endif + + + +#else // MPT_COMPILER + + + +#if defined(__wasm64__) || defined(__wasm64) +#define MPT_ARCH_WASM64 1 + +#elif defined(__wasm32__) || defined(__wasm32) +#define MPT_ARCH_WASM32 1 + +#elif defined(__aarch64__) || defined(_M_ARM64) +#define MPT_ARCH_AARCH64 1 + +#elif defined(__arm__) || defined(_M_ARM) +#define MPT_ARCH_ARM 1 + +#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64) || defined(__amd64) || defined(__x86_64) +#define MPT_ARCH_AMD64 1 + +#elif defined(__i386__) || defined(_X86_) || defined(_M_IX86) || defined(__i386) || defined(__X86__) +#define MPT_ARCH_X86 1 + +#endif + + + +#endif // MPT_COMPILER + + + +#ifndef MPT_ARCH_GENERIC +#define MPT_ARCH_GENERIC 0 +#endif +#ifndef MPT_ARCH_WASM64 +#define MPT_ARCH_WASM64 0 +#endif +#ifndef MPT_ARCH_WASM32 +#define MPT_ARCH_WASM32 0 +#endif +#ifndef MPT_ARCH_AARCH64 +#define MPT_ARCH_AARCH64 0 +#endif +#ifndef MPT_ARCH_ARM +#define MPT_ARCH_ARM 0 +#endif +#ifndef MPT_ARCH_AMD64 +#define MPT_ARCH_AMD64 0 +#endif +#ifndef MPT_ARCH_X86 +#define MPT_ARCH_X86 0 +#endif + + + +#if !MPT_COMPILER_GENERIC + +#if MPT_COMPILER_MSVC +#define MPT_ARCH_LITTLE_ENDIAN +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MPT_ARCH_BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MPT_ARCH_LITTLE_ENDIAN +#endif +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__) +#if __ORDER_BIG_ENDIAN__ != __ORDER_LITTLE_ENDIAN__ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define MPT_ARCH_BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define MPT_ARCH_LITTLE_ENDIAN +#endif +#endif +#endif + +// fallback: +#if !defined(MPT_ARCH_BIG_ENDIAN) && !defined(MPT_ARCH_LITTLE_ENDIAN) +#if (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) \ + || (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ + || (defined(_STLP_BIG_ENDIAN) && !defined(_STLP_LITTLE_ENDIAN)) +#define MPT_ARCH_BIG_ENDIAN +#elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) \ + || (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ + || (defined(_STLP_LITTLE_ENDIAN) && !defined(_STLP_BIG_ENDIAN)) +#define MPT_ARCH_LITTLE_ENDIAN +#elif defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) \ + || defined(__s390__) +#define MPT_ARCH_BIG_ENDIAN +#elif defined(__i386__) || defined(_M_IX86) \ + || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \ + || defined(__bfin__) +#define MPT_ARCH_LITTLE_ENDIAN +#endif +#endif + +#endif // !MPT_COMPILER_GENERIC + + + +#endif // MPT_BASE_DETECT_ARCH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp index 54e253da4..b01718b33 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_compiler.hpp @@ -26,8 +26,8 @@ #define MPT_CLANG_AT_LEAST(major, minor, patch) (MPT_COMPILER_CLANG_VERSION >= MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #define MPT_CLANG_BEFORE(major, minor, patch) (MPT_COMPILER_CLANG_VERSION < MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) -#if MPT_CLANG_BEFORE(7, 0, 0) -#error "clang version 7 required" +#if MPT_CLANG_BEFORE(6, 0, 0) +#error "clang version 6 required" #endif #if defined(__clang_analyzer__) @@ -43,14 +43,16 @@ #define MPT_GCC_AT_LEAST(major, minor, patch) (MPT_COMPILER_GCC_VERSION >= MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) #define MPT_GCC_BEFORE(major, minor, patch) (MPT_COMPILER_GCC_VERSION < MPT_COMPILER_MAKE_VERSION3((major), (minor), (patch))) -#if MPT_GCC_BEFORE(8, 1, 0) -#error "GCC version 8.1 required" +#if MPT_GCC_BEFORE(7, 1, 0) +#error "GCC version 7.1 required" #endif #elif defined(_MSC_VER) #define MPT_COMPILER_MSVC 1 -#if (_MSC_VER >= 1934) +#if (_MSC_VER >= 1935) +#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 5) +#elif (_MSC_VER >= 1934) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 4) #elif (_MSC_VER >= 1933) #define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2022, 3) @@ -154,9 +156,12 @@ #if MPT_COMPILER_GENERIC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG #if (__cplusplus >= 202002) -// Support for C++20 is lacking across all compilers. -// Only assume C++17 for non-MSVC, even when in C++20 mode. +#if defined(__APPLE__) && MPT_CLANG_BEFORE(13, 0, 0) +// XCode 12.5 has a really weird mix of Clang and libc++. Just black-list C++20 support for XCode <= 12. #define MPT_CXX 17 +#else +#define MPT_CXX 20 +#endif #elif (__cplusplus >= 201703) #define MPT_CXX 17 #else diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libc.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libc.hpp index 4cc811e77..da6fc93ef 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libc.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libc.hpp @@ -15,14 +15,20 @@ // order of checks is important! #if MPT_COMPILER_GENERIC #define MPT_LIBC_GENERIC 1 -#elif MPT_COMPILER_GCC && (defined(__MINGW32__) || defined(__MINGW64__)) -#define MPT_LIBC_MS 1 -#elif defined(__GLIBC__) +#elif (defined(__MINGW32__) || defined(__MINGW64__)) +#define MPT_LIBC_MINGW 1 +#elif (defined(__GLIBC__) || defined(__GNU_LIBRARY__)) #define MPT_LIBC_GLIBC 1 #elif MPT_COMPILER_MSVC #define MPT_LIBC_MS 1 #elif MPT_COMPILER_CLANG && MPT_OS_WINDOWS #define MPT_LIBC_MS 1 +#elif defined(__BIONIC__) +#define MPT_LIBC_BIONIC 1 +#elif defined(__APPLE__) +#define MPT_LIBC_APPLE 1 +#elif defined(__DJGPP__) +#define MPT_LIBC_DJGPP 1 #else #define MPT_LIBC_GENERIC 1 #endif @@ -33,9 +39,44 @@ #ifndef MPT_LIBC_GLIBC #define MPT_LIBC_GLIBC 0 #endif +#ifndef MPT_LIBC_MINGW +#define MPT_LIBC_MINGW 0 +#endif #ifndef MPT_LIBC_MS #define MPT_LIBC_MS 0 #endif +#ifndef MPT_LIBC_BIONIC +#define MPT_LIBC_BIONIC 0 +#endif +#ifndef MPT_LIBC_APPLE +#define MPT_LIBC_APPLE 0 +#endif +#ifndef MPT_LIBC_DJGPP +#define MPT_LIBC_DJGPP 0 +#endif + +#if MPT_LIBC_MS +#if defined(_DEBUG) +#define MPT_LIBC_MS_DEBUG 1 +#endif +#if defined(_DLL) +#define MPT_LIBC_MS_SHARED 1 +#define MPT_LIBC_MS_STATIC 0 +#else +#define MPT_LIBC_MS_SHARED 0 +#define MPT_LIBC_MS_STATIC 1 +#endif +#endif + +#ifndef MPT_LIBC_MS_DEBUG +#define MPT_LIBC_MS_DEBUG 0 +#endif +#ifndef MPT_LIBC_MS_SHARED +#define MPT_LIBC_MS_SHARED 0 +#endif +#ifndef MPT_LIBC_MS_STATIC +#define MPT_LIBC_MS_STATIC 0 +#endif diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libcxx.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libcxx.hpp index 7f21564f1..a6b3bd967 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libcxx.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_libcxx.hpp @@ -20,9 +20,15 @@ #if MPT_COMPILER_GENERIC #define MPT_LIBCXX_GENERIC 1 #elif defined(_LIBCPP_VERSION) -#define MPT_LIBCXX_LLVM 1 +#define MPT_LIBCXX_LLVM 1 +#define MPT_LIBCXX_LLVM_VERSION _LIBCPP_VERSION +#define MPT_LIBCXX_LLVM_AT_LEAST(ver) (MPT_LIBCXX_LLVM_VERSION >= (ver)) +#define MPT_LIBCXX_LLVM_BEFORE(ver) (MPT_LIBCXX_LLVM_VERSION < (ver)) #elif defined(__GLIBCXX__) || defined(__GLIBCPP__) -#define MPT_LIBCXX_GNU 1 +#define MPT_LIBCXX_GNU 1 +#define MPT_LIBCXX_GNU_VERSION _GLIBCXX_RELEASE +#define MPT_LIBCXX_GNU_AT_LEAST(ver) (MPT_LIBCXX_GNU_VERSION >= (ver)) +#define MPT_LIBCXX_GNU_BEFORE(ver) (MPT_LIBCXX_GNU_VERSION < (ver)) #elif MPT_COMPILER_MSVC #define MPT_LIBCXX_MS 1 #elif MPT_COMPILER_CLANG && MPT_OS_WINDOWS @@ -35,10 +41,16 @@ #define MPT_LIBCXX_GENERIC 0 #endif #ifndef MPT_LIBCXX_LLVM -#define MPT_LIBCXX_LLVM 0 +#define MPT_LIBCXX_LLVM 0 +#define MPT_LIBCXX_LLVM_VERSION 0 +#define MPT_LIBCXX_LLVM_AT_LEAST(ver) 0 +#define MPT_LIBCXX_LLVM_BEFORE(ver) 0 #endif #ifndef MPT_LIBCXX_GNU -#define MPT_LIBCXX_GNU 0 +#define MPT_LIBCXX_GNU 0 +#define MPT_LIBCXX_GNU_VERSION 0 +#define MPT_LIBCXX_GNU_AT_LEAST(ver) 0 +#define MPT_LIBCXX_GNU_BEFORE(ver) 0 #endif #ifndef MPT_LIBCXX_MS #define MPT_LIBCXX_MS 0 diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp index 507cce88d..59e02e25e 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_os.hpp @@ -5,37 +5,306 @@ +#define MPT_WIN_MAKE_VERSION(major, minor, sp, build) ((major << 24) + (minor << 16) + (sp << 8) + (build << 0)) + +// clang-format off + +#define MPT_WIN_WIN32S MPT_WIN_MAKE_VERSION(0x03, 0x00, 0x00, 0x00) + +#define MPT_WIN_WIN95 MPT_WIN_MAKE_VERSION(0x04, 0x00, 0x00, 0x00) +#define MPT_WIN_WIN98 MPT_WIN_MAKE_VERSION(0x04, 0x10, 0x00, 0x00) +#define MPT_WIN_WINME MPT_WIN_MAKE_VERSION(0x04, 0x90, 0x00, 0x00) + +#define MPT_WIN_NT3 MPT_WIN_MAKE_VERSION(0x03, 0x00, 0x00, 0x00) +#define MPT_WIN_NT4 MPT_WIN_MAKE_VERSION(0x04, 0x00, 0x00, 0x00) +#define MPT_WIN_2000 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x00, 0x00) +#define MPT_WIN_2000SP1 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x01, 0x00) +#define MPT_WIN_2000SP2 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x02, 0x00) +#define MPT_WIN_2000SP3 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x03, 0x00) +#define MPT_WIN_2000SP4 MPT_WIN_MAKE_VERSION(0x05, 0x00, 0x04, 0x00) +#define MPT_WIN_XP MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x00, 0x00) +#define MPT_WIN_XPSP1 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x01, 0x00) +#define MPT_WIN_XPSP2 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x02, 0x00) +#define MPT_WIN_XPSP3 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x03, 0x00) +#define MPT_WIN_XPSP4 MPT_WIN_MAKE_VERSION(0x05, 0x01, 0x04, 0x00) // unused +#define MPT_WIN_XP64 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x00, 0x00) // unused +#define MPT_WIN_XP64SP1 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x01, 0x00) +#define MPT_WIN_XP64SP2 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x02, 0x00) +#define MPT_WIN_XP64SP3 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x03, 0x00) // unused +#define MPT_WIN_XP64SP4 MPT_WIN_MAKE_VERSION(0x05, 0x02, 0x04, 0x00) // unused +#define MPT_WIN_VISTA MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x00, 0x00) +#define MPT_WIN_VISTASP1 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x01, 0x00) +#define MPT_WIN_VISTASP2 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x02, 0x00) +#define MPT_WIN_VISTASP3 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x03, 0x00) // unused +#define MPT_WIN_VISTASP4 MPT_WIN_MAKE_VERSION(0x06, 0x00, 0x04, 0x00) // unused +#define MPT_WIN_7 MPT_WIN_MAKE_VERSION(0x06, 0x01, 0x00, 0x00) +#define MPT_WIN_8 MPT_WIN_MAKE_VERSION(0x06, 0x02, 0x00, 0x00) +#define MPT_WIN_81 MPT_WIN_MAKE_VERSION(0x06, 0x03, 0x00, 0x00) + +#define MPT_WIN_10 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x00) // NTDDI_WIN10 1507 +#define MPT_WIN_10_1511 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x01) // NTDDI_WIN10_TH2 1511 +#define MPT_WIN_10_1607 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x02) // NTDDI_WIN10_RS1 1607 +#define MPT_WIN_10_1703 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x03) // NTDDI_WIN10_RS2 1703 +#define MPT_WIN_10_1709 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x04) // NTDDI_WIN10_RS3 1709 +#define MPT_WIN_10_1803 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x05) // NTDDI_WIN10_RS4 1803 +#define MPT_WIN_10_1809 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x06) // NTDDI_WIN10_RS5 1809 +#define MPT_WIN_10_1903 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x07) // NTDDI_WIN10_19H1 1903/19H1 +#define MPT_WIN_10_1909 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x08) // NTDDI_WIN10_VB 1909/19H2 +#define MPT_WIN_10_2004 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x09) // NTDDI_WIN10_MN 2004/20H1 + // 20H2 + // 21H1 +#define MPT_WIN_10_21H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0a) // NTDDI_WIN10_FE 21H2 + // 22H2 + +#define MPT_WIN_11 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0b) // NTDDI_WIN10_CO 21H2 +#define MPT_WIN_11_22H2 MPT_WIN_MAKE_VERSION(0x0a, 0x00, 0x00, 0x0c) // NTDDI_WIN10_NI 22H2 + +// MPT_WIN_API_DESKTOP : Windows 8/10 Desktop Application (Win32) +// MPT_WIN_API_UNIVERSAL : Windows 10 Store App / Universal App +// MPT_WIN_API_STORE_PC : Windows 8 Store Desktop App +// MPT_WIN_API_STORE_PHONE : Windows 8 Store Phone App + +// clang-format on + + + // The order of the checks matters! #if defined(__DJGPP__) #define MPT_OS_DJGPP 1 + + #elif defined(__EMSCRIPTEN__) #define MPT_OS_EMSCRIPTEN 1 #if !defined(__EMSCRIPTEN_major__) || !defined(__EMSCRIPTEN_minor__) || !defined(__EMSCRIPTEN_tiny__) #include #endif #if defined(__EMSCRIPTEN_major__) && defined(__EMSCRIPTEN_minor__) -#if (__EMSCRIPTEN_major__ > 1) +#if (__EMSCRIPTEN_major__ > 3) // ok -#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ > 39) +#elif (__EMSCRIPTEN_major__ == 3) && (__EMSCRIPTEN_minor__ > 1) // ok -#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ == 39) && (__EMSCRIPTEN_tiny__ >= 7) +#elif (__EMSCRIPTEN_major__ == 3) && (__EMSCRIPTEN_minor__ == 1) && (__EMSCRIPTEN_tiny__ >= 1) // ok #else -#error "Emscripten >= 1.39.7 is required." +#error "Emscripten >= 3.1.1 is required." #endif #endif + + #elif defined(_WIN32) #define MPT_OS_WINDOWS 1 +#if !defined(_WIN32_WINDOWS) && !defined(WINVER) +// include modern SDK version header if not targeting Win9x +#include +#ifdef _WIN32_WINNT_NT4 +static_assert((_WIN32_WINNT_NT4 << 16) == MPT_WIN_NT4); +#endif +#ifdef _WIN32_WINNT_WIN2K +static_assert((_WIN32_WINNT_WIN2K << 16) == MPT_WIN_2000); +#endif +#ifdef _WIN32_WINNT_WINXP +static_assert((_WIN32_WINNT_WINXP << 16) == MPT_WIN_XP); +#endif +#ifdef _WIN32_WINNT_WS03 +static_assert((_WIN32_WINNT_WS03 << 16) == MPT_WIN_XP64); +#endif +#ifdef _WIN32_WINNT_VISTA +static_assert((_WIN32_WINNT_VISTA << 16) == MPT_WIN_VISTA); +#endif +#ifdef _WIN32_WINNT_WIN7 +static_assert((_WIN32_WINNT_WIN7 << 16) == MPT_WIN_7); +#endif +#ifdef _WIN32_WINNT_WIN8 +static_assert((_WIN32_WINNT_WIN8 << 16) == MPT_WIN_8); +#endif +#ifdef _WIN32_WINNT_WINBLUE +static_assert((_WIN32_WINNT_WINBLUE << 16) == MPT_WIN_81); +#endif +#ifdef _WIN32_WINNT_WIN10 +static_assert((_WIN32_WINNT_WIN10 << 16) == MPT_WIN_10); +#endif +#ifdef NTDDI_WIN4 +static_assert(NTDDI_WIN4 == MPT_WIN_NT4); +#endif +#ifdef NTDDI_WIN2K +static_assert(NTDDI_WIN2K == MPT_WIN_2000); +#endif +#ifdef NTDDI_WIN2KSP1 +static_assert(NTDDI_WIN2KSP1 == MPT_WIN_2000SP1); +#endif +#ifdef NTDDI_WIN2KSP2 +static_assert(NTDDI_WIN2KSP2 == MPT_WIN_2000SP2); +#endif +#ifdef NTDDI_WIN2KSP3 +static_assert(NTDDI_WIN2KSP3 == MPT_WIN_2000SP3); +#endif +#ifdef NTDDI_WIN2KSP4 +static_assert(NTDDI_WIN2KSP4 == MPT_WIN_2000SP4); +#endif +#ifdef NTDDI_WINXP +static_assert(NTDDI_WINXP == MPT_WIN_XP); +#endif +#ifdef NTDDI_WINXPSP1 +static_assert(NTDDI_WINXPSP1 == MPT_WIN_XPSP1); +#endif +#ifdef NTDDI_WINXPSP2 +static_assert(NTDDI_WINXPSP2 == MPT_WIN_XPSP2); +#endif +#ifdef NTDDI_WINXPSP3 +static_assert(NTDDI_WINXPSP3 == MPT_WIN_XPSP3); +#endif +#ifdef NTDDI_WINXPSP4 +static_assert(NTDDI_WINXPSP4 == MPT_WIN_XPSP4); +#endif +#ifdef NTDDI_WS03 +static_assert(NTDDI_WS03 == MPT_WIN_XP64); +#endif +#ifdef NTDDI_WS03SP1 +static_assert(NTDDI_WS03SP1 == MPT_WIN_XP64SP1); +#endif +#ifdef NTDDI_WS03SP2 +static_assert(NTDDI_WS03SP2 == MPT_WIN_XP64SP2); +#endif +#ifdef NTDDI_WS03SP3 +static_assert(NTDDI_WS03SP3 == MPT_WIN_XP64SP3); +#endif +#ifdef NTDDI_WS03SP4 +static_assert(NTDDI_WS03SP4 == MPT_WIN_XP64SP4); +#endif +#ifdef NTDDI_VISTA +static_assert(NTDDI_VISTA == MPT_WIN_VISTA); +#endif +#ifdef NTDDI_VISTASP1 +static_assert(NTDDI_VISTASP1 == MPT_WIN_VISTASP1); +#endif +#ifdef NTDDI_VISTASP2 +static_assert(NTDDI_VISTASP2 == MPT_WIN_VISTASP2); +#endif +#ifdef NTDDI_VISTASP3 +static_assert(NTDDI_VISTASP3 == MPT_WIN_VISTASP3); +#endif +#ifdef NTDDI_VISTASP4 +static_assert(NTDDI_VISTASP4 == MPT_WIN_VISTASP4); +#endif +#ifdef NTDDI_WIN7 +static_assert(NTDDI_WIN7 == MPT_WIN_7); +#endif +#ifdef NTDDI_WIN8 +static_assert(NTDDI_WIN8 == MPT_WIN_8); +#endif +#ifdef NTDDI_WINBLUE +static_assert(NTDDI_WINBLUE == MPT_WIN_81); +#endif +#ifdef NTDDI_WIN10 +static_assert(NTDDI_WIN10 == MPT_WIN_10); +#endif +#ifdef NTDDI_WIN10_TH2 +static_assert(NTDDI_WIN10_TH2 == MPT_WIN_10_1511); +#endif +#ifdef NTDDI_WIN10_RS1 +static_assert(NTDDI_WIN10_RS1 == MPT_WIN_10_1607); +#endif +#ifdef NTDDI_WIN10_RS2 +static_assert(NTDDI_WIN10_RS2 == MPT_WIN_10_1703); +#endif +#ifdef NTDDI_WIN10_RS3 +static_assert(NTDDI_WIN10_RS3 == MPT_WIN_10_1709); +#endif +#ifdef NTDDI_WIN10_RS4 +static_assert(NTDDI_WIN10_RS4 == MPT_WIN_10_1803); +#endif +#ifdef NTDDI_WIN10_RS5 +static_assert(NTDDI_WIN10_RS5 == MPT_WIN_10_1809); +#endif +#ifdef NTDDI_WIN10_19H1 +static_assert(NTDDI_WIN10_19H1 == MPT_WIN_10_1903); +#endif +#ifdef NTDDI_WIN10_VB +static_assert(NTDDI_WIN10_VB == MPT_WIN_10_1909); +#endif +#ifdef NTDDI_WIN10_MN +static_assert(NTDDI_WIN10_MN == MPT_WIN_10_2004); +#endif +#ifdef NTDDI_WIN10_FE +static_assert(NTDDI_WIN10_FE == MPT_WIN_10_21H2); +#endif +#ifdef NTDDI_WIN10_CO +static_assert(NTDDI_WIN10_CO == MPT_WIN_11); +#endif +#ifdef NTDDI_WIN10_NI +static_assert(NTDDI_WIN10_NI == MPT_WIN_11_22H2); +#endif +#endif #if defined(WINAPI_FAMILY) #include -#if (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define MPT_OS_WINDOWS_WINRT 0 #else #define MPT_OS_WINDOWS_WINRT 1 #endif +#define MPT_WIN_API_DESKTOP WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define MPT_WIN_API_UNIVERSAL WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP) +#define MPT_WIN_API_STORE_PC WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define MPT_WIN_API_STORE_PHONE WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) #else // !WINAPI_FAMILY -#define MPT_OS_WINDOWS_WINRT 0 +#define MPT_OS_WINDOWS_WINRT 0 +#define MPT_WIN_API_DESKTOP 1 +#define MPT_WIN_API_UNIVERSAL 0 +#define MPT_WIN_API_STORE_PC 0 +#define MPT_WIN_API_STORE_PHONE 0 #endif // WINAPI_FAMILY +#if defined(NTDDI_VERSION) || defined(_WIN32_WINNT) +#define MPT_OS_WINDOWS_WINNT 1 +#define MPT_OS_WINDOWS_WIN9X 0 +#define MPT_OS_WINDOWS_WIN32 0 +#if defined(NTDDI_VERSION) +#define MPT_WIN_VERSION NTDDI_VERSION +#else +#define MPT_WIN_VERSION (_WIN32_WINNT << 16) +#endif +#elif defined(_WIN32_WINDOWS) +#define MPT_OS_WINDOWS_WINNT 0 +#define MPT_OS_WINDOWS_WIN9X 1 +#define MPT_OS_WINDOWS_WIN32 0 +#define MPT_WIN_VERSION (_WIN32_WINDOWS << 16) +#elif defined(WINVER) +#define MPT_OS_WINDOWS_WINNT 0 +#define MPT_OS_WINDOWS_WIN9X 0 +#define MPT_OS_WINDOWS_WIN32 1 +#define MPT_WIN_VERSION (WINVER << 16) +#else +// assume modern +#define MPT_OS_WINDOWS_WINNT 1 +#define MPT_OS_WINDOWS_WIN9X 0 +#define MPT_OS_WINDOWS_WIN32 0 +#define MPT_WIN_VERSION MPT_WIN_NT4 +#endif +#define MPT_WINRT_AT_LEAST(v) (MPT_OS_WINDOWS_WINRT && MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION >= (v))) +#define MPT_WINRT_BEFORE(v) (MPT_OS_WINDOWS_WINRT && MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION < (v))) +#define MPT_WINNT_AT_LEAST(v) (MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION >= (v))) +#define MPT_WINNT_BEFORE(v) (MPT_OS_WINDOWS_WINNT && (MPT_WIN_VERSION < (v))) +#define MPT_WIN9X_AT_LEAST(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X) && (MPT_WIN_VERSION >= (v))) +#define MPT_WIN9X_BEFORE(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X) && (MPT_WIN_VERSION < (v))) +#define MPT_WIN32_AT_LEAST(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) && (MPT_WIN_VERSION >= (v))) +#define MPT_WIN32_BEFORE(v) ((MPT_OS_WINDOWS_WINNT || MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) && (MPT_WIN_VERSION < (v))) +#if MPT_OS_WINDOWS_WINRT +#define MPT_WIN_AT_LEAST(v) MPT_WINRT_AT_LEAST(v) +#define MPT_WIN_BEFORE(v) MPT_WINRT_BEFORE(v) +#elif MPT_OS_WINDOWS_WINNT +#define MPT_WIN_AT_LEAST(v) MPT_WINNT_AT_LEAST(v) +#define MPT_WIN_BEFORE(v) MPT_WINNT_BEFORE(v) +#elif MPT_OS_WINDOWS_WIN9X +#define MPT_WIN_AT_LEAST(v) MPT_WIN9X_AT_LEAST(v) +#define MPT_WIN_BEFORE(v) MPT_WIN9X_BEFORE(v) +#elif MPT_OS_WINDOWS_WIN32 +#define MPT_WIN_AT_LEAST(v) MPT_WIN32_AT_LEAST(v) +#define MPT_WIN_BEFORE(v) MPT_WIN32_BEFORE(v) +#else +#define MPT_WIN_AT_LEAST(v) 0 +#define MPT_WIN_BEFORE(v) 1 +#endif + + #elif defined(__APPLE__) #define MPT_OS_MACOSX_OR_IOS 1 #include @@ -49,26 +318,47 @@ //#elif TARGET_OS_MAC //#else //#endif + + #elif defined(__HAIKU__) #define MPT_OS_HAIKU 1 + + #elif defined(__ANDROID__) || defined(ANDROID) #define MPT_OS_ANDROID 1 + + #elif defined(__linux__) #define MPT_OS_LINUX 1 + + #elif defined(__DragonFly__) #define MPT_OS_DRAGONFLYBSD 1 + + #elif defined(__FreeBSD__) #define MPT_OS_FREEBSD 1 + + #elif defined(__OpenBSD__) #define MPT_OS_OPENBSD 1 + + #elif defined(__NetBSD__) #define MPT_OS_NETBSD 1 + + #elif defined(__unix__) #define MPT_OS_GENERIC_UNIX 1 + + #else #define MPT_OS_UNKNOWN 1 + + #endif + #ifndef MPT_OS_DJGPP #define MPT_OS_DJGPP 0 #endif @@ -81,6 +371,57 @@ #ifndef MPT_OS_WINDOWS_WINRT #define MPT_OS_WINDOWS_WINRT 0 #endif +#ifndef MPT_OS_WINDOWS_WINNT +#define MPT_OS_WINDOWS_WINNT 0 +#endif +#ifndef MPT_OS_WINDOWS_WIN9X +#define MPT_OS_WINDOWS_WIN9X 0 +#endif +#ifndef MPT_OS_WINDOWS_WIN32 +#define MPT_OS_WINDOWS_WIN32 0 +#endif +#ifndef MPT_WINRT_AT_LEAST +#define MPT_WINRT_AT_LEAST(v) 0 +#endif +#ifndef MPT_WINRT_BEFORE +#define MPT_WINRT_BEFORE(v) 0 +#endif +#ifndef MPT_WINNT_AT_LEAST +#define MPT_WINNT_AT_LEAST(v) 0 +#endif +#ifndef MPT_WINNT_BEFORE +#define MPT_WINNT_BEFORE(v) 0 +#endif +#ifndef MPT_WIN9X_AT_LEAST +#define MPT_WIN9X_AT_LEAST(v) 0 +#endif +#ifndef MPT_WIN9X_BEFORE +#define MPT_WIN9X_BEFORE(v) 0 +#endif +#ifndef MPT_WIN32_AT_LEAST +#define MPT_WIN32_AT_LEAST(v) 0 +#endif +#ifndef MPT_WIN32_BEFORE +#define MPT_WIN32_BEFORE(v) 0 +#endif +#ifndef MPT_WIN_AT_LEAST +#define MPT_WIN_AT_LEAST(v) 0 +#endif +#ifndef MPT_WIN_BEFORE +#define MPT_WIN_BEFORE(v) 0 +#endif +#ifndef MPT_WIN_API_DESKTOP +#define MPT_WIN_API_DESKTOP 0 +#endif +#ifndef MPT_WIN_API_UNIVERSAL +#define MPT_WIN_API_UNIVERSAL 0 +#endif +#ifndef MPT_WIN_API_STORE_PC +#define MPT_WIN_API_STORE_PC 0 +#endif +#ifndef MPT_WIN_API_STORE_PHONE +#define MPT_WIN_API_STORE_PHONE 0 +#endif #ifndef MPT_OS_MACOSX_OR_IOS #define MPT_OS_MACOSX_OR_IOS 0 #endif @@ -114,4 +455,8 @@ +#define MPT_MODE_KERNEL 0 + + + #endif // MPT_BASE_DETECT_OS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp index ab7b076a2..54aacbbe4 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/detect_quirks.hpp @@ -6,13 +6,39 @@ #include "mpt/base/detect_compiler.hpp" +#include "mpt/base/detect_libc.hpp" #include "mpt/base/detect_libcxx.hpp" #include "mpt/base/detect_os.hpp" +#if MPT_CXX_AT_LEAST(20) +#include +#else // !C++20 +#include +#endif // C++20 + #if MPT_COMPILER_MSVC +#if !defined(_MSVC_TRADITIONAL) +#define MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR +#else +#if _MSVC_TRADITIONAL +#define MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR +#endif +#endif +#endif + + + +#if MPT_GCC_BEFORE(9, 1, 0) +#define MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW +#endif + + + +#if MPT_CXX_BEFORE(20) && MPT_COMPILER_MSVC // Compiler has multiplication/division semantics when shifting signed integers. +// In C++20, this behaviour is required by the standard. #define MPT_COMPILER_SHIFT_SIGNED 1 #endif @@ -22,8 +48,8 @@ -// This should really be based on __STDCPP_THREADS__, but that is not defined by -// GCC or clang. Stupid. +// This should really be based on __STDCPP_THREADS__, +// but that is not defined consistently by GCC or clang. Stupid. // Just assume multithreaded and disable for platforms we know are // singlethreaded later on. #define MPT_PLATFORM_MULTITHREADED 1 @@ -40,8 +66,24 @@ +#if MPT_MSVC_BEFORE(2019, 0) || MPT_GCC_BEFORE(8, 1, 0) +#define MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT +#endif + + + +#if MPT_GCC_BEFORE(11, 1, 0) +#define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS +#elif MPT_CLANG_BEFORE(12, 0, 0) +#define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS +#elif (defined(__MINGW32__) || defined(__MINGW64__)) && MPT_LIBCXX_GNU && defined(_GLIBCXX_HAS_GTHREADS) && !defined(__STDCPP_THREADS__) +#define MPT_COMPILER_QUIRK_NO_STDCPP_THREADS +#endif + + + #if MPT_OS_WINDOWS && MPT_COMPILER_MSVC -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) // _WIN32_WINNT_VISTA +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #define MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #endif #endif @@ -60,9 +102,30 @@ -#if MPT_OS_DJGPP +#if MPT_LIBCXX_GNU +#if !defined(_GLIBCXX_USE_WCHAR_T) +#ifndef MPT_COMPILER_QUIRK_NO_WCHAR #define MPT_COMPILER_QUIRK_NO_WCHAR #endif +#endif +#endif +#if defined(__MINGW32__) && !defined(__MINGW64__) && (MPT_OS_WINDOWS_WIN9X || MPT_OS_WINDOWS_WIN32) +#ifndef MPT_COMPILER_QUIRK_NO_WCHAR +#define MPT_COMPILER_QUIRK_NO_WCHAR +#endif +#endif + + + +#if MPT_LIBCXX_LLVM_BEFORE(14000) +#define MPT_COMPILER_QUIRK_NO_STRING_VIEW_ITERATOR_CTOR +#endif + + + +#if MPT_LIBCXX_GNU_BEFORE(9) +#define MPT_COMPILER_QUIRK_NO_FILESYSTEM +#endif @@ -73,6 +136,42 @@ +#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG + +#if defined(__FAST_MATH__) +#define MPT_COMPILER_QUIRK_FASTMATH 1 +#endif +#if defined(__FINITE_MATH_ONLY__) +#if (__FINITE_MATH_ONLY__ >= 1) +#define MPT_COMPILER_QUIRK_FINITEMATH 1 +#endif +#endif + +#elif MPT_COMPILER_MSVC + +#if defined(_M_FP_FAST) +#define MPT_COMPILER_QUIRK_FASTMATH 1 +#define MPT_COMPILER_QUIRK_FINITEMATH 1 +#endif + +#endif + +#ifndef MPT_COMPILER_QUIRK_FASTMATH +#define MPT_COMPILER_QUIRK_FASTMATH 0 +#endif + +#ifndef MPT_COMPILER_QUIRK_FINITEMATH +#define MPT_COMPILER_QUIRK_FINITEMATH 0 +#endif + + + +#if MPT_COMPILER_GCC && !defined(__arm__) +#if defined(_SOFT_FLOAT) +#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1 +#endif +#endif + #if defined(__arm__) #if defined(__SOFTFP__) @@ -126,7 +225,48 @@ -#if MPT_OS_MACOSX_OR_IOS +#if MPT_LIBC_DJGPP +#define MPT_LIBC_QUIRK_NO_FENV +#endif + + + +#if MPT_CXX_AT_LEAST(20) +#if MPT_LIBCXX_MS && MPT_OS_WINDOWS +#if MPT_WIN_BEFORE(MPT_WIN_10_1903) +// std::chrono timezones require Windows 10 1903 with VS2022 as of 2022-01-22. +// See and +// . +#define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE +#endif +#endif +#if MPT_LIBCXX_GNU_BEFORE(11) +#define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE +#elif MPT_LIBCXX_LLVM_BEFORE(7000) +#define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE +#endif +#if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 2) || !MPT_COMPILER_MSVC) +#elif MPT_LIBCXX_GNU +#define MPT_LIBCXX_QUIRK_NO_CHRONO_DATE_PARSE +#endif +#if MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2022, 6) || !MPT_COMPILER_MSVC) +// Causes massive memory leaks. +// See +// +// / . +#define MPT_LIBCXX_QUIRK_CHRONO_TZ_MEMLEAK +#endif +#endif + + + +#if MPT_LIBCXX_GNU_BEFORE(8) +#define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT +#elif MPT_LIBCXX_LLVM_BEFORE(7000) +#define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT +#elif MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(8000) +#define MPT_LIBCXX_QUIRK_NO_TO_CHARS_INT +#elif MPT_OS_MACOSX_OR_IOS #if defined(TARGET_OS_OSX) #if TARGET_OS_OSX #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15) @@ -138,10 +278,16 @@ -#if (MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2019, 4) || !MPT_COMPILER_MSVC)) || (MPT_LIBCXX_GNU && (MPT_GCC_BEFORE(11, 0, 0) || !MPT_COMPILER_GCC)) || MPT_LIBCXX_LLVM || MPT_LIBCXX_GENERIC +#if (MPT_LIBCXX_MS && (MPT_MSVC_BEFORE(2019, 4) || !MPT_COMPILER_MSVC)) || MPT_LIBCXX_GNU_BEFORE(11) || MPT_LIBCXX_LLVM || MPT_LIBCXX_GENERIC #define MPT_LIBCXX_QUIRK_NO_TO_CHARS_FLOAT #endif +#if MPT_OS_ANDROID && MPT_LIBCXX_LLVM_BEFORE(7000) +#define MPT_LIBCXX_QUIRK_NO_HAS_UNIQUE_OBJECT_REPRESENTATIONS +#endif + + + #endif // MPT_BASE_DETECT_QUIRKS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/macros.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/macros.hpp index c54ebf92c..db9e2a4a4 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/macros.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/macros.hpp @@ -41,10 +41,38 @@ -#define MPT_FORCE_CONSTEXPR(expr) [&]() { \ +#if MPT_CXX_AT_LEAST(20) +#define MPT_CONSTEVAL consteval +#else // !C++20 +// fallback to constexpr +#define MPT_CONSTEVAL MPT_CONSTEXPRINLINE +#endif // C++20 + + + +#if MPT_CXX_AT_LEAST(20) +// this assumes that for C++20, a consteval function will be used +#define MPT_FORCE_CONSTEVAL_EXPRESSION(expr) (expr) +#define MPT_FORCE_CONSTEVAL_VALUE(val) (val) +#else // !C++20 +#define MPT_FORCE_CONSTEVAL_EXPRESSION(expr) [&]() { \ constexpr auto x = (expr); \ return x; \ }() +#define MPT_FORCE_CONSTEVAL_VALUE(val) []() { \ + constexpr auto x = (val); \ + return x; \ +}() +#endif // C++20 + + + +#if MPT_CXX_AT_LEAST(20) +#define MPT_CONSTINIT constinit +#else // !C++20 +// fallback to nothing +#define MPT_CONSTINIT +#endif // C++20 diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/memory.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/memory.hpp index 1ee933789..f67218480 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/memory.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/memory.hpp @@ -83,13 +83,18 @@ struct is_binary_safe : public std::conditional -struct is_binary_safe : public is_binary_safe { }; +struct is_binary_safe : public is_binary_safe::type> { }; template -struct is_binary_safe : public is_binary_safe { }; +struct is_binary_safe : public is_binary_safe::type> { }; template -struct is_binary_safe> : public is_binary_safe { }; +struct is_binary_safe> : public is_binary_safe::type> { }; template -struct is_binary_safe> : public is_binary_safe { }; +struct is_binary_safe> : public is_binary_safe::type> { }; + +template +struct is_binary_safe> : public is_binary_safe::type> { }; +template +struct is_binary_safe> : public is_binary_safe::type> { }; template @@ -98,7 +103,9 @@ constexpr bool check_binary_size(std::size_t size) noexcept { && (sizeof(T) == size) && (alignof(T) == 1) && std::is_standard_layout::value +#if !defined(MPT_LIBCXX_QUIRK_NO_HAS_UNIQUE_OBJECT_REPRESENTATIONS) && std::has_unique_object_representations::value +#endif && mpt::is_binary_safe::value; } @@ -239,6 +246,26 @@ struct as_raw_memory_impl { } }; +template +struct as_raw_memory_impl> { + inline mpt::const_byte_span operator()(const mpt::span & v) const { + static_assert(mpt::is_binary_safe::type>::value); + return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); + } + inline mpt::byte_span operator()(const mpt::span & v) const { + static_assert(mpt::is_binary_safe::type>::value); + return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); + } +}; + +template +struct as_raw_memory_impl> { + inline mpt::const_byte_span operator()(const mpt::span & v) const { + static_assert(mpt::is_binary_safe::type>::value); + return mpt::as_span(reinterpret_cast(v.data()), v.size() * sizeof(T)); + } +}; + // In order to be able to partially specialize it, // as_raw_memory is implemented via a class template. // Do not overload or specialize as_raw_memory directly. diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/namespace.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/namespace.hpp index 36b7e5cc4..b08e25943 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/namespace.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/namespace.hpp @@ -31,21 +31,33 @@ #if MPT_LIBC_GENERIC #define MPT_VERSION_ABI_LIBC _ #elif MPT_LIBC_MS -#ifdef _DLL -#ifdef _DEBUG +#if MPT_LIBC_MS_SHARED +#ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MDd #else #define MPT_VERSION_ABI_LIBC MDr #endif -#else -#ifdef _DEBUG +#elif MPT_LIBC_MS_STATIC +#ifdef MPT_LIBC_MS_DEBUG #define MPT_VERSION_ABI_LIBC MTd #else #define MPT_VERSION_ABI_LIBC MTr #endif +#else +#ifdef MPT_LIBC_MS_DEBUG +#define MPT_VERSION_ABI_LIBC Md +#else +#define MPT_VERSION_ABI_LIBC Mr +#endif #endif #elif MPT_LIBC_GLIBC #define MPT_VERSION_ABI_LIBC G +#elif MPT_LIBC_MINGW +#define MPT_VERSION_ABI_LIBC MW +#elif MPT_LIBC_BIONIC +#define MPT_VERSION_ABI_LIBC B +#elif MPT_LIBC_APPLE +#define MPT_VERSION_ABI_LIBC A #else #define MPT_VERSION_ABI_LIBC _ #endif diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/pointer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/pointer.hpp index b6fd3f28d..be1da99e4 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/pointer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/pointer.hpp @@ -5,6 +5,7 @@ +#include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" #include @@ -46,6 +47,27 @@ constexpr Tdst pointer_cast(const Tsrc & src) noexcept { } +template +class void_ptr { +private: + T * m_ptr = nullptr; +public: + MPT_FORCEINLINE explicit void_ptr(void * ptr) + : m_ptr(reinterpret_cast(ptr)) { + return; + } + MPT_FORCEINLINE T & operator*() { + return *m_ptr; + } + MPT_FORCEINLINE T * operator->() { + return m_ptr; + } + MPT_FORCEINLINE operator void *() { + return m_ptr; + } +}; + + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/secure.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/secure.hpp index 80b3519de..3e2316a99 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/secure.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/secure.hpp @@ -22,6 +22,20 @@ inline namespace MPT_INLINE_NS { +// C23 memset_explicit +inline MPT_NOINLINE void * memset_explicit(void * const dst, int const value, std::size_t const len) noexcept { + std::atomic_thread_fence(std::memory_order_seq_cst); + volatile unsigned char * volatile p = static_cast(dst); + std::atomic_thread_fence(std::memory_order_seq_cst); + for (volatile std::size_t i = 0; i < len; ++i) { + p[i] = static_cast(value); + } + std::atomic_thread_fence(std::memory_order_seq_cst); + return dst; +} + + + namespace secure { diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_arithmetic_shift.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_arithmetic_shift.hpp index d0a4330b7..9f6ef75e9 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_arithmetic_shift.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_arithmetic_shift.hpp @@ -33,69 +33,75 @@ MPT_TEST_GROUP_INLINE("mpt/base/arithmetic_shift") #pragma clang diagnostic pop #endif { - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 1), mpt::rshift_signed_standard(-32768, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 1), mpt::rshift_signed_standard(-32767, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 1), mpt::rshift_signed_standard(-32766, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 1), mpt::rshift_signed_standard(-2, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_standard(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_standard(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_standard(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 1), mpt::rshift_signed_standard(2, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 1), mpt::rshift_signed_standard(32766, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 1), mpt::rshift_signed_standard(32767, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 14), mpt::rshift_signed_standard(-32768, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 14), mpt::rshift_signed_standard(-32767, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 14), mpt::rshift_signed_standard(-32766, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 14), mpt::rshift_signed_standard(-2, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 14), mpt::rshift_signed_standard(-1, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 14), mpt::rshift_signed_standard(0, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 14), mpt::rshift_signed_standard(1, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 14), mpt::rshift_signed_standard(2, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 14), mpt::rshift_signed_standard(32766, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 14), mpt::rshift_signed_standard(32767, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 15), mpt::rshift_signed_standard(-32768, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 15), mpt::rshift_signed_standard(-32767, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 15), mpt::rshift_signed_standard(-32766, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 15), mpt::rshift_signed_standard(-2, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 15), mpt::rshift_signed_standard(-1, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 15), mpt::rshift_signed_standard(0, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 15), mpt::rshift_signed_standard(1, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 15), mpt::rshift_signed_standard(2, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 15), mpt::rshift_signed_standard(32766, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 15), mpt::rshift_signed_standard(32767, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 1), mpt::rshift_signed_portable(-32768, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 1), mpt::rshift_signed_portable(-32767, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 1), mpt::rshift_signed_portable(-32766, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 1), mpt::rshift_signed_portable(-2, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_portable(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_portable(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_portable(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 1), mpt::rshift_signed_portable(2, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 1), mpt::rshift_signed_portable(32766, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 1), mpt::rshift_signed_portable(32767, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 14), mpt::rshift_signed_portable(-32768, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 14), mpt::rshift_signed_portable(-32767, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 14), mpt::rshift_signed_portable(-32766, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 14), mpt::rshift_signed_portable(-2, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 14), mpt::rshift_signed_portable(-1, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 14), mpt::rshift_signed_portable(0, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 14), mpt::rshift_signed_portable(1, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 14), mpt::rshift_signed_portable(2, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 14), mpt::rshift_signed_portable(32766, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 14), mpt::rshift_signed_portable(32767, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 15), mpt::rshift_signed_portable(-32768, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 15), mpt::rshift_signed_portable(-32767, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32766, 15), mpt::rshift_signed_portable(-32766, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-2, 15), mpt::rshift_signed_portable(-2, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 15), mpt::rshift_signed_portable(-1, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 15), mpt::rshift_signed_portable(0, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 15), mpt::rshift_signed_portable(1, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(2, 15), mpt::rshift_signed_portable(2, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32766, 15), mpt::rshift_signed_portable(32766, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(32767, 15), mpt::rshift_signed_portable(32767, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 1), mpt::lshift_signed_standard(-32768, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 1), mpt::lshift_signed_standard(-32767, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 1), mpt::lshift_signed_standard(-32766, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 1), mpt::lshift_signed_standard(-2, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_standard(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_standard(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_standard(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 1), mpt::lshift_signed_standard(2, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 1), mpt::lshift_signed_standard(32766, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 1), mpt::lshift_signed_standard(32767, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 14), mpt::lshift_signed_standard(-32768, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 14), mpt::lshift_signed_standard(-32767, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 14), mpt::lshift_signed_standard(-32766, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 14), mpt::lshift_signed_standard(-2, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 14), mpt::lshift_signed_standard(-1, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 14), mpt::lshift_signed_standard(0, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 14), mpt::lshift_signed_standard(1, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 14), mpt::lshift_signed_standard(2, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 14), mpt::lshift_signed_standard(32766, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 14), mpt::lshift_signed_standard(32767, 14)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 15), mpt::lshift_signed_standard(-32768, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 15), mpt::lshift_signed_standard(-32767, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 15), mpt::lshift_signed_standard(-32766, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 15), mpt::lshift_signed_standard(-2, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 15), mpt::lshift_signed_standard(-1, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 15), mpt::lshift_signed_standard(0, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 15), mpt::lshift_signed_standard(1, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 15), mpt::lshift_signed_standard(2, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 15), mpt::lshift_signed_standard(32766, 15)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 15), mpt::lshift_signed_standard(32767, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 1), mpt::lshift_signed_portable(-32768, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 1), mpt::lshift_signed_portable(-32767, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 1), mpt::lshift_signed_portable(-32766, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 1), mpt::lshift_signed_portable(-2, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_portable(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_portable(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_portable(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 1), mpt::lshift_signed_portable(2, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 1), mpt::lshift_signed_portable(32766, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 1), mpt::lshift_signed_portable(32767, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 14), mpt::lshift_signed_portable(-32768, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 14), mpt::lshift_signed_portable(-32767, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 14), mpt::lshift_signed_portable(-32766, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 14), mpt::lshift_signed_portable(-2, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 14), mpt::lshift_signed_portable(-1, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 14), mpt::lshift_signed_portable(0, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 14), mpt::lshift_signed_portable(1, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 14), mpt::lshift_signed_portable(2, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 14), mpt::lshift_signed_portable(32766, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 14), mpt::lshift_signed_portable(32767, 14)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32768, 15), mpt::lshift_signed_portable(-32768, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32767, 15), mpt::lshift_signed_portable(-32767, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-32766, 15), mpt::lshift_signed_portable(-32766, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-2, 15), mpt::lshift_signed_portable(-2, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 15), mpt::lshift_signed_portable(-1, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 15), mpt::lshift_signed_portable(0, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 15), mpt::lshift_signed_portable(1, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(2, 15), mpt::lshift_signed_portable(2, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 15), mpt::lshift_signed_portable(32766, 15)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 15), mpt::lshift_signed_portable(32767, 15)); -#if MPT_COMPILER_SHIFT_SIGNED +#if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED + +#if MPT_COMPILER_GCC + // +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-negative-value" +#endif // MPT_COMPILER_GCC MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32768, 1), (-32768) >> 1); MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-32767, 1), (-32767) >> 1); @@ -159,157 +165,181 @@ MPT_TEST_GROUP_INLINE("mpt/base/arithmetic_shift") MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32766, 15), (32766) << 15); MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(32767, 15), (32767) << 15); -#endif - - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_standard(0 - 0x80000000, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_standard(-0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_standard(-0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_standard(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_standard(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_standard(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_standard(0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_standard(0x7fffffff, 1)); - - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_standard(0 - 0x80000000, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_standard(-0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_standard(-0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_standard(-1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_standard(0, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_standard(1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_standard(0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_standard(0x7fffffff, 31)); - - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_standard(0 - 0x80000000, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_standard(-0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_standard(-0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_standard(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_standard(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_standard(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_standard(0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_standard(0x7fffffff, 1)); - - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_standard(0 - 0x80000000, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_standard(-0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_standard(-0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_standard(-1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_standard(0, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_standard(1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_standard(0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_standard(0x7fffffff, 31)); - -#if MPT_COMPILER_SHIFT_SIGNED - - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_undefined(0 - 0x80000000, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_undefined(-0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_undefined(-0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_undefined(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_undefined(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_undefined(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_undefined(0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_undefined(0x7fffffff, 1)); - - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_undefined(0 - 0x80000000, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_undefined(-0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_undefined(-0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_undefined(-1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_undefined(0, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_undefined(1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_undefined(0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_undefined(0x7fffffff, 31)); - - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_undefined(0 - 0x80000000, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_undefined(-0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_undefined(-0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_undefined(-1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_undefined(0, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_undefined(1, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_undefined(0x7ffffffe, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_undefined(0x7fffffff, 1)); - - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_undefined(0 - 0x80000000, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_undefined(-0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_undefined(-0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_undefined(-1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_undefined(0, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_undefined(1, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_undefined(0x7ffffffe, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_undefined(0x7fffffff, 31)); +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC #endif - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_standard(0ull - 0x8000000000000000ull, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_standard(-0x7fffffffffffffffll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_standard(-0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_standard(-1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_standard(0ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_standard(1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_standard(0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_standard(0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_portable(0 - 0x80000000, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_portable(-0x7fffffff, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_portable(-0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_portable(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_portable(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_portable(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_portable(0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_portable(0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_standard(0ull - 0x8000000000000000ull, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_standard(-0x7fffffffffffffffll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_standard(-0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_standard(-1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_standard(0ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_standard(1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_standard(0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_standard(0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_portable(0 - 0x80000000, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_portable(-0x7fffffff, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_portable(-0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_portable(-1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_portable(0, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_portable(1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_portable(0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_portable(0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_standard(0ull - 0x8000000000000000ull, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_standard(-0x7fffffffffffffffll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_standard(-0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_standard(-1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_standard(0ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_standard(1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_standard(0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_standard(0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_portable(0 - 0x80000000, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_portable(-0x7fffffff, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_portable(-0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_portable(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_portable(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_portable(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_portable(0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_portable(0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_standard(0ull - 0x8000000000000000ull, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_standard(-0x7fffffffffffffffll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_standard(-0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_standard(-1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_standard(0ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_standard(1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_standard(0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_standard(0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_portable(0 - 0x80000000, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_portable(-0x7fffffff, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_portable(-0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_portable(-1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_portable(0, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_portable(1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_portable(0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_portable(0x7fffffff, 31)); -#if MPT_COMPILER_SHIFT_SIGNED +#if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_undefined(0ull - 0x8000000000000000ull, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_undefined(-0x7fffffffffffffffll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_undefined(-0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_undefined(-1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_undefined(0ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_undefined(1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_undefined(0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_undefined(0x7fffffffffffffffll, 1)); +#if MPT_COMPILER_GCC + // +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-negative-value" +#endif // MPT_COMPILER_GCC - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_undefined(0ull - 0x8000000000000000ull, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_undefined(-0x7fffffffffffffffll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_undefined(-0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_undefined(-1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_undefined(0ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_undefined(1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_undefined(0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_undefined(0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 1), mpt::rshift_signed_cxx20(0 - 0x80000000, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 1), mpt::rshift_signed_cxx20(-0x7fffffff, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 1), mpt::rshift_signed_cxx20(-0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 1), mpt::rshift_signed_cxx20(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 1), mpt::rshift_signed_cxx20(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 1), mpt::rshift_signed_cxx20(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 1), mpt::rshift_signed_cxx20(0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 1), mpt::rshift_signed_cxx20(0x7fffffff, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_undefined(0ull - 0x8000000000000000ull, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_undefined(-0x7fffffffffffffffll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_undefined(-0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_undefined(-1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_undefined(0ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_undefined(1ll, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_undefined(0x7ffffffffffffffell, 1)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_undefined(0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0 - 0x80000000, 31), mpt::rshift_signed_cxx20(0 - 0x80000000, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffff, 31), mpt::rshift_signed_cxx20(-0x7fffffff, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffe, 31), mpt::rshift_signed_cxx20(-0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1, 31), mpt::rshift_signed_cxx20(-1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0, 31), mpt::rshift_signed_cxx20(0, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1, 31), mpt::rshift_signed_cxx20(1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffe, 31), mpt::rshift_signed_cxx20(0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffff, 31), mpt::rshift_signed_cxx20(0x7fffffff, 31)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_undefined(0ull - 0x8000000000000000ull, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_undefined(-0x7fffffffffffffffll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_undefined(-0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_undefined(-1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_undefined(0ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_undefined(1ll, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_undefined(0x7ffffffffffffffell, 63)); - MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_undefined(0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 1), mpt::lshift_signed_cxx20(0 - 0x80000000, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 1), mpt::lshift_signed_cxx20(-0x7fffffff, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 1), mpt::lshift_signed_cxx20(-0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 1), mpt::lshift_signed_cxx20(-1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 1), mpt::lshift_signed_cxx20(0, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 1), mpt::lshift_signed_cxx20(1, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 1), mpt::lshift_signed_cxx20(0x7ffffffe, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 1), mpt::lshift_signed_cxx20(0x7fffffff, 1)); + + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0 - 0x80000000, 31), mpt::lshift_signed_cxx20(0 - 0x80000000, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffff, 31), mpt::lshift_signed_cxx20(-0x7fffffff, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffe, 31), mpt::lshift_signed_cxx20(-0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1, 31), mpt::lshift_signed_cxx20(-1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0, 31), mpt::lshift_signed_cxx20(0, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1, 31), mpt::lshift_signed_cxx20(1, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffe, 31), mpt::lshift_signed_cxx20(0x7ffffffe, 31)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffff, 31), mpt::lshift_signed_cxx20(0x7fffffff, 31)); + +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC + +#endif + + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_portable(0ull - 0x8000000000000000ull, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_portable(-0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_portable(-0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_portable(-1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_portable(0ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_portable(1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_portable(0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_portable(0x7fffffffffffffffll, 1)); + + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_portable(0ull - 0x8000000000000000ull, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_portable(-0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_portable(-0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_portable(-1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_portable(0ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_portable(1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_portable(0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_portable(0x7fffffffffffffffll, 63)); + + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_portable(0ull - 0x8000000000000000ull, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_portable(-0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_portable(-0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_portable(-1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_portable(0ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_portable(1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_portable(0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_portable(0x7fffffffffffffffll, 1)); + + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_portable(0ull - 0x8000000000000000ull, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_portable(-0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_portable(-0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_portable(-1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_portable(0ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_portable(1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_portable(0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_portable(0x7fffffffffffffffll, 63)); + +#if MPT_CXX_AT_LEAST(20) || MPT_COMPILER_SHIFT_SIGNED + +#if MPT_COMPILER_GCC + // +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-negative-value" +#endif // MPT_COMPILER_GCC + + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 1), mpt::rshift_signed_cxx20(0ull - 0x8000000000000000ull, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 1), mpt::rshift_signed_cxx20(-0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 1), mpt::rshift_signed_cxx20(-0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 1), mpt::rshift_signed_cxx20(-1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 1), mpt::rshift_signed_cxx20(0ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 1), mpt::rshift_signed_cxx20(1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 1), mpt::rshift_signed_cxx20(0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 1), mpt::rshift_signed_cxx20(0x7fffffffffffffffll, 1)); + + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ull - 0x8000000000000000ull, 63), mpt::rshift_signed_cxx20(0ull - 0x8000000000000000ull, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7fffffffffffffffll, 63), mpt::rshift_signed_cxx20(-0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-0x7ffffffffffffffell, 63), mpt::rshift_signed_cxx20(-0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(-1ll, 63), mpt::rshift_signed_cxx20(-1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0ll, 63), mpt::rshift_signed_cxx20(0ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(1ll, 63), mpt::rshift_signed_cxx20(1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7ffffffffffffffell, 63), mpt::rshift_signed_cxx20(0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::rshift_signed(0x7fffffffffffffffll, 63), mpt::rshift_signed_cxx20(0x7fffffffffffffffll, 63)); + + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 1), mpt::lshift_signed_cxx20(0ull - 0x8000000000000000ull, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 1), mpt::lshift_signed_cxx20(-0x7fffffffffffffffll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 1), mpt::lshift_signed_cxx20(-0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 1), mpt::lshift_signed_cxx20(-1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 1), mpt::lshift_signed_cxx20(0ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 1), mpt::lshift_signed_cxx20(1ll, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 1), mpt::lshift_signed_cxx20(0x7ffffffffffffffell, 1)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 1), mpt::lshift_signed_cxx20(0x7fffffffffffffffll, 1)); + + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ull - 0x8000000000000000ull, 63), mpt::lshift_signed_cxx20(0ull - 0x8000000000000000ull, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7fffffffffffffffll, 63), mpt::lshift_signed_cxx20(-0x7fffffffffffffffll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-0x7ffffffffffffffell, 63), mpt::lshift_signed_cxx20(-0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(-1ll, 63), mpt::lshift_signed_cxx20(-1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0ll, 63), mpt::lshift_signed_cxx20(0ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(1ll, 63), mpt::lshift_signed_cxx20(1ll, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7ffffffffffffffell, 63), mpt::lshift_signed_cxx20(0x7ffffffffffffffell, 63)); + MPT_TEST_EXPECT_EQUAL(mpt::lshift_signed(0x7fffffffffffffffll, 63), mpt::lshift_signed_cxx20(0x7fffffffffffffffll, 63)); + +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC #endif } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_bit.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_bit.hpp index 3dcf232d9..e2e54eb5d 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_bit.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/tests/tests_base_bit.hpp @@ -12,6 +12,8 @@ #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" +#include + namespace mpt { @@ -211,6 +213,16 @@ MPT_TEST_GROUP_INLINE("mpt/base/bit") MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000002u), 1); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000001u), 1); MPT_TEST_EXPECT_EQUAL(mpt::lower_bound_entropy_bits(0x00000000u), 0); + + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint8(0x12)), 0x12); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint16(0x1234)), 0x3412); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint32(0x12345678u)), 0x78563412u); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(uint64(0x123456789abcdef0ull)), 0xf0debc9a78563412ull); + + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int8(std::numeric_limits::min())), std::numeric_limits::min()); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int16(std::numeric_limits::min())), int16(0x80)); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int32(std::numeric_limits::min())), int32(0x80)); + MPT_TEST_EXPECT_EQUAL(mpt::byteswap(int64(std::numeric_limits::min())), int64(0x80)); } } // namespace bit diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/utility.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/utility.hpp index 7087a6a25..3ef9a8888 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/base/utility.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/base/utility.hpp @@ -6,12 +6,14 @@ #include "mpt/base/detect_compiler.hpp" +#include "mpt/base/detect_libcxx.hpp" #include "mpt/base/namespace.hpp" #if MPT_CXX_BEFORE(20) #include "mpt/base/saturate_cast.hpp" #endif +#include #include #include @@ -23,7 +25,15 @@ namespace mpt { inline namespace MPT_INLINE_NS { -#if MPT_CXX_AT_LEAST(20) && !MPT_CLANG_BEFORE(13, 0, 0) + +template +MPT_CONSTEXPRINLINE Tdst c_cast(Tsrc && x) { + return (Tdst)std::forward(x); +} + + + +#if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_LLVM_BEFORE(13000) using std::in_range; @@ -64,8 +74,7 @@ struct value_initializer { template struct value_initializer { inline void operator()(T (&a)[N]) { - for (auto & e : a) - { + for (auto & e : a) { value_initializer{}(e); } } @@ -76,9 +85,22 @@ inline void reset(T & x) { value_initializer{}(x); } +template +void reset(T & x, Targs &&... args) { + x = T{std::forward(args)...}; +} -#if MPT_CXX_AT_LEAST(20) && !MPT_CLANG_BEFORE(13, 0, 0) + +template +void reconstruct(T & x, Targs &&... args) { + x.~T(); + new (&x) T{std::forward(args)...}; +} + + + +#if MPT_CXX_AT_LEAST(20) && !MPT_LIBCXX_LLVM_BEFORE(13000) using std::cmp_equal; using std::cmp_greater; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/compiler.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/compiler.hpp new file mode 100644 index 000000000..01ce1bec6 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/compiler.hpp @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_CHECK_COMPILER_HPP +#define MPT_CHECK_COMPILER_HPP + +#include "mpt/base/detect_compiler.hpp" +#include "mpt/base/detect_quirks.hpp" +#include "mpt/base/compiletime_warning.hpp" + +#ifndef MPT_CHECK_CXX_IGNORE_PREPROCESSOR +#if defined(MPT_COMPILER_QUIRK_MSVC_OLD_PREPROCESSOR) +MPT_WARNING("C++ preprocessor is not standard conformings.") +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_FASTMATH +#if MPT_COMPILER_MSVC +#if (defined(_M_FP_FAST) && (_M_FP_FAST == 1)) +MPT_WARNING("C++ compiler has fast-math support enabled. This is not standard-conforming.") +#endif +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG +#if (defined(__FAST_MATH__) && (__FAST_MATH__ == 1)) +MPT_WARNING("C++ compiler has fast-math support enabled. This is not standard-conforming.") +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_FINITEMATH +#if MPT_COMPILER_MSVC +#if (defined(_M_FP_FAST) && (_M_FP_FAST == 1)) +MPT_WARNING("C++ compiler assumes finite math only. This is not standard-conforming.") +#endif +#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG +#if (defined(__FINITE_MATH_ONLY__) && (__FINITE_MATH_ONLY__ == 1)) +MPT_WARNING("C++ compiler assumes finite math only. This is not standard-conforming.") +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_EXCEPTIONS +#if MPT_COMPILER_GCC +#if (!defined(__EXCEPTIONS) || (__EXCEPTIONS != 1)) +MPT_WARNING("C++ compiler has no exception support.") +#endif +#elif MPT_COMPILER_CLANG && !defined(_MSC_VER) +#if (!defined(__EXCEPTIONS) || (__EXCEPTIONS != 1)) +MPT_WARNING("C++ compiler has no exception support.") +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_RTTI +#if MPT_COMPILER_MSVC +#if (!defined(_CPPRTTI) || (_CPPRTTI != 1)) +MPT_WARNING("C++ compiler has no RTTI support.") +#endif +#elif MPT_COMPILER_GCC +#if (!defined(__GXX_RTTI) || (__GXX_RTTI != 1)) +MPT_WARNING("C++ compiler has no RTTI support.") +#endif +#elif MPT_COMPILER_CLANG && !defined(_MSC_VER) +#if (!defined(__GXX_RTTI) || (__GXX_RTTI != 1)) +MPT_WARNING("C++ compiler has no RTTI support.") +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_UNICODE +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +#if (!defined(__STDC_ISO_10646__) || (__STDC_ISO_10646__ <= 198700L)) +#if !MPT_COMPILER_MSVC && !MPT_COMPILER_GCC && !MPT_COMPILER_CLANG +// Disabled for all known compilers, as none of them defines __STDC_ISO_10646__, even though all of them provide Unicode wchar_t. +MPT_WARNING("C++ compiler uses non-Unicode wchar_t.") +#endif +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_EBCDIC +#if defined(__STDC_MB_MIGHT_NEQ_WC__) && (__STDC_MB_MIGHT_NEQ_WC__ == 1) +#if !(MPT_COMPILER_CLANG && MPT_OS_FREEBSD) +// Disabled on FreeBSD because . +MPT_WARNING("C++ compiler uses a weird 8bit charset, maybe EBCDIC.") +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_NO_STDCPP_THREADS +#if MPT_PLATFORM_MULTITHREADED +#if !defined(MPT_COMPILER_QUIRK_NO_STDCPP_THREADS) +#if !defined(__STDCPP_THREADS__) +MPT_WARNING("C++ __STDCPP_THREADS__ is not defined. Non-conforming compiler detected.") +#else +#if (__STDCPP_THREADS__ != 1) +MPT_WARNING("C++ compiler has no thread support.") +#endif +#endif +#endif +#endif +#endif + +#ifndef MPT_CHECK_CXX_IGNORE_WARNING_SINGLETHREADED_THREADSAFE_STATICS +#if !MPT_PLATFORM_MULTITHREADED +#if MPT_CXX_AT_LEAST(20) && MPT_COMPILER_GCC +#if (defined(__cpp_threadsafe_static_init) && (__cpp_threadsafe_static_init >= 200806L)) +MPT_WARNING("C++ compiler provides threadsafe initialization of static variables, however the platform is single-threaded.") +#endif +#endif +#endif +#endif + +#endif // MPT_CHECK_COMPILER_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp index 89a978348..8e3789991 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/libc.hpp @@ -3,37 +3,29 @@ #ifndef MPT_CHECK_LIBC_HPP #define MPT_CHECK_LIBC_HPP -#include "mpt/base/detect_os.hpp" +#include "mpt/base/detect_libc.hpp" +#include "mpt/base/detect_quirks.hpp" #include "mpt/base/compiletime_warning.hpp" -#ifndef __STDC_CONSTANT_MACROS -#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_STDC_CONSTANT_MACROS -MPT_WARNING("C stdlib does not provide constant macros. Please #define __STDC_CONSTANT_MACROS.") +#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_MTRT +#if MPT_PLATFORM_MULTITHREADED +#if MPT_LIBC_MINGW +// MinGW only has `#define _MT` in header files instead of `#define _MT 1`. +#if !defined(_MT) +MPT_WARNING("C stdlib is not multi-threaded.") #endif +#elif MPT_LIBC_MS +#if defined(_MT) +#if (_MT != 1) +MPT_WARNING("C stdlib is not multi-threaded.") #endif - -#ifndef __STDC_FORMAT_MACROS -#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_STDC_FORMAT_MACROS -MPT_WARNING("C stdlib does not provide limit macros. Please #define __STDC_FORMAT_MACROS.") +#else +MPT_WARNING("C stdlib is not multi-threaded.") #endif -#endif - -#ifndef __STDC_LIMIT_MACROS -#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_STDC_LIMIT_MACROS -MPT_WARNING("C stdlib does not provide limit macros. Please #define __STDC_LIMIT_MACROS.") -#endif -#endif - -#ifndef _USE_MATH_DEFINES -#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_USE_MATH_DEFINES -MPT_WARNING("C stdlib does not provide math constants. Please #define _USE_MATH_DEFINES.") -#endif -#endif - -#if MPT_LIBC_GLIBC -#if !defined(_FILE_OFFSET_BITS) -#ifndef MPT_CHECK_LIBC_IGNORE_WARNING_NO_FILE_OFFSET_BITS -MPT_WARNING("C stdlib may not provide 64bit std::FILE access. Please #define _FILE_OFFSET_BITS=64.") +//#elif !MPT_LIBC_MS && !MPT_LIBC_MINGW && !MPT_LIBC_GENERIC +//#if (!defined(_REENTRANT) || (_REENTRANT != 1)) +//MPT_WARNING("C stdlib is not multi-threaded.") +//#endif #endif #endif #endif diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp index b6a05f924..fea40114b 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/check/windows.hpp @@ -8,10 +8,16 @@ #if MPT_OS_WINDOWS -#ifndef UNICODE #ifndef MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_UNICODE +#if MPT_OS_WINDOWS_WINNT +#ifndef UNICODE MPT_WARNING("windows.h uses MBCS TCHAR. Please #define UNICODE.") #endif +#elif MPT_OS_WINDOWS_WIN9X +#ifdef UNICODE +MPT_WARNING("Targeting Win9x but windows.h uses UNICODE TCHAR. Please do not #define UNICODE.") +#endif +#endif #endif #ifndef NOMINMAX diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/floatingpoint.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/floatingpoint.hpp index 7eaff1593..b90e4df0e 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/floatingpoint.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/floatingpoint.hpp @@ -10,6 +10,7 @@ #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/endian/type_traits.hpp" #include @@ -143,6 +144,10 @@ public: MPT_FORCEINLINE explicit IEEE754binary32Emulated(float32 f) { SetInt32(EncodeIEEE754binary32(f)); } + MPT_FORCEINLINE IEEE754binary32Emulated & operator=(float32 f) { + SetInt32(EncodeIEEE754binary32(f)); + return *this; + } // b0...b3 are in memory order, i.e. depend on the endianness of this type // little endian: (0x00,0x00,0x80,0x3f) // big endian: (0x3f,0x80,0x00,0x00) @@ -194,6 +199,10 @@ public: MPT_FORCEINLINE explicit IEEE754binary64Emulated(float64 f) { SetInt64(EncodeIEEE754binary64(f)); } + MPT_FORCEINLINE IEEE754binary64Emulated & operator=(float64 f) { + SetInt64(EncodeIEEE754binary64(f)); + return *this; + } MPT_FORCEINLINE explicit IEEE754binary64Emulated(std::byte b0, std::byte b1, std::byte b2, std::byte b3, std::byte b4, std::byte b5, std::byte b6, std::byte b7) { bytes[0] = b0; bytes[1] = b1; @@ -287,6 +296,10 @@ public: MPT_FORCEINLINE explicit IEEE754binary32Native(float32 f) { value = f; } + MPT_FORCEINLINE IEEE754binary32Native & operator=(float32 f) { + value = f; + return *this; + } // b0...b3 are in memory order, i.e. depend on the endianness of this type // little endian: (0x00,0x00,0x80,0x3f) // big endian: (0x3f,0x80,0x00,0x00) @@ -336,6 +349,10 @@ public: MPT_FORCEINLINE explicit IEEE754binary64Native(float64 f) { value = f; } + MPT_FORCEINLINE IEEE754binary64Native & operator=(float64 f) { + value = f; + return *this; + } MPT_FORCEINLINE explicit IEEE754binary64Native(std::byte b0, std::byte b1, std::byte b2, std::byte b3, std::byte b4, std::byte b5, std::byte b6, std::byte b7) { static_assert(endian == mpt::endian::little || endian == mpt::endian::big); if constexpr (endian == mpt::endian::little) { @@ -433,46 +450,24 @@ static_assert(sizeof(float64be_fast) == 8); -template -struct make_float_be { +template <> +struct make_endian { + using type = IEEE754binary32LE; }; template <> -struct make_float_be { - using type = IEEE754binary64BE; -}; - -template <> -struct make_float_be { +struct make_endian { using type = IEEE754binary32BE; }; -template -struct make_float_le { -}; - template <> -struct make_float_le { +struct make_endian { using type = IEEE754binary64LE; }; template <> -struct make_float_le { - using type = IEEE754binary32LE; -}; - -template -struct make_float_endian { -}; - -template -struct make_float_endian { - using type = typename make_float_le::type>::type; -}; - -template -struct make_float_endian { - using type = typename make_float_be::type>::type; +struct make_endian { + using type = IEEE754binary64BE; }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/int24.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/int24.hpp index cdab86179..d29a7a5f3 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/int24.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/int24.hpp @@ -6,9 +6,12 @@ #include "mpt/base/bit.hpp" +#include "mpt/base/integer.hpp" #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/endian/integer.hpp" +#include "mpt/endian/type_traits.hpp" #include #include @@ -39,13 +42,19 @@ struct uint24 { bytes[2] = mpt::byte_cast(static_cast((static_cast(other) >> 16) & 0xff)); } } - operator int() const noexcept { + operator unsigned int() const noexcept { MPT_MAYBE_CONSTANT_IF (mpt::endian_is_big()) { return (mpt::byte_cast(bytes[0]) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[2]); } else { return (mpt::byte_cast(bytes[2]) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[0]); } } + friend bool operator==(uint24 a, uint24 b) noexcept { + return static_cast(a) == static_cast(b); + } + friend bool operator!=(uint24 a, uint24 b) noexcept { + return static_cast(a) != static_cast(b); + } }; static_assert(sizeof(uint24) == 3); @@ -74,12 +83,127 @@ struct int24 { return (static_cast(mpt::byte_cast(bytes[2])) * 65536) + (mpt::byte_cast(bytes[1]) * 256) + mpt::byte_cast(bytes[0]); } } + friend bool operator==(int24 a, int24 b) noexcept { + return static_cast(a) == static_cast(b); + } + friend bool operator!=(int24 a, int24 b) noexcept { + return static_cast(a) != static_cast(b); + } }; static_assert(sizeof(int24) == 3); +template <> +struct packed_int_type { + using type = int32; +}; +template <> +struct packed_int_type { + using type = uint32; +}; + + + +template +MPT_CONSTEXPRINLINE std::array EndianEncode24(base_type val) noexcept { + static_assert(std::is_same::value || std::is_same::value); + static_assert(endian == mpt::endian::little || endian == mpt::endian::big); + static_assert(std::numeric_limits::is_integer); + if constexpr (endian == mpt::endian::native) { + std::array data{}; + for (std::size_t i = 0; i < sizeof(base_type); ++i) { + data[i] = val.bytes[i]; + } + return data; + } else { + return EndianEncodeImpl(val); + } +} + +template +MPT_CONSTEXPRINLINE base_type EndianDecode24(std::array data) noexcept { + static_assert(std::is_same::value || std::is_same::value); + static_assert(endian == mpt::endian::little || endian == mpt::endian::big); + static_assert(std::numeric_limits::is_integer); + if constexpr (endian == mpt::endian::native) { + base_type val = base_type(); + for (std::size_t i = 0; i < sizeof(base_type); ++i) { + val.bytes[i] = data[i]; + } + return val; + } else { + return EndianDecodeImpl(data); + } +} + + + +template <> +MPT_CONSTEXPRINLINE std::array EndianEncode(int24 val) noexcept { + return mpt::EndianEncode24(val); +} +template <> +MPT_CONSTEXPRINLINE int24 EndianDecode(std::array data) noexcept { + return mpt::EndianDecode24(data); +} +template <> +MPT_CONSTEXPRINLINE std::array EndianEncode(int24 val) noexcept { + return mpt::EndianEncode24(val); +} +template <> +MPT_CONSTEXPRINLINE int24 EndianDecode(std::array data) noexcept { + return mpt::EndianDecode24(data); +} + +template <> +MPT_CONSTEXPRINLINE std::array EndianEncode(uint24 val) noexcept { + return mpt::EndianEncode24(val); +} +template <> +MPT_CONSTEXPRINLINE uint24 EndianDecode(std::array data) noexcept { + return mpt::EndianDecode24(data); +} +template <> +MPT_CONSTEXPRINLINE std::array EndianEncode(uint24 val) noexcept { + return mpt::EndianEncode24(val); +} +template <> +MPT_CONSTEXPRINLINE uint24 EndianDecode(std::array data) noexcept { + return mpt::EndianDecode24(data); +} + + + +using int24le = packed; +using uint24le = packed; + +using int24be = packed; +using uint24be = packed; + +constexpr bool declare_binary_safe(const int24le &) { + return true; +} +constexpr bool declare_binary_safe(const uint24le &) { + return true; +} + +constexpr bool declare_binary_safe(const int24be &) { + return true; +} +constexpr bool declare_binary_safe(const uint24be &) { + return true; +} + +static_assert(mpt::check_binary_size(3)); +static_assert(mpt::check_binary_size(3)); + +static_assert(mpt::check_binary_size(3)); +static_assert(mpt::check_binary_size(3)); + + + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/integer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/integer.hpp index abc54b739..8854c4813 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/integer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/integer.hpp @@ -11,6 +11,7 @@ #include "mpt/base/macros.hpp" #include "mpt/base/memory.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/endian/type_traits.hpp" #include #include @@ -20,10 +21,6 @@ #include #include -#if MPT_COMPILER_MSVC -#include -#endif - namespace mpt { @@ -31,77 +28,14 @@ inline namespace MPT_INLINE_NS { -struct BigEndian_tag { - static constexpr mpt::endian endian = mpt::endian::big; -}; - -struct LittleEndian_tag { - static constexpr mpt::endian endian = mpt::endian::little; -}; - - - -constexpr inline uint16 constexpr_bswap16(uint16 x) noexcept { - return uint16(0) - | ((x >> 8) & 0x00FFu) - | ((x << 8) & 0xFF00u); -} - -constexpr inline uint32 constexpr_bswap32(uint32 x) noexcept { - return uint32(0) - | ((x & 0x000000FFu) << 24) - | ((x & 0x0000FF00u) << 8) - | ((x & 0x00FF0000u) >> 8) - | ((x & 0xFF000000u) >> 24); -} - -constexpr inline uint64 constexpr_bswap64(uint64 x) noexcept { - return uint64(0) - | (((x >> 0) & 0xffull) << 56) - | (((x >> 8) & 0xffull) << 48) - | (((x >> 16) & 0xffull) << 40) - | (((x >> 24) & 0xffull) << 32) - | (((x >> 32) & 0xffull) << 24) - | (((x >> 40) & 0xffull) << 16) - | (((x >> 48) & 0xffull) << 8) - | (((x >> 56) & 0xffull) << 0); -} - -#if MPT_COMPILER_GCC -#define MPT_bswap16 __builtin_bswap16 -#define MPT_bswap32 __builtin_bswap32 -#define MPT_bswap64 __builtin_bswap64 -#elif MPT_COMPILER_MSVC -#define MPT_bswap16 _byteswap_ushort -#define MPT_bswap32 _byteswap_ulong -#define MPT_bswap64 _byteswap_uint64 -#endif - -// No intrinsics available -#ifndef MPT_bswap16 -#define MPT_bswap16(x) mpt::constexpr_bswap16(x) -#endif -#ifndef MPT_bswap32 -#define MPT_bswap32(x) mpt::constexpr_bswap32(x) -#endif -#ifndef MPT_bswap64 -#define MPT_bswap64(x) mpt::constexpr_bswap64(x) -#endif - - - -template -MPT_CONSTEXPRINLINE std::array EndianEncode(T val) noexcept { - static_assert(Tendian::endian == mpt::endian::little || Tendian::endian == mpt::endian::big); - static_assert(std::numeric_limits::is_integer); - static_assert(!std::numeric_limits::is_signed); - static_assert(sizeof(T) == size); - using base_type = T; - using unsigned_base_type = typename std::make_unsigned::type; - using endian_type = Tendian; - unsigned_base_type uval = static_cast(val); - std::array data{}; - if constexpr (endian_type::endian == mpt::endian::little) { +template +MPT_CONSTEXPRINLINE std::array EndianEncodeImpl(base_type val) noexcept { + static_assert(endian == mpt::endian::little || endian == mpt::endian::big); + static_assert(std::numeric_limits::is_integer); + using unsigned_int_type = typename std::make_unsigned::type; + unsigned_int_type uval = static_cast(static_cast(val)); + std::array data{}; + if constexpr (endian == mpt::endian::little) { for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast(static_cast((uval >> (i * 8)) & 0xffu)); } @@ -113,170 +47,109 @@ MPT_CONSTEXPRINLINE std::array EndianEncode(T val) noexcept { return data; } -template -MPT_CONSTEXPRINLINE T EndianDecode(std::array data) noexcept { - static_assert(Tendian::endian == mpt::endian::little || Tendian::endian == mpt::endian::big); - static_assert(std::numeric_limits::is_integer); - static_assert(!std::numeric_limits::is_signed); - static_assert(sizeof(T) == size); - using base_type = T; - using unsigned_base_type = typename std::make_unsigned::type; - using endian_type = Tendian; +template +MPT_CONSTEXPRINLINE std::array EndianEncode(base_type val) noexcept { + return EndianEncodeImpl(val); +} + +template +MPT_CONSTEXPRINLINE base_type EndianDecodeImpl(std::array data) noexcept { + static_assert(endian == mpt::endian::little || endian == mpt::endian::big); + static_assert(std::numeric_limits::is_integer); + using unsigned_int_type = typename std::make_unsigned::type; base_type val = base_type(); - unsigned_base_type uval = unsigned_base_type(); - if constexpr (endian_type::endian == mpt::endian::little) { + unsigned_int_type uval = unsigned_int_type(); + if constexpr (endian == mpt::endian::little) { for (std::size_t i = 0; i < sizeof(base_type); ++i) { - uval |= static_cast(static_cast(data[i])) << (i * 8); + uval |= static_cast(static_cast(static_cast(data[i])) << (i * 8)); } } else { for (std::size_t i = 0; i < sizeof(base_type); ++i) { - uval |= static_cast(static_cast(data[(sizeof(base_type) - 1) - i])) << (i * 8); + uval |= static_cast(static_cast(static_cast(data[(sizeof(base_type) - 1) - i])) << (i * 8)); } } - val = static_cast(uval); + val = static_cast(static_cast(uval)); return val; } - -MPT_CONSTEXPR20_FUN uint64 SwapBytesImpl(uint64 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap64(value); - } else { - return MPT_bswap64(value); - } +template +MPT_CONSTEXPRINLINE base_type EndianDecode(std::array data) noexcept { + return EndianDecodeImpl(data); } -MPT_CONSTEXPR20_FUN uint32 SwapBytesImpl(uint32 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap32(value); - } else { - return MPT_bswap32(value); - } -} - -MPT_CONSTEXPR20_FUN uint16 SwapBytesImpl(uint16 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap16(value); - } else { - return MPT_bswap16(value); - } -} - -MPT_CONSTEXPR20_FUN int64 SwapBytesImpl(int64 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap64(value); - } else { - return MPT_bswap64(value); - } -} - -MPT_CONSTEXPR20_FUN int32 SwapBytesImpl(int32 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap32(value); - } else { - return MPT_bswap32(value); - } -} - -MPT_CONSTEXPR20_FUN int16 SwapBytesImpl(int16 value) noexcept { - MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - return mpt::constexpr_bswap16(value); - } else { - return MPT_bswap16(value); - } -} - -// Do NOT remove these overloads, even if they seem useless. -// We do not want risking to extend 8bit integers to int and then -// endian-converting and casting back to int. -// Thus these overloads. - -MPT_CONSTEXPR20_FUN uint8 SwapBytesImpl(uint8 value) noexcept { - return value; -} - -MPT_CONSTEXPR20_FUN int8 SwapBytesImpl(int8 value) noexcept { - return value; -} - -MPT_CONSTEXPR20_FUN char SwapBytesImpl(char value) noexcept { - return value; -} - -#undef MPT_bswap16 -#undef MPT_bswap32 -#undef MPT_bswap64 +template +struct packed_int_type { + using type = T; +}; // On-disk integer types with defined endianness and no alignemnt requirements // Note: To easily debug module loaders (and anything else that uses this // wrapper struct), you can use the Debugger Visualizers available in // build/vs/debug/ to conveniently view the wrapped contents. -template +template ::type> struct packed { public: using base_type = T; - using endian_type = Tendian; + using int_type = Tint; public: std::array data; public: MPT_CONSTEXPR20_FUN void set(base_type val) noexcept { - static_assert(std::numeric_limits::is_integer); + static_assert(std::numeric_limits::is_integer); MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - if constexpr (endian_type::endian == mpt::endian::big) { - typename std::make_unsigned::type uval = val; + if constexpr (endian == mpt::endian::big) { + typename std::make_unsigned::type uval = val; for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast((uval >> (8 * (sizeof(base_type) - 1 - i))) & 0xffu); } } else { - typename std::make_unsigned::type uval = val; + typename std::make_unsigned::type uval = val; for (std::size_t i = 0; i < sizeof(base_type); ++i) { data[i] = static_cast((uval >> (8 * i)) & 0xffu); } } } else { - if constexpr (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big) { - if constexpr (mpt::endian::native != endian_type::endian) { - val = mpt::SwapBytesImpl(val); + if constexpr (std::is_integral::value && (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)) { + if constexpr (mpt::endian::native != endian) { + val = mpt::byteswap(val); } std::memcpy(data.data(), &val, sizeof(val)); } else { - using unsigned_base_type = typename std::make_unsigned::type; - data = EndianEncode(val); + data = EndianEncode(val); } } } MPT_CONSTEXPR20_FUN base_type get() const noexcept { - static_assert(std::numeric_limits::is_integer); + static_assert(std::numeric_limits::is_integer); MPT_MAYBE_CONSTANT_IF (MPT_IS_CONSTANT_EVALUATED20()) { - if constexpr (endian_type::endian == mpt::endian::big) { - typename std::make_unsigned::type uval = 0; + if constexpr (endian == mpt::endian::big) { + typename std::make_unsigned::type uval = 0; for (std::size_t i = 0; i < sizeof(base_type); ++i) { - uval |= static_cast::type>(data[i]) << (8 * (sizeof(base_type) - 1 - i)); + uval |= static_cast::type>(static_cast::type>(data[i]) << (8 * (sizeof(base_type) - 1 - i))); } return static_cast(uval); } else { - typename std::make_unsigned::type uval = 0; + typename std::make_unsigned::type uval = 0; for (std::size_t i = 0; i < sizeof(base_type); ++i) { - uval |= static_cast::type>(data[i]) << (8 * i); + uval |= static_cast::type>(static_cast::type>(data[i]) << (8 * i)); } return static_cast(uval); } } else { - if constexpr (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big) { + if constexpr (std::is_integral::value && (mpt::endian::native == mpt::endian::little || mpt::endian::native == mpt::endian::big)) { base_type val = base_type(); std::memcpy(&val, data.data(), sizeof(val)); - if constexpr (mpt::endian::native != endian_type::endian) { - val = mpt::SwapBytesImpl(val); + if constexpr (mpt::endian::native != endian) { + val = mpt::byteswap(val); } return val; } else { - using unsigned_base_type = typename std::make_unsigned::type; - return EndianDecode(data); + return EndianDecode(data); } } } @@ -341,23 +214,23 @@ public: } }; -using int64le = packed; -using int32le = packed; -using int16le = packed; -using int8le = packed; -using uint64le = packed; -using uint32le = packed; -using uint16le = packed; -using uint8le = packed; +using int64le = packed; +using int32le = packed; +using int16le = packed; +using int8le = packed; +using uint64le = packed; +using uint32le = packed; +using uint16le = packed; +using uint8le = packed; -using int64be = packed; -using int32be = packed; -using int16be = packed; -using int8be = packed; -using uint64be = packed; -using uint32be = packed; -using uint16be = packed; -using uint8be = packed; +using int64be = packed; +using int32be = packed; +using int16be = packed; +using int8be = packed; +using uint64be = packed; +using uint32be = packed; +using uint16be = packed; +using uint8be = packed; constexpr bool declare_binary_safe(const int64le &) { return true; @@ -429,30 +302,18 @@ static_assert(mpt::check_binary_size(1)); -template -struct make_le { - using type = packed::type, LittleEndian_tag>; -}; - -template -struct make_be { - using type = packed::type, BigEndian_tag>; -}; - -template -struct make_endian { -}; - template struct make_endian { - using type = packed::type, LittleEndian_tag>; + using type = packed::type, mpt::endian::little>; }; template struct make_endian { - using type = packed::type, BigEndian_tag>; + using type = packed::type, mpt::endian::big>; }; + + template MPT_CONSTEXPR20_FUN auto as_le(T v) noexcept -> typename mpt::make_le::type>::type { typename mpt::make_le::type>::type res{}; @@ -467,6 +328,8 @@ MPT_CONSTEXPR20_FUN auto as_be(T v) noexcept -> typename mpt::make_be MPT_CONSTEXPR20_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept { Tpacked res{}; @@ -482,10 +345,10 @@ MPT_CONSTEXPR20_FUN Tpacked as_endian(typename Tpacked::base_type v) noexcept { namespace std { -template -class numeric_limits> : public std::numeric_limits { }; -template -class numeric_limits> : public std::numeric_limits { }; +template +class numeric_limits> : public std::numeric_limits { }; +template +class numeric_limits> : public std::numeric_limits { }; } // namespace std diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_int24.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_int24.hpp new file mode 100644 index 000000000..84b729c87 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_int24.hpp @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP +#define MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP + + + +#include "mpt/base/detect_compiler.hpp" +#include "mpt/base/integer.hpp" +#include "mpt/base/macros.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/endian/int24.hpp" +#include "mpt/endian/integer.hpp" +#include "mpt/test/test.hpp" +#include "mpt/test/test_macros.hpp" + +#include + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace tests { +namespace endian { +namespace integer { + +#if MPT_COMPILER_CLANG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" +#endif +MPT_TEST_GROUP_INLINE("mpt/endian/int24") +#if MPT_COMPILER_CLANG +#pragma clang diagnostic pop +#endif +{ + static_assert(std::numeric_limits::min() == std::numeric_limits::min()); + static_assert(std::numeric_limits::min() == std::numeric_limits::min()); + + { + int24le le24; + le24.set(int24(0x123456)); + int24be be24; + be24.set(int24(0x123456)); + MPT_TEST_EXPECT_EQUAL(le24, int24(0x123456)); + MPT_TEST_EXPECT_EQUAL(be24, int24(0x123456)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x56\x34\x12", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x12\x34\x56", 3), 0); + } + { + int24le le24; + le24.set(int24(-0x7fffff)); + int24be be24; + be24.set(int24(-0x7fffff)); + MPT_TEST_EXPECT_EQUAL(le24, int24(-0x7fffff)); + MPT_TEST_EXPECT_EQUAL(be24, int24(-0x7fffff)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x01\x00\x80", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x01", 3), 0); + } + { + int24le le24; + le24.set(int24(-0x000001)); + int24be be24; + be24.set(int24(-0x000001)); + MPT_TEST_EXPECT_EQUAL(le24, int24(-0x000001)); + MPT_TEST_EXPECT_EQUAL(be24, int24(-0x000001)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\xff", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\xff\xff\xff", 3), 0); + } + { + int24le le24; + le24.set(int24(0x7fffff)); + int24be be24; + be24.set(int24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(le24, int24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(be24, int24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\x7f", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x7f\xff\xff", 3), 0); + } + { + int24le le24; + le24.set(int24(-0x800000)); + int24be be24; + be24.set(int24(-0x800000)); + MPT_TEST_EXPECT_EQUAL(le24, int24(-0x800000)); + MPT_TEST_EXPECT_EQUAL(be24, int24(-0x800000)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x00\x00\x80", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x00", 3), 0); + } + + { + uint24le le24; + le24.set(uint24(0x123456)); + uint24be be24; + be24.set(uint24(0x123456)); + MPT_TEST_EXPECT_EQUAL(le24, uint24(0x123456)); + MPT_TEST_EXPECT_EQUAL(be24, uint24(0x123456)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x56\x34\x12", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x12\x34\x56", 3), 0); + } + { + uint24le le24; + le24.set(uint24(0xffffff)); + uint24be be24; + be24.set(uint24(0xffffff)); + MPT_TEST_EXPECT_EQUAL(le24, uint24(0xffffff)); + MPT_TEST_EXPECT_EQUAL(be24, uint24(0xffffff)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\xff", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\xff\xff\xff", 3), 0); + } + { + uint24le le24; + le24.set(uint24(0x7fffff)); + uint24be be24; + be24.set(uint24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(le24, uint24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(be24, uint24(0x7fffff)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\xff\xff\x7f", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x7f\xff\xff", 3), 0); + } + { + uint24le le24; + le24.set(uint24(0x800000)); + uint24be be24; + be24.set(uint24(0x800000)); + MPT_TEST_EXPECT_EQUAL(le24, uint24(0x800000)); + MPT_TEST_EXPECT_EQUAL(be24, uint24(0x800000)); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&le24, "\x00\x00\x80", 3), 0); + MPT_TEST_EXPECT_EQUAL(std::memcmp(&be24, "\x80\x00\x00", 3), 0); + } +} + +} // namespace integer +} // namespace endian +} // namespace tests + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_ENDIAN_TESTS_ENDIAN_INT24_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_integer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_integer.hpp index 0511642ea..1c1ec0a2d 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_integer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/tests/tests_endian_integer.hpp @@ -72,16 +72,6 @@ MPT_TEST_GROUP_INLINE("mpt/endian/integer") MPT_CONSTEXPR20_VAR int32le foo = test_endian_constexpr::test(23); static_cast(foo); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(uint8(0x12)), 0x12); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(uint16(0x1234)), 0x3412); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(uint32(0x12345678u)), 0x78563412u); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(uint64(0x123456789abcdef0ull)), 0xf0debc9a78563412ull); - - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(int8(std::numeric_limits::min())), std::numeric_limits::min()); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(int16(std::numeric_limits::min())), int16(0x80)); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(int32(std::numeric_limits::min())), int32(0x80)); - MPT_TEST_EXPECT_EQUAL(mpt::SwapBytesImpl(int64(std::numeric_limits::min())), int64(0x80)); - // Packed integers with defined endianness { int8le le8; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/type_traits.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/type_traits.hpp new file mode 100644 index 000000000..af592fb10 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/endian/type_traits.hpp @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_ENDIAN_TYPE_TRAITS_HPP +#define MPT_ENDIAN_TYPE_TRAITS_HPP + + + +#include "mpt/base/bit.hpp" +#include "mpt/base/namespace.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +template +struct make_endian { +}; + +template +struct make_le { + using type = typename mpt::make_endian::type; +}; + +template +struct make_be { + using type = typename mpt::make_endian::type; +}; + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_ENDIAN_TYPE_TRAITS_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception.hpp new file mode 100644 index 000000000..2a824b2f0 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception.hpp @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_EXCEPTION_EXCEPTION_HPP +#define MPT_EXCEPTION_EXCEPTION_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/string/types.hpp" +#include "mpt/string_transcode/transcode.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +class exception_ustring_wrapper_base { +protected: + exception_ustring_wrapper_base() = default; + virtual ~exception_ustring_wrapper_base() = default; +public: + virtual mpt::ustring uwhat() const = 0; +}; + +template +class exception_ustring_wrapper : public T + , public virtual mpt::exception_ustring_wrapper_base { +private: + mpt::ustring m_what; +public: + exception_ustring_wrapper(mpt::ustring str) + : T(mpt::transcode(mpt::exception_encoding, str)) + , m_what(str) { + return; + } + ~exception_ustring_wrapper() override = default; + mpt::ustring uwhat() const override { + return m_what; + } +}; + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_EXCEPTION_EXCEPTION_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception_text.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception_text.hpp new file mode 100644 index 000000000..a40545dab --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/exception_text.hpp @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_EXCEPTION_EXCEPTION_TEXT_HPP +#define MPT_EXCEPTION_EXCEPTION_TEXT_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/exception/exception.hpp" +#include "mpt/string/types.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#include + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +template +inline Tstring get_exception_text(const std::exception & e) { + if (const mpt::exception_ustring_wrapper_base * pue = dynamic_cast(&e)) { + const mpt::exception_ustring_wrapper_base & ue = *pue; + mpt::ustring what = ue.uwhat(); + if (what.length() > 0) { + return mpt::transcode(std::move(what)); + } else if (typeid(ue).name() && (std::strlen(typeid(ue).name()) > 0)) { + return mpt::transcode(mpt::source_string{typeid(ue).name()}); + } else { + return mpt::transcode(mpt::source_string{"unknown exception name"}); + } + } else if (e.what() && (std::strlen(e.what()) > 0)) { + return mpt::transcode(mpt::exception_string{e.what()}); + } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { + return mpt::transcode(mpt::source_string{typeid(e).name()}); + } else { + return mpt::transcode(mpt::source_string{"unknown exception name"}); + } +} + +template <> +inline std::string get_exception_text(const std::exception & e) { + if (e.what() && (std::strlen(e.what()) > 0)) { + return std::string{e.what()}; + } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { + return std::string{typeid(e).name()}; + } else { + return std::string{"unknown exception name"}; + } +} + + + +template +inline Tstring get_current_exception_text() { + try { + throw; + } catch (const std::exception & e) { + return mpt::get_exception_text(e); + } catch (...) { + return mpt::transcode(mpt::source_string{"unknown exception"}); + } +} + +template <> +inline std::string get_current_exception_text() { + try { + throw; + } catch (const std::exception & e) { + return mpt::get_exception_text(e); + } catch (...) { + return std::string{"unknown exception"}; + } +} + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_EXCEPTION_EXCEPTION_TEXT_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/logic_error.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/logic_error.hpp new file mode 100644 index 000000000..04e19ac45 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/logic_error.hpp @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_EXCEPTION_LOGIC_ERROR_HPP +#define MPT_EXCEPTION_LOGIC_ERROR_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/exception/exception.hpp" + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +using logic_error = mpt::exception_ustring_wrapper; + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_EXCEPTION_LOGIC_ERROR_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/runtime_error.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/runtime_error.hpp new file mode 100644 index 000000000..477d3686f --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception/runtime_error.hpp @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_EXCEPTION_RUNTIME_ERROR_HPP +#define MPT_EXCEPTION_RUNTIME_ERROR_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/exception/exception.hpp" + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +using runtime_error = mpt::exception_ustring_wrapper; + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_EXCEPTION_RUNTIME_ERROR_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception_text/exception_text.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception_text/exception_text.hpp index 26d184944..e69de29bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/exception_text/exception_text.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/exception_text/exception_text.hpp @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ - -#ifndef MPT_EXCEPTION_TEXT_EXCEPTION_TEXT_HPP -#define MPT_EXCEPTION_TEXT_EXCEPTION_TEXT_HPP - - - -#include "mpt/base/namespace.hpp" -#include "mpt/string/types.hpp" -#include "mpt/string_transcode/transcode.hpp" - -#include - -#include - - - -namespace mpt { -inline namespace MPT_INLINE_NS { - - - -template -inline Tstring get_exception_text(const std::exception & e) { - if (e.what() && (std::strlen(e.what()) > 0)) { - return mpt::transcode(mpt::exception_string{e.what()}); - } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { - return mpt::transcode(mpt::source_string{typeid(e).name()}); - } else { - return mpt::transcode(mpt::source_string{"unknown exception name"}); - } -} - -template <> -inline std::string get_exception_text(const std::exception & e) { - if (e.what() && (std::strlen(e.what()) > 0)) { - return std::string{e.what()}; - } else if (typeid(e).name() && (std::strlen(typeid(e).name()) > 0)) { - return std::string{typeid(e).name()}; - } else { - return std::string{"unknown exception name"}; - } -} - - -template -inline Tstring get_current_exception_text() { - try { - throw; - } catch (const std::exception & e) { - return mpt::get_exception_text(e); - } catch (...) { - return mpt::transcode(mpt::source_string{"unknown exception"}); - } -} - -template <> -inline std::string get_current_exception_text() { - try { - throw; - } catch (const std::exception & e) { - return mpt::get_exception_text(e); - } catch (...) { - return std::string{"unknown exception"}; - } -} - - -} // namespace MPT_INLINE_NS -} // namespace mpt - - - -#endif // MPT_EXCEPTION_TEXT_EXCEPTION_TEXT_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/concat.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/concat.hpp new file mode 100644 index 000000000..f7384e334 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/concat.hpp @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_FORMAT_CONCAT_HPP +#define MPT_FORMAT_CONCAT_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/format/default_formatter.hpp" + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +template +inline Tstring concat(Ts &&... xs) { + return (default_formatter::template format(std::forward(xs)) + ...); +} + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_FORMAT_CONCAT_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/message.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/message.hpp index b4b0e9147..889d5e147 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/message.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/message.hpp @@ -33,11 +33,11 @@ public: } }; -template +template class message_formatter { -public: - using Tstring = typename mpt::make_string_type::type; +private: + using Tstringview = typename mpt::make_string_view_type::type; private: Tstring format; @@ -76,13 +76,13 @@ private: state = state::close_seen; } else { state = state::text; - traits::append(result, 1, c); // output c here + traits::append(result, c); // output c here } break; case state::open_seen: if (c == char_type('{')) { state = state::text; - traits::append(result, 1, char_type('{')); // output { here + traits::append(result, char_type('{')); // output { here } else if (c == char_type('}')) { state = state::text; unnumbered_args = true; @@ -135,7 +135,7 @@ private: state = state::error; } else if (c == char_type('}')) { state = state::text; - traits::append(result, 1, char_type('}')); // output } here + traits::append(result, char_type('}')); // output } here } else { state = state::error; } @@ -172,12 +172,15 @@ public: return do_format(mpt::as_span(vals)); } -}; // struct message_formatter +}; // class message_formatter template class message_formatter_counted { +private: + using Tstringview = typename mpt::make_string_view_type::type; + private: message_formatter formatter; @@ -195,7 +198,7 @@ public: return formatter(std::forward(xs)...); } -}; // struct message_formatter_counted +}; // struct message_formatter_counted template diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple.hpp index 2ca40dcea..af085ecdf 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple.hpp @@ -33,88 +33,88 @@ struct format : format_simple_base { } template - static inline Tstring fmt(const T & x, const format_simple_spec & f) { + static inline Tstring fmt(const T & x, const format_simple_spec & f) { return mpt::format_simple(x, f); } template static inline Tstring dec(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff()); + return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff()); } template static inline Tstring dec0(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width)); + return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width)); } template - static inline Tstring dec(unsigned int g, char s, const T & x) { + static inline Tstring dec(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff().Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseDec().FillOff().Group(g).GroupSep(s)); } template - static inline Tstring dec0(unsigned int g, char s, const T & x) { + static inline Tstring dec0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring hex(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff()); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff()); } template static inline Tstring HEX(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff()); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff()); } template static inline Tstring hex0(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width)); } template static inline Tstring HEX0(const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width)); } template - static inline Tstring hex(unsigned int g, char s, const T & x) { + static inline Tstring hex(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s)); } template - static inline Tstring HEX(unsigned int g, char s, const T & x) { + static inline Tstring HEX(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s)); } template - static inline Tstring hex0(unsigned int g, char s, const T & x) { + static inline Tstring hex0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s)); } template - static inline Tstring HEX0(unsigned int g, char s, const T & x) { + static inline Tstring HEX0(unsigned int g, Tstring s, const T & x) { static_assert(std::numeric_limits::is_integer); - return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s)); + return mpt::format_simple(x, format_simple_spec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring flt(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); - return mpt::format_simple(x, format_simple_spec().NotaNrm().FillOff().Precision(precision)); + return mpt::format_simple(x, format_simple_spec().NotaNrm().FillOff().Precision(precision)); } template static inline Tstring fix(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); - return mpt::format_simple(x, format_simple_spec().NotaFix().FillOff().Precision(precision)); + return mpt::format_simple(x, format_simple_spec().NotaFix().FillOff().Precision(precision)); } template static inline Tstring sci(const T & x, int precision = -1) { static_assert(std::is_floating_point::value); - return mpt::format_simple(x, format_simple_spec().NotaSci().FillOff().Precision(precision)); + return mpt::format_simple(x, format_simple_spec().NotaSci().FillOff().Precision(precision)); } template diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_floatingpoint.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_floatingpoint.hpp index d1ccb32b0..c9449745c 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_floatingpoint.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_floatingpoint.hpp @@ -20,7 +20,7 @@ #include "mpt/format/default_floatingpoint.hpp" #include "mpt/format/helpers.hpp" #include "mpt/format/simple_spec.hpp" -#include "mpt/string/types.hpp" +#include "mpt/string/utility.hpp" #include "mpt/string_transcode/transcode.hpp" #if MPT_FORMAT_FORMAT_SIMPLE_FLOAT_CXX17 @@ -88,26 +88,26 @@ inline Tstring format_simple_floatingpoint_to_chars(const T & x, std::chars_form } template -inline Tstring format_simple_floatingpoint_postprocess_width(Tstring str, const format_simple_spec & format) { +inline Tstring format_simple_floatingpoint_postprocess_width(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); if (f & format_simple_base::FillNul) { auto pos = str.begin(); if (str.length() > 0) { - if (str[0] == mpt::unsafe_char_convert('+')) { + if (str[0] == mpt::char_constants::plus) { pos++; width++; - } else if (str[0] == mpt::unsafe_char_convert('-')) { + } else if (str[0] == mpt::char_constants::minus) { pos++; width++; } } if (str.length() - std::distance(str.begin(), pos) < width) { - str.insert(pos, width - str.length() - std::distance(str.begin(), pos), '0'); + str.insert(pos, width - str.length() - std::distance(str.begin(), pos), mpt::char_constants::number0); } } else { if (str.length() < width) { - str.insert(0, width - str.length(), ' '); + str.insert(0, width - str.length(), mpt::char_constants::space); } } return str; @@ -115,8 +115,9 @@ inline Tstring format_simple_floatingpoint_postprocess_width(Tstring str, const template ::value, bool> = true> -inline Tstring format_simple(const T & x, const format_simple_spec & f) { +inline Tstring format_simple(const T & x, const format_simple_spec & format) { using format_string_type = typename mpt::select_format_string_type::type; + const format_simple_spec f = mpt::transcode_format_simple_spec(format); if (f.GetPrecision() != -1) { if (f.GetFlags() & format_simple_base::NotaSci) { return mpt::transcode(mpt::format_simple_floatingpoint_postprocess_width(format_simple_floatingpoint_to_chars(x, std::chars_format::scientific, f.GetPrecision()), f)); @@ -144,31 +145,31 @@ template struct NumPunct : std::numpunct { private: unsigned int group; - char sep; + Tchar sep; public: - NumPunct(unsigned int g, char s) + NumPunct(unsigned int g, Tchar s) : group(g) , sep(s) { } std::string do_grouping() const override { return std::string(1, static_cast(group)); } Tchar do_thousands_sep() const override { - return static_cast(sep); + return sep; } }; -template -inline void format_simple_floatingpoint_apply_stream_format(Tostream & o, const format_simple_spec & format, const T &) { - if (format.GetGroup() > 0) - { - o.imbue(std::locale(o.getloc(), new NumPunct(format.GetGroup(), format.GetGroupSep()))); +template +inline void format_simple_floatingpoint_apply_stream_format(Tostream & o, const format_simple_spec & format, const T &) { + if (format.GetGroup() > 0) { + if (mpt::string_traits::length(format.GetGroupSep()) >= 1) { + o.imbue(std::locale(o.getloc(), new NumPunct(format.GetGroup(), format.GetGroupSep()[0]))); + } } format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); int precision = format.GetPrecision(); - if (precision != -1 && width != 0 && !(f & format_simple_base::NotaFix) && !(f & format_simple_base::NotaSci)) - { + if (precision != -1 && width != 0 && !(f & format_simple_base::NotaFix) && !(f & format_simple_base::NotaSci)) { // fixup: // precision behaves differently from .# // avoid default format when precision and width are set @@ -193,26 +194,19 @@ inline void format_simple_floatingpoint_apply_stream_format(Tostream & o, const } if (f & format_simple_base::FillOff) { /* nothing */ } else if (f & format_simple_base::FillNul) { - o << std::setw(width) << std::setfill(typename Tostream::char_type('0')); + o << std::setw(width) << std::setfill(mpt::char_constants::number0); } - if (precision != -1) - { + if (precision != -1) { o << std::setprecision(precision); - } else - { - if constexpr (std::is_floating_point::value) - { - if (f & format_simple_base::NotaNrm) - { + } else { + if constexpr (std::is_floating_point::value) { + if (f & format_simple_base::NotaNrm) { o << std::setprecision(std::numeric_limits::max_digits10); - } else if (f & format_simple_base::NotaFix) - { + } else if (f & format_simple_base::NotaFix) { o << std::setprecision(std::numeric_limits::digits10); - } else if (f & format_simple_base::NotaSci) - { + } else if (f & format_simple_base::NotaSci) { o << std::setprecision(std::numeric_limits::max_digits10 - 1); - } else - { + } else { o << std::setprecision(std::numeric_limits::max_digits10); } } @@ -221,7 +215,7 @@ inline void format_simple_floatingpoint_apply_stream_format(Tostream & o, const template -inline Tstring format_simple_floatingpoint_stream(const T & x, const format_simple_spec & f) { +inline Tstring format_simple_floatingpoint_stream(const T & x, const format_simple_spec & f) { using stream_char_type = typename mpt::select_format_char_type::type; std::basic_ostringstream s; s.imbue(std::locale::classic()); @@ -232,8 +226,10 @@ inline Tstring format_simple_floatingpoint_stream(const T & x, const format_simp template ::value, bool> = true> -inline Tstring format_simple(const T & x, const format_simple_spec & format) { - return mpt::transcode(mpt::format_simple_floatingpoint_stream::type>(x, format)); +inline Tstring format_simple(const T & x, const format_simple_spec & format) { + using format_string_type = typename mpt::select_format_string_type::type; + const format_simple_spec f = mpt::transcode_format_simple_spec(format); + return mpt::transcode(mpt::format_simple_floatingpoint_stream(x, f)); } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_integer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_integer.hpp index addecf8fe..35177c400 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_integer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_integer.hpp @@ -99,21 +99,21 @@ inline Tstring format_simple_integer_to_stream(const T & x, int base) { return mpt::convert_formatted_simple(s.str()); } else { if constexpr (std::is_same::value) { - return x ? Tstring(1, mpt::unsafe_char_convert('1')) : Tstring(1, mpt::unsafe_char_convert('0')); + return x ? Tstring(1, mpt::char_constants::number1) : Tstring(1, mpt::char_constants::number0); } else if constexpr (std::is_unsigned::value) { Tstring result; T val = x; if (val == 0) { - result += Tstring(1, mpt::unsafe_char_convert('0')); + result += Tstring(1, mpt::char_constants::number0); } else { using Tunsigned = typename std::make_unsigned::type; while (val > 0) { Tunsigned digit = static_cast(val % static_cast(base)); val = static_cast(val / static_cast(base)); if (digit >= 10) { - result += Tstring(1, static_cast(mpt::unsafe_char_convert('a') - 10 + digit)); + result += Tstring(1, static_cast(mpt::char_constants::a - 10 + digit)); } else { - result += Tstring(1, static_cast(mpt::unsafe_char_convert('0') + digit)); + result += Tstring(1, static_cast(mpt::char_constants::number0 + digit)); } } std::reverse(result.begin(), result.end()); @@ -122,7 +122,7 @@ inline Tstring format_simple_integer_to_stream(const T & x, int base) { } else { Tstring result; if (x == 0) { - result += Tstring(1, mpt::unsafe_char_convert('0')); + result += Tstring(1, mpt::char_constants::number0); } else { using Tunsigned = typename std::make_unsigned::type; Tunsigned val = (x != -x) ? ((x >= 0) ? x : -x) : (static_cast(-(x + 1)) + 1); @@ -130,13 +130,13 @@ inline Tstring format_simple_integer_to_stream(const T & x, int base) { Tunsigned digit = static_cast(val % static_cast(base)); val = static_cast(val / static_cast(base)); if (digit >= 10) { - result += Tstring(1, static_cast(mpt::unsafe_char_convert('a') - 10 + digit)); + result += Tstring(1, static_cast(mpt::char_constants::a - 10 + digit)); } else { - result += Tstring(1, static_cast(mpt::unsafe_char_convert('0') + digit)); + result += Tstring(1, static_cast(mpt::char_constants::number0 + digit)); } } if (x < 0) { - result += Tstring(1, mpt::unsafe_char_convert('-')); + result += Tstring(1, mpt::char_constants::minus); } std::reverse(result.begin(), result.end()); } @@ -149,12 +149,12 @@ inline Tstring format_simple_integer_to_stream(const T & x, int base) { template -inline Tstring format_simple_integer_postprocess_case(Tstring str, const format_simple_spec & format) { +inline Tstring format_simple_integer_postprocess_case(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); if (f & format_simple_base::CaseUpp) { for (auto & c : str) { - if (mpt::unsafe_char_convert('a') <= c && c <= mpt::unsafe_char_convert('z')) { - c -= mpt::unsafe_char_convert('a') - mpt::unsafe_char_convert('A'); + if (mpt::char_constants::a <= c && c <= mpt::char_constants::z) { + c -= mpt::char_constants::a - mpt::char_constants::A; } } } @@ -163,22 +163,22 @@ inline Tstring format_simple_integer_postprocess_case(Tstring str, const format_ template -inline Tstring format_simple_integer_postprocess_digits(Tstring str, const format_simple_spec & format) { +inline Tstring format_simple_integer_postprocess_digits(Tstring str, const format_simple_spec & format) { format_simple_flags f = format.GetFlags(); std::size_t width = format.GetWidth(); if (f & format_simple_base::FillNul) { auto pos = str.begin(); if (str.length() > 0) { - if (str[0] == mpt::unsafe_char_convert('+')) { + if (str[0] == mpt::char_constants::plus) { pos++; width++; - } else if (str[0] == mpt::unsafe_char_convert('-')) { + } else if (str[0] == mpt::char_constants::minus) { pos++; width++; } } if (str.length() < width) { - str.insert(pos, width - str.length(), mpt::unsafe_char_convert('0')); + str.insert(pos, width - str.length(), mpt::char_constants::number0); } } return str; @@ -190,15 +190,15 @@ inline Tstring format_simple_integer_postprocess_digits(Tstring str, const forma #pragma warning(disable : 4723) // potential divide by 0 #endif // MPT_COMPILER_MSVC template -inline Tstring format_simple_integer_postprocess_group(Tstring str, const format_simple_spec & format) { +inline Tstring format_simple_integer_postprocess_group(Tstring str, const format_simple_spec & format) { if (format.GetGroup() > 0) { const unsigned int groupSize = format.GetGroup(); - const char groupSep = format.GetGroupSep(); + const Tstring groupSep = format.GetGroupSep(); std::size_t len = str.length(); for (std::size_t n = 0; n < len; ++n) { if (n > 0 && (n % groupSize) == 0) { - if (!(n == (len - 1) && (str[0] == mpt::unsafe_char_convert('+') || str[0] == mpt::unsafe_char_convert('-')))) { - str.insert(str.begin() + (len - n), 1, mpt::unsafe_char_convert(groupSep)); + if (!(n == (len - 1) && (str[0] == mpt::char_constants::plus || str[0] == mpt::char_constants::minus))) { + str.insert(len - n, groupSep); } } } @@ -213,7 +213,7 @@ inline Tstring format_simple_integer_postprocess_group(Tstring str, const format #if MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> -inline Tstring format_simple(const T & x, const format_simple_spec & format) { +inline Tstring format_simple(const T & x, const format_simple_spec & format) { int base = 10; if (format.GetFlags() & format_simple_base::BaseDec) { base = 10; @@ -222,13 +222,14 @@ inline Tstring format_simple(const T & x, const format_simple_spec & format) { base = 16; } using format_string_type = typename mpt::select_format_string_type::type; - return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_chars(x, base), format), format), format)); + const format_simple_spec f = mpt::transcode_format_simple_spec(format); + return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_chars(x, base), f), f), f)); } #else // !MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 template ::value, bool> = true> -inline Tstring format_simple(const T & x, const format_simple_spec & format) { +inline Tstring format_simple(const T & x, const format_simple_spec & format) { int base = 10; if (format.GetFlags() & format_simple_base::BaseDec) { base = 10; @@ -237,7 +238,8 @@ inline Tstring format_simple(const T & x, const format_simple_spec & format) { base = 16; } using format_string_type = typename mpt::select_format_string_type::type; - return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_stream(x, base), format), format), format)); + const format_simple_spec f = mpt::transcode_format_simple_spec(format); + return mpt::transcode(mpt::format_simple_integer_postprocess_group(mpt::format_simple_integer_postprocess_digits(mpt::format_simple_integer_postprocess_case(mpt::format_simple_integer_to_stream(x, base), f), f), f)); } #endif // MPT_FORMAT_FORMAT_SIMPLE_INT_CXX17 diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_spec.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_spec.hpp index 797a61994..cff18b0a9 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_spec.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/simple_spec.hpp @@ -7,6 +7,9 @@ #include "mpt/base/macros.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#include #include @@ -37,20 +40,21 @@ using format_simple_flags = unsigned int; static_assert(sizeof(format_simple_flags) >= sizeof(format_simple_base::FormatFlagsEnum)); +template class format_simple_spec { private: format_simple_flags flags; std::size_t width; // int+float int precision; // float unsigned int group; // int - char group_sep; // int + Tstring group_sep; // int public: MPT_CONSTEXPRINLINE format_simple_spec() noexcept : flags(0) , width(0) , precision(-1) , group(0) - , group_sep(',') { } + , group_sep() { } MPT_CONSTEXPRINLINE format_simple_flags GetFlags() const noexcept { return flags; } @@ -63,7 +67,7 @@ public: MPT_CONSTEXPRINLINE unsigned int GetGroup() const noexcept { return group; } - MPT_CONSTEXPRINLINE char GetGroupSep() const noexcept { + MPT_CONSTEXPRINLINE Tstring GetGroupSep() const { return group_sep; } MPT_CONSTEXPRINLINE format_simple_spec & SetFlags(format_simple_flags f) noexcept { @@ -82,8 +86,8 @@ public: group = g; return *this; } - MPT_CONSTEXPRINLINE format_simple_spec & SetGroupSep(char s) noexcept { - group_sep = s; + MPT_CONSTEXPRINLINE format_simple_spec & SetGroupSep(Tstring s) { + group_sep = std::move(s); return *this; } @@ -145,8 +149,8 @@ public: group = g; return *this; } - MPT_CONSTEXPRINLINE format_simple_spec & GroupSep(char s) noexcept { - group_sep = s; + MPT_CONSTEXPRINLINE format_simple_spec & GroupSep(Tstring s) { + group_sep = std::move(s); return *this; } @@ -213,6 +217,53 @@ public: }; +template +inline format_simple_spec transcode_format_simple_spec(const format_simple_spec & src) { + format_simple_spec dst; + dst.SetFlags(src.GetFlags()); + dst.SetWidth(src.GetWidth()); + dst.SetPrecision(src.GetPrecision()); + dst.SetGroup(src.GetGroup()); + dst.SetGroupSep(mpt::transcode(src.GetGroupSep())); + return dst; +} + +template ::value, bool> = true> +inline format_simple_spec transcode_format_simple_spec(Tencoding to, const format_simple_spec & src) { + format_simple_spec dst; + dst.SetFlags(src.GetFlags()); + dst.SetWidth(src.GetWidth()); + dst.SetPrecision(src.GetPrecision()); + dst.SetGroup(src.GetGroup()); + dst.SetGroupSep(mpt::transcode(to, src.GetGroupSep())); + return dst; +} + +template ::type, std::string>::value, bool> = true> +inline format_simple_spec transcode_format_simple_spec(Tencoding from, const format_simple_spec & src) { + format_simple_spec dst; + dst.SetFlags(src.GetFlags()); + dst.SetWidth(src.GetWidth()); + dst.SetPrecision(src.GetPrecision()); + dst.SetGroup(src.GetGroup()); + dst.SetGroupSep(mpt::transcode(from, src.GetGroupSep())); + return dst; +} + +template +inline format_simple_spec transcode_format_simple_spec(Tto to, Tfrom from, const format_simple_spec & src) { + format_simple_spec dst; + dst.SetFlags(src.GetFlags()); + dst.SetWidth(src.GetWidth()); + dst.SetPrecision(src.GetPrecision()); + dst.SetGroup(src.GetGroup()); + dst.SetGroupSep(mpt::transcode(to, from, src.GetGroupSep())); + return dst; +} + + + + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_message.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_message.hpp index 5de2dc13d..b5c5030dd 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_message.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_message.hpp @@ -9,6 +9,7 @@ #include "mpt/base/namespace.hpp" #include "mpt/format/message.hpp" #include "mpt/format/message_macros.hpp" +#include "mpt/string/types.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" @@ -62,6 +63,10 @@ MPT_TEST_GROUP_INLINE("mpt/format/message") MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("%b")(), "%b"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{{}}")(), "{}"); MPT_TEST_EXPECT_EQUAL(MPT_AFORMAT_MESSAGE("{{{}}}")("a"), "{a}"); + + // formatting string_view + MPT_TEST_EXPECT_EQUAL(MPT_UFORMAT_MESSAGE("{}")(mpt::ustring(MPT_ULITERAL("foo"))), MPT_USTRING("foo")); + MPT_TEST_EXPECT_EQUAL(MPT_UFORMAT_MESSAGE("{}")(mpt::ustring_view(MPT_ULITERAL("foo"))), MPT_USTRING("foo")); } } // namespace message diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_simple.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_simple.hpp index 2902a220c..468687d11 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_simple.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/format/tests/tests_format_simple.hpp @@ -7,6 +7,7 @@ #include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" +#include "mpt/detect/mfc.hpp" #include "mpt/format/simple.hpp" #include "mpt/format/simple_integer.hpp" #include "mpt/string/types.hpp" @@ -15,6 +16,7 @@ #include #include +#include @@ -132,32 +134,32 @@ MPT_TEST_GROUP_INLINE("mpt/format/simple") MPT_TEST_EXPECT_EQUAL(mpt::format::fix(234.2, 1), "234.2"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(2342.0, 1), "2342.0"); - MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ';', 2345678), std::string("2;34;56;78")); - MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ';', 12345678), std::string("12;34;56;78")); - MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, ':', 0xa2345678), std::string("a2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ";", 2345678), std::string("2;34;56;78")); + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ";", 12345678), std::string("12;34;56;78")); + MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, ":", 0xa2345678), std::string("a2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, ';', 12345678), MPT_USTRING("12;34;56;78")); - MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, ':', 0xa2345678), MPT_USTRING("a2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, MPT_USTRING(";"), 12345678), MPT_USTRING("12;34;56;78")); + MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("a2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, ':', 0xa2345678), MPT_USTRING("A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, ':', 0xa2345678), MPT_USTRING("A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, ':', 0xa2345678), MPT_USTRING("0A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, ':', 0xa2345678), MPT_USTRING("0:0A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, ':', 0xa2345678), MPT_USTRING("00:0A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, ':', 0xa2345678), MPT_USTRING("000:0A2:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, ':', -0x12345678), MPT_USTRING("-12:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, ':', -0x12345678), MPT_USTRING("-12:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, ':', -0x12345678), MPT_USTRING("-012:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, ':', -0x12345678), MPT_USTRING("-0:012:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, ':', -0x12345678), MPT_USTRING("-00:012:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, ':', -0x12345678), MPT_USTRING("-000:012:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("0A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("0:0A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("00:0A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, MPT_USTRING(":"), 0xa2345678), MPT_USTRING("000:0A2:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-12:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-12:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-012:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-0:012:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-00:012:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, MPT_USTRING(":"), -0x12345678), MPT_USTRING("-000:012:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, ':', 0x345678), MPT_USTRING("345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, ':', 0x345678), MPT_USTRING("345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, ':', 0x345678), MPT_USTRING("0:345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, ':', -0x345678), MPT_USTRING("-345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, ':', -0x345678), MPT_USTRING("-345:678")); - MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, ':', -0x345678), MPT_USTRING("-0:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), 0x345678), MPT_USTRING("0:345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-345:678")); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, MPT_USTRING(":"), -0x345678), MPT_USTRING("-0:345:678")); MPT_TEST_EXPECT_EQUAL(mpt::format::left(3, "a"), "a "); MPT_TEST_EXPECT_EQUAL(mpt::format::right(3, "a"), " a"); @@ -169,6 +171,55 @@ MPT_TEST_GROUP_INLINE("mpt/format/simple") MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 4), "6.123"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 4), "6.1235"); + MPT_TEST_EXPECT_EQUAL(mpt::format::val(std::u32string(U"foo")), U"foo"); + MPT_TEST_EXPECT_EQUAL(mpt::format::val(std::u32string_view(U"foo")), U"foo"); + +#if MPT_DETECTED_MFC + + MPT_TEST_EXPECT_EQUAL(mpt::format::flt(58.65403492763, 6), TEXT("58.654")); + MPT_TEST_EXPECT_EQUAL(mpt::format::fix(23.42, 1), TEXT("23.4")); + MPT_TEST_EXPECT_EQUAL(mpt::format::fix(234.2, 1), TEXT("234.2")); + MPT_TEST_EXPECT_EQUAL(mpt::format::fix(2342.0, 1), TEXT("2342.0")); + + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 2345678), CString(TEXT("2;34;56;78"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 12345678), CString(TEXT("12;34;56;78"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, TEXT(":"), 0xa2345678), CString(TEXT("a2:345:678"))); + + MPT_TEST_EXPECT_EQUAL(mpt::format::dec(2, TEXT(";"), 12345678), CString(TEXT("12;34;56;78"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::hex(3, TEXT(":"), 0xa2345678), CString(TEXT("a2:345:678"))); + + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), 0xa2345678), CString(TEXT("A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, TEXT(":"), 0xa2345678), CString(TEXT("A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, TEXT(":"), 0xa2345678), CString(TEXT("0A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, TEXT(":"), 0xa2345678), CString(TEXT("0:0A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, TEXT(":"), 0xa2345678), CString(TEXT("00:0A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, TEXT(":"), 0xa2345678), CString(TEXT("000:0A2:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), -0x12345678), CString(TEXT("-12:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<8>(3, TEXT(":"), -0x12345678), CString(TEXT("-12:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<9>(3, TEXT(":"), -0x12345678), CString(TEXT("-012:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<10>(3, TEXT(":"), -0x12345678), CString(TEXT("-0:012:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<11>(3, TEXT(":"), -0x12345678), CString(TEXT("-00:012:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<12>(3, TEXT(":"), -0x12345678), CString(TEXT("-000:012:345:678"))); + + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, TEXT(":"), 0x345678), CString(TEXT("345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, TEXT(":"), 0x345678), CString(TEXT("345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), 0x345678), CString(TEXT("0:345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<5>(3, TEXT(":"), -0x345678), CString(TEXT("-345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<6>(3, TEXT(":"), -0x345678), CString(TEXT("-345:678"))); + MPT_TEST_EXPECT_EQUAL(mpt::format::HEX0<7>(3, TEXT(":"), -0x345678), CString(TEXT("-0:345:678"))); + + MPT_TEST_EXPECT_EQUAL(mpt::format::left(3, TEXT("a")), TEXT("a ")); + MPT_TEST_EXPECT_EQUAL(mpt::format::right(3, TEXT("a")), TEXT(" a")); + MPT_TEST_EXPECT_EQUAL(mpt::format::center(3, TEXT("a")), TEXT(" a ")); + MPT_TEST_EXPECT_EQUAL(mpt::format::center(4, TEXT("a")), TEXT(" a ")); + + MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 3), TEXT("6.12")); + MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 3), TEXT("6.123")); + MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 4), TEXT("6.123")); + MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 4), TEXT("6.1235")); + +#endif + #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::format::flt(6.12345, 3), L"6.12"); MPT_TEST_EXPECT_EQUAL(mpt::format::fix(6.12345, 3), L"6.123"); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/base.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/base.hpp index ade1b5060..fa607b9af 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/base.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/base.hpp @@ -38,7 +38,6 @@ struct FileOperations { template inline FileOperations FileOps(Tfile & f) { - ; return FileOperations{f}; } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io.hpp index 1379f1e53..1437cf57b 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io.hpp @@ -12,6 +12,7 @@ #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/endian/integer.hpp" +#include "mpt/endian/type_traits.hpp" #include "mpt/io/base.hpp" #include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_span.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_span.hpp index 94cdaa994..8f3534cbf 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_span.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_span.hpp @@ -79,8 +79,7 @@ public: } inline bool SeekRelative(IO::Offset off) { - if (f.second < 0) - { + if (f.second < 0) { return false; } f.second += off; @@ -88,12 +87,10 @@ public: } inline mpt::byte_span ReadRawImpl(mpt::byte_span data) { - if (f.second < 0) - { + if (f.second < 0) { return data.first(0); } - if (f.second >= static_cast(f.first.size())) - { + if (f.second >= static_cast(f.first.size())) { return data.first(0); } std::size_t num = mpt::saturate_cast(std::min(static_cast(f.first.size()) - f.second, static_cast(data.size()))); @@ -103,17 +100,14 @@ public: } inline bool WriteRawImpl(mpt::const_byte_span data) { - if (f.second < 0) - { + if (f.second < 0) { return false; } - if (f.second > static_cast(f.first.size())) - { + if (f.second > static_cast(f.first.size())) { return false; } std::size_t num = mpt::saturate_cast(std::min(static_cast(f.first.size()) - f.second, static_cast(data.size()))); - if (num != data.size()) - { + if (num != data.size()) { return false; } std::copy(data.data(), data.data() + num, mpt::byte_cast(f.first.data() + f.second)); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_stdstream.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_stdstream.hpp index e15582e03..34f7194bb 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_stdstream.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/io_stdstream.hpp @@ -28,15 +28,13 @@ namespace IO { -//static_assert(sizeof(std::streamoff) == 8); // Assert 64bit file support. - struct FileOperationsStdIos { private: std::ios & f; public: - FileOperationsStdIos(std::ios & f_) + inline FileOperationsStdIos(std::ios & f_) : f(f_) { return; } @@ -54,7 +52,7 @@ private: std::istream & f; public: - FileOperationsStdIstream(std::istream & f_) + inline FileOperationsStdIstream(std::istream & f_) : FileOperationsStdIos(f_) , f(f_) { return; @@ -64,30 +62,26 @@ public: inline bool IsReadSeekable() { f.clear(); std::streampos oldpos = f.tellg(); - if (f.fail() || oldpos == std::streampos(-1)) - { + if (f.fail() || oldpos == std::streampos(std::streamoff(-1))) { f.clear(); return false; } f.seekg(0, std::ios::beg); - if (f.fail()) - { + if (f.fail()) { f.clear(); f.seekg(oldpos); f.clear(); return false; } f.seekg(0, std::ios::end); - if (f.fail()) - { + if (f.fail()) { f.clear(); f.seekg(oldpos); f.clear(); return false; } std::streampos length = f.tellg(); - if (f.fail() || length == std::streampos(-1)) - { + if (f.fail() || length == std::streampos(std::streamoff(-1))) { f.clear(); f.seekg(oldpos); f.clear(); @@ -99,11 +93,11 @@ public: } inline IO::Offset TellRead() { - return f.tellg(); + return static_cast(f.tellg()); } inline bool SeekBegin() { - f.seekg(0); + f.seekg(0, std::ios::beg); return !f.fail(); } @@ -113,8 +107,7 @@ public: } inline bool SeekAbsolute(IO::Offset pos) { - if (!mpt::in_range(pos)) - { + if (!mpt::in_range(pos)) { return false; } f.seekg(static_cast(pos), std::ios::beg); @@ -122,8 +115,7 @@ public: } inline bool SeekRelative(IO::Offset off) { - if (!mpt::in_range(off)) - { + if (!mpt::in_range(off)) { return false; } f.seekg(static_cast(off), std::ios::cur); @@ -147,7 +139,7 @@ private: std::ostream & f; public: - FileOperationsStdOstream(std::ostream & f_) + inline FileOperationsStdOstream(std::ostream & f_) : FileOperationsStdIos(f_) , f(f_) { return; @@ -157,30 +149,26 @@ public: inline bool IsWriteSeekable() { f.clear(); std::streampos oldpos = f.tellp(); - if (f.fail() || oldpos == std::streampos(-1)) - { + if (f.fail() || oldpos == std::streampos(std::streamoff(-1))) { f.clear(); return false; } f.seekp(0, std::ios::beg); - if (f.fail()) - { + if (f.fail()) { f.clear(); f.seekp(oldpos); f.clear(); return false; } f.seekp(0, std::ios::end); - if (f.fail()) - { + if (f.fail()) { f.clear(); f.seekp(oldpos); f.clear(); return false; } std::streampos length = f.tellp(); - if (f.fail() || length == std::streampos(-1)) - { + if (f.fail() || length == std::streampos(std::streamoff(-1))) { f.clear(); f.seekp(oldpos); f.clear(); @@ -192,11 +180,11 @@ public: } inline IO::Offset TellWrite() { - return f.tellp(); + return static_cast(f.tellp()); } inline bool SeekBegin() { - f.seekp(0); + f.seekp(0, std::ios::beg); return !f.fail(); } @@ -206,8 +194,7 @@ public: } inline bool SeekAbsolute(IO::Offset pos) { - if (!mpt::in_range(pos)) - { + if (!mpt::in_range(pos)) { return false; } f.seekp(static_cast(pos), std::ios::beg); @@ -215,8 +202,7 @@ public: } inline bool SeekRelative(IO::Offset off) { - if (!mpt::in_range(off)) - { + if (!mpt::in_range(off)) { return false; } f.seekp(static_cast(off), std::ios::cur); @@ -242,7 +228,7 @@ private: std::iostream & f; public: - FileOperationsStdIOstream(std::iostream & f_) + inline FileOperationsStdIOstream(std::iostream & f_) : FileOperationsStdIstream(f_) , FileOperationsStdOstream(f_) , f(f_) { @@ -263,8 +249,7 @@ public: } inline bool SeekAbsolute(IO::Offset pos) { - if (!mpt::in_range(pos)) - { + if (!mpt::in_range(pos)) { return false; } FileOperationsStdIstream::SeekAbsolute(pos); @@ -273,8 +258,7 @@ public: } inline bool SeekRelative(IO::Offset off) { - if (!mpt::in_range(off)) - { + if (!mpt::in_range(off)) { return false; } FileOperationsStdIstream::SeekRelative(off); @@ -289,7 +273,7 @@ template struct FileOperations::value>> : public FileOperationsStdIOstream { public: - FileOperations(Tstream & f) + inline FileOperations(Tstream & f) : FileOperationsStdIOstream(f) { return; } @@ -301,7 +285,7 @@ template struct FileOperations::value && !std::is_base_of::value>> : public FileOperationsStdIstream { public: - FileOperations(Tstream & f) + inline FileOperations(Tstream & f) : FileOperationsStdIstream(f) { return; } @@ -313,7 +297,7 @@ template struct FileOperations::value && !std::is_base_of::value>> : public FileOperationsStdOstream { public: - FileOperations(Tstream & f) + inline FileOperations(Tstream & f) : FileOperationsStdOstream(f) { return; } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/tests/tests_io.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/tests/tests_io.hpp index 3a529c5c0..0eb026ffa 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io/tests/tests_io.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io/tests/tests_io.hpp @@ -47,7 +47,7 @@ MPT_TEST_GROUP_INLINE("mpt/io") { std::ostringstream ss; - MPT_TEST_EXPECT_EQUAL(ss.tellp(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(ss.tellp()), std::streamoff(0)); } { std::ostringstream ss; @@ -66,11 +66,11 @@ MPT_TEST_GROUP_INLINE("mpt/io") } { std::istringstream ss; - MPT_TEST_EXPECT_EQUAL(ss.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(ss.tellg()), std::streamoff(0)); } { std::istringstream ss; - ss.seekg(0); + ss.seekg(0, std::ios::beg); MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true); } { @@ -88,23 +88,23 @@ MPT_TEST_GROUP_INLINE("mpt/io") std::ostringstream s; char b = 23; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.write(&b, 1); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(1)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekp(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(1)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellp()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b)); } @@ -112,15 +112,15 @@ MPT_TEST_GROUP_INLINE("mpt/io") { std::istringstream s; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); } @@ -128,24 +128,24 @@ MPT_TEST_GROUP_INLINE("mpt/io") std::istringstream s("a"); char a = 0; MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.read(&a, 1); MPT_TEST_EXPECT_EQUAL(a, 'a'); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(1)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::beg); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(0)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); s.seekg(0, std::ios_base::end); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); - MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(1)); + MPT_TEST_EXPECT_EQUAL(static_cast(s.tellg()), std::streamoff(1)); MPT_TEST_EXPECT_EQUAL(!s.fail(), true); MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a')); } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fileref.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fileref.hpp new file mode 100644 index 000000000..019f7a1d7 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fileref.hpp @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_FILEREF_HPP +#define MPT_IO_FILE_FILEREF_HPP + + + +#include "mpt/base/alloc.hpp" +#include "mpt/base/memory.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/base/saturate_cast.hpp" +#include "mpt/base/span.hpp" +#include "mpt/io/base.hpp" +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/io_file/fstream.hpp" +#include "mpt/path/os_path.hpp" + +#include +#include +#include + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +// FileRef is a simple reference to an on-disk file by the means of a +// filename which allows easy assignment of the whole file contents to and from +// byte buffers. + +class FileRef { +private: + const mpt::os_path m_Filename; + +public: + FileRef(const mpt::os_path & filename) + : m_Filename(filename) { + return; + } + +public: + FileRef & operator=(const std::vector & data) { + mpt::IO::ofstream file(m_Filename, std::ios::binary); + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::WriteRaw(file, mpt::as_span(data)); + mpt::IO::Flush(file); + return *this; + } + + FileRef & operator=(const std::vector & data) { + mpt::IO::ofstream file(m_Filename, std::ios::binary); + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::WriteRaw(file, mpt::as_span(data)); + mpt::IO::Flush(file); + return *this; + } + + FileRef & operator=(const std::string & data) { + mpt::IO::ofstream file(m_Filename, std::ios::binary); + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::WriteRaw(file, mpt::as_span(data)); + mpt::IO::Flush(file); + return *this; + } + + operator std::vector() const { + mpt::IO::ifstream file(m_Filename, std::ios::binary); + if (!mpt::IO::IsValid(file)) { + return std::vector(); + } + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::SeekEnd(file); + std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); + mpt::IO::SeekBegin(file); + mpt::IO::ReadRaw(file, mpt::as_span(buf)); + return buf; + } + + operator std::vector() const { + mpt::IO::ifstream file(m_Filename, std::ios::binary); + if (!mpt::IO::IsValid(file)) { + return std::vector(); + } + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::SeekEnd(file); + std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); + mpt::IO::SeekBegin(file); + mpt::IO::ReadRaw(file, mpt::as_span(buf)); + return buf; + } + + operator std::string() const { + mpt::IO::ifstream file(m_Filename, std::ios::binary); + if (!mpt::IO::IsValid(file)) { + return std::string(); + } + file.exceptions(std::ios_base::failbit | std::ios_base::badbit); + mpt::IO::SeekEnd(file); + std::vector buf(mpt::saturate_cast(mpt::IO::TellRead(file))); + mpt::IO::SeekBegin(file); + mpt::IO::ReadRaw(file, mpt::as_span(buf)); + return mpt::buffer_cast(buf); + } +}; + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_FILEREF_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fstream.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fstream.hpp new file mode 100644 index 000000000..ff3be42a0 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/fstream.hpp @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_FSTREAM_HPP +#define MPT_IO_FILE_FSTREAM_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/base/span.hpp" +#include "mpt/io/base.hpp" +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/path/os_path_long.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) +#if MPT_GCC_AT_LEAST(9, 1, 0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) +#include +#endif // MPT_GCC_AT_LEAST(9,1,0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) +#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR +#include +#include +#include +#include + +#if MPT_LIBCXX_MS +#include +#endif // MPT_LIBCXX_MS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +namespace detail { + +template +inline void fstream_open(Tbase & base, const mpt::os_path & filename, std::ios_base::openmode mode) { +#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) +#if MPT_GCC_AT_LEAST(9, 1, 0) && !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) + base.open(static_cast(mpt::support_long_path(filename)), mode); +#else // !MPT_GCC_AT_LEAST(9,1,0) || MPT_COMPILER_QUIRK_NO_FILESYSTEM + // Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable. + base.open(mpt::transcode(mpt::logical_encoding::locale, mpt::support_long_path(filename)).c_str(), mode); +#endif // MPT_GCC_AT_LEAST(9,1,0) && !MPT_COMPILER_QUIRK_NO_FILESYSTEM +#else // !MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR + base.open(mpt::support_long_path(filename).c_str(), mode); +#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR +} + +} // namespace detail + +// We cannot rely on implicit conversion of mpt::path to std::filesystem::path when constructing std::fstream +// because of broken overload implementation in GCC libstdc++ 8, 9, 10. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95642 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90704 + +class fstream + : public std::fstream { +private: + using base_type = std::fstream; + +public: + explicit fstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { + detail::fstream_open(*this, filename, mode); + } +#if MPT_LIBCXX_MS +protected: + fstream(std::FILE * file) + : std::fstream(file) { + } +#endif // MPT_LIBCXX_MS +public: + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; +#endif +}; + +class ifstream + : public std::ifstream { +private: + using base_type = std::ifstream; + +public: + explicit ifstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::in) { + detail::fstream_open(*this, filename, mode); + } +#if MPT_LIBCXX_MS +protected: + ifstream(std::FILE * file) + : std::ifstream(file) { + } +#endif // MPT_LIBCXX_MS +public: + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; +#endif +}; + +class ofstream + : public std::ofstream { +private: + using base_type = std::ofstream; + +public: + explicit ofstream(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::out) { + detail::fstream_open(*this, filename, mode); + } +#if MPT_LIBCXX_MS +protected: + ofstream(std::FILE * file) + : std::ofstream(file) { + } +#endif // MPT_LIBCXX_MS +public: + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::string_view & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::wstring_view & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; +#endif +}; + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_FSTREAM_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/inputfile.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/inputfile.hpp new file mode 100644 index 000000000..80839bddd --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/inputfile.hpp @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_INPUTFILE_HPP +#define MPT_IO_FILE_INPUTFILE_HPP + + + +#include "mpt/base/alloc.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/base/saturate_cast.hpp" +#include "mpt/base/span.hpp" +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/io_file/fstream.hpp" +#include "mpt/path/os_path.hpp" + +#include +#include +#include +#include + +#include +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +class UncachedInputFile { + +private: + mpt::os_path m_Filename; + mpt::IO::ifstream m_File; + bool m_IsValid; + +public: + UncachedInputFile(const mpt::os_path & filename) + : m_Filename(filename) + , m_File(m_Filename, std::ios::binary | std::ios::in) + , m_IsValid(true) { + assert(!m_Filename.empty()); + } + + ~UncachedInputFile() = default; + + bool IsValid() const { + return m_IsValid && m_File.good(); + } + + mpt::os_path GetFilename() const { + return m_Filename; + } + + std::istream & GetStream() { + return m_File; + } +}; + + + +class CachedInputFile { + +private: + mpt::os_path m_Filename; + mpt::IO::ifstream m_File; + bool m_IsValid; + bool m_IsCached; + std::vector m_Cache; + +public: + CachedInputFile(const mpt::os_path & filename) + : m_Filename(filename) + , m_File(m_Filename, std::ios::binary | std::ios::in) + , m_IsValid(false) + , m_IsCached(false) { + assert(!filename.empty()); + if (mpt::IO::IsReadSeekable(m_File)) { + if (!mpt::IO::SeekEnd(m_File)) { + m_File.close(); + return; + } + mpt::IO::Offset filesize = mpt::IO::TellRead(m_File); + if (!mpt::IO::SeekBegin(m_File)) { + m_File.close(); + return; + } + if (mpt::in_range(filesize)) { + std::size_t buffersize = mpt::saturate_cast(filesize); + m_Cache.resize(buffersize); + if (mpt::IO::ReadRaw(m_File, mpt::as_span(m_Cache)).size() != mpt::saturate_cast(filesize)) { + m_File.close(); + return; + } + if (!mpt::IO::SeekBegin(m_File)) { + m_File.close(); + return; + } + m_IsCached = true; + m_IsValid = true; + return; + } + } + m_IsValid = true; + return; + } + + ~CachedInputFile() = default; + + bool IsValid() const { + return m_IsValid && m_File.good(); + } + + bool IsCached() const { + return m_IsCached; + } + + mpt::os_path GetFilename() const { + return m_Filename; + } + + std::istream & GetStream() { + assert(!m_IsCached); + return m_File; + } + + mpt::const_byte_span GetCache() { + assert(m_IsCached); + return mpt::as_span(m_Cache); + } +}; + + + +class InputFile { + +private: + std::variant m_impl; + +public: + InputFile(const mpt::os_path & filename, bool enable_cache = false) { + if (enable_cache) { + m_impl.emplace(filename); + } else { + m_impl.emplace(filename); + } + } + + ~InputFile() = default; + + bool IsValid() const { + if (std::holds_alternative(m_impl)) { + return std::get(m_impl).IsValid(); + } else if (std::holds_alternative(m_impl)) { + return std::get(m_impl).IsValid(); + } + return false; + } + + bool IsCached() const { + if (std::holds_alternative(m_impl)) { + return false; + } else if (std::holds_alternative(m_impl)) { + return std::get(m_impl).IsCached(); + } + throw false; + } + + mpt::os_path GetFilename() const { + if (std::holds_alternative(m_impl)) { + return std::get(m_impl).GetFilename(); + } else if (std::holds_alternative(m_impl)) { + return std::get(m_impl).GetFilename(); + } + return {}; + } + + std::istream & GetStream() { + if (std::holds_alternative(m_impl)) { + return std::get(m_impl).GetStream(); + } else if (std::holds_alternative(m_impl)) { + return std::get(m_impl).GetStream(); + } + throw std::bad_variant_access(); + } + + mpt::const_byte_span GetCache() { + if (std::holds_alternative(m_impl)) { + throw std::bad_variant_access(); + } else if (std::holds_alternative(m_impl)) { + return std::get(m_impl).GetCache(); + } + throw std::bad_variant_access(); + } +}; + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_INPUTFILE_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/outputfile.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/outputfile.hpp new file mode 100644 index 000000000..a3eaeebe5 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file/outputfile.hpp @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_OUTPUTFILE_HPP +#define MPT_IO_FILE_OUTPUTFILE_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/io_file/fstream.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/string/types.hpp" + +#include +#include +#include + +#if MPT_LIBCXX_MS +#include +#endif // MPT_LIBCXX_MS + +#if MPT_LIBCXX_MS +#include +#endif // MPT_LIBCXX_MS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +enum class FlushMode { + None = 0, // no explicit flushes at all + Single = 1, // explicitly flush higher-leverl API layers + Full = 2, // explicitly flush *all* layers, up to and including disk write caches +}; + +inline FlushMode FlushModeFromBool(bool flush) { + return flush ? FlushMode::Full : FlushMode::None; +} + +class SafeOutputFile { + +private: + FlushMode m_FlushMode; +#if MPT_LIBCXX_MS + std::FILE * m_f = nullptr; +#else // !MPT_LIBCXX_MS + mpt::IO::ofstream m_s; +#endif // MPT_LIBCXX_MS +#if MPT_LIBCXX_MS + class FILEostream + : public mpt::IO::ofstream { + public: + FILEostream(std::FILE * file) + : mpt::IO::ofstream(file) { + return; + } + }; + + FILEostream m_s; + + static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode) { + mpt::tstring fopen_mode; + switch (mode & ~(std::ios_base::ate | std::ios_base::binary)) { + case std::ios_base::in: + fopen_mode = _T("r"); + break; + case std::ios_base::out: + [[fallthrough]]; + case std::ios_base::out | std::ios_base::trunc: + fopen_mode = _T("w"); + break; + case std::ios_base::app: + [[fallthrough]]; + case std::ios_base::out | std::ios_base::app: + fopen_mode = _T("a"); + break; + case std::ios_base::out | std::ios_base::in: + fopen_mode = _T("r+"); + break; + case std::ios_base::out | std::ios_base::in | std::ios_base::trunc: + fopen_mode = _T("w+"); + break; + case std::ios_base::out | std::ios_base::in | std::ios_base::app: + [[fallthrough]]; + case std::ios_base::in | std::ios_base::app: + fopen_mode = _T("a+"); + break; + } + if (fopen_mode.empty()) { + return fopen_mode; + } + if (mode & std::ios_base::binary) { + fopen_mode += _T("b"); + } + if (flushMode == FlushMode::Full) { + fopen_mode += _T("c"); // force commit on fflush (MSVC specific) + } + return fopen_mode; + } + + std::FILE * internal_fopen(const mpt::os_path & filename, std::ios_base::openmode mode, FlushMode flushMode) { + m_f = nullptr; + mpt::tstring fopen_mode = convert_mode(mode, flushMode); + if (fopen_mode.empty()) { + return nullptr; + } + std::FILE * f = +#ifdef UNICODE + _wfopen(mpt::support_long_path(mpt::transcode(filename)).c_str(), fopen_mode.c_str()) +#else + std::fopen(mpt::support_long_path(mpt::transcode(filename)).c_str(), fopen_mode.c_str()) +#endif + ; + if (!f) { + return nullptr; + } + if (mode & std::ios_base::ate) { + if (std::fseek(f, 0, SEEK_END) != 0) { + std::fclose(f); + f = nullptr; + return nullptr; + } + } + m_f = f; + return f; + } + +#endif // MPT_LIBCXX_MS + +public: + SafeOutputFile() = delete; + + explicit SafeOutputFile(const mpt::os_path & filename, std::ios_base::openmode mode = std::ios_base::out, FlushMode flushMode = FlushMode::Full) + : m_FlushMode(flushMode) +#if MPT_LIBCXX_MS + , m_s(internal_fopen(filename, mode | std::ios_base::out, flushMode)) +#else // !MPT_LIBCXX_MS + , m_s(filename, mode) +#endif // MPT_LIBCXX_MS + { + if (!stream().is_open()) { + stream().setstate(mpt::IO::ofstream::failbit); + } + } + + mpt::IO::ofstream & stream() { + return m_s; + } + + operator mpt::IO::ofstream &() { + return stream(); + } + + const mpt::IO::ofstream & stream() const { + return m_s; + } + + operator const mpt::IO::ofstream &() const { + return stream(); + } + + operator bool() const { + return stream() ? true : false; + } + + bool operator!() const { + return stream().operator!(); + } + + // cppcheck-suppress exceptThrowInDestructor + ~SafeOutputFile() noexcept(false) { + const bool mayThrow = (std::uncaught_exceptions() == 0); + if (!stream()) { +#if MPT_LIBCXX_MS + if (m_f) { + std::fclose(m_f); + } +#endif // MPT_LIBCXX_MS + if (mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { + // cppcheck-suppress exceptThrowInDestructor + throw std::ios_base::failure(std::string("Error before flushing file buffers.")); + } + return; + } + if (!stream().rdbuf()) { +#if MPT_LIBCXX_MS + if (m_f) { + std::fclose(m_f); + } +#endif // MPT_LIBCXX_MS + if (mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { + // cppcheck-suppress exceptThrowInDestructor + throw std::ios_base::failure(std::string("Error before flushing file buffers.")); + } + return; + } +#if MPT_LIBCXX_MS + if (!m_f) { + return; + } +#endif // MPT_LIBCXX_MS + bool errorOnFlush = false; + if (m_FlushMode != FlushMode::None) { + try { + if (stream().rdbuf()->pubsync() != 0) { + errorOnFlush = true; + } + } catch (const std::exception &) { + errorOnFlush = true; +#if MPT_LIBCXX_MS + if (m_FlushMode != FlushMode::None) { + if (std::fflush(m_f) != 0) { + errorOnFlush = true; + } + } + if (std::fclose(m_f) != 0) { + errorOnFlush = true; + } +#endif // MPT_LIBCXX_MS + if (mayThrow) { + // ignore errorOnFlush here, and re-throw the earlier exception + // cppcheck-suppress exceptThrowInDestructor + throw; + } + } + } +#if MPT_LIBCXX_MS + if (m_FlushMode != FlushMode::None) { + if (std::fflush(m_f) != 0) { + errorOnFlush = true; + } + } + if (std::fclose(m_f) != 0) { + errorOnFlush = true; + } +#endif // MPT_LIBCXX_MS + if (mayThrow && errorOnFlush && (stream().exceptions() & (std::ios::badbit | std::ios::failbit))) { + // cppcheck-suppress exceptThrowInDestructor + throw std::ios_base::failure(std::string("Error flushing file buffers.")); + } + } +}; + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_OUTPUTFILE_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp new file mode 100644 index 000000000..4ec1c4a93 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_adapter/fileadapter.hpp @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP +#define MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/base/saturate_cast.hpp" +#include "mpt/io/base.hpp" +#if !MPT_OS_WINDOWS +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/io_file/fstream.hpp" +#endif // !MPT_OS_WINDOWS +#include "mpt/io_file_unique/unique_basename.hpp" +#include "mpt/io_file_unique/unique_tempfilename.hpp" +#if MPT_OS_WINDOWS +#include "mpt/path/os_path.hpp" +#endif // MPT_OS_WINDOWS +#include "mpt/string_transcode/transcode.hpp" +#if MPT_OS_WINDOWS +#include "mpt/system_error/system_error.hpp" +#endif // MPT_OS_WINDOWS + +#include +#if !MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + +#include +#if !MPT_OS_WINDOWS +#include +#endif // !MPT_OS_WINDOWS + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + +#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS_WINRT +#if MPT_WINRT_AT_LEAST(MPT_WIN_8) +#define MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE +#endif +#else // !MPT_OS_WINDOWS_WINRT +#define MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE +#endif // MPT_OS_WINDOWS_WINRT +#endif // MPT_OS_WINDOWS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +template +class FileAdapter { + +private: + mpt::os_path m_Filename; + bool m_IsTempFile; + +public: + FileAdapter(TFileCursor & file, const mpt::os_path & tempName = unique_tempfilename{unique_basename{}, MPT_OS_PATH("tmp")}) + : m_IsTempFile(false) { + try { + file.Rewind(); + if (!file.GetOptionalFileName()) { + +#ifdef MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE + + HANDLE hFile = NULL; +#if MPT_OS_WINDOWS_WINRT + hFile = mpt::windows::CheckFileHANDLE(CreateFile2(mpt::support_long_path(tempName).c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL)); +#else + hFile = mpt::windows::CheckFileHANDLE(CreateFile(mpt::support_long_path(tempName).c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL)); +#endif + while (!file.EndOfFile()) { + typename TFileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); + std::size_t towrite = view.size(); + std::size_t written = 0; + do { + DWORD chunkSize = mpt::saturate_cast(towrite); + DWORD chunkDone = 0; + try { + mpt::windows::CheckBOOL(WriteFile(hFile, view.data() + written, chunkSize, &chunkDone, NULL)); + } catch (...) { + CloseHandle(hFile); + hFile = NULL; + throw; + } + if (chunkDone != chunkSize) { + CloseHandle(hFile); + hFile = NULL; + throw std::runtime_error("Incomplete WriteFile()."); + } + towrite -= chunkDone; + written += chunkDone; + } while (towrite > 0); + } + CloseHandle(hFile); + hFile = NULL; + +#else // !MPT_IO_FILE_ONDISKFILEWRAPPER_USE_CREATEFILE + + mpt::IO::ofstream f(tempName, std::ios::binary); + if (!f) { + throw std::runtime_error("Error creating temporary file."); + } + while (!file.EndOfFile()) { + typename TFileCursor::PinnedView view = file.ReadPinnedView(mpt::IO::BUFFERSIZE_NORMAL); + std::size_t towrite = view.size(); + std::size_t written = 0; + do { + std::size_t chunkSize = mpt::saturate_cast(towrite); + bool chunkOk = false; + chunkOk = mpt::IO::WriteRaw(f, mpt::const_byte_span(view.data() + written, chunkSize)); + if (!chunkOk) { + throw std::runtime_error("Incomplete Write."); + } + towrite -= chunkSize; + written += chunkSize; + } while (towrite > 0); + } + f.close(); + +#endif // MPT_ONDISKFILEWRAPPER_NO_CREATEFILE + + m_Filename = tempName; + m_IsTempFile = true; + } else { + m_Filename = file.GetOptionalFileName().value(); + } + } catch (const std::runtime_error &) { + m_Filename = mpt::os_path{}; + m_IsTempFile = false; + } + } + + ~FileAdapter() { + if (m_IsTempFile) { +#if MPT_OS_WINDOWS + DeleteFile(m_Filename.c_str()); +#else // !MPT_OS_WINDOWS + std::remove(m_Filename.c_str()); + //std::error_code ec{}; + //std::filesystem::remove(mpt::transcode(m_Filename.AsNative()), ec); +#endif // MPT_OS_WINDOWS + m_IsTempFile = false; + } + m_Filename = mpt::os_path{}; + } + +public: + bool IsValid() const { + return !m_Filename.empty(); + } + + mpt::os_path GetFilename() const { + return m_Filename; + } + +}; // class FileAdapter + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_ADAPTER_FILEADAPTER_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_read/inputfile_filecursor.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_read/inputfile_filecursor.hpp new file mode 100644 index 000000000..796475f34 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_read/inputfile_filecursor.hpp @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP +#define MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP + + + +#include "mpt/base/namespace.hpp" +#include "mpt/io/io.hpp" +#include "mpt/io/io_stdstream.hpp" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_read/filecursor_filename_traits.hpp" +#include "mpt/io_read/filecursor_memory.hpp" +#include "mpt/io_read/filecursor_stdstream.hpp" +#include "mpt/io_read/filecursor_traits_filedata.hpp" +#include "mpt/io_read/filedata_memory.hpp" +#include "mpt/io_read/filedata_stdstream.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +// templated in order to reduce header inter-dependencies +template +inline FileCursor> make_FileCursor(UncachedInputFile & file) { + if (!file.IsValid()) { + return FileCursor>(); + } + return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); +} + + + +// templated in order to reduce header inter-dependencies +template +inline FileCursor> make_FileCursor(CachedInputFile & file) { + if (!file.IsValid()) { + return FileCursor>(); + } + if (file.IsCached()) { + return mpt::IO::make_FileCursor(file.GetCache(), std::make_shared(file.GetFilename())); + } else { + return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); + } +} + + + +// templated in order to reduce header inter-dependencies +template +inline FileCursor> make_FileCursor(InputFile & file) { + if (!file.IsValid()) { + return FileCursor>(); + } + if (file.IsCached()) { + return mpt::IO::make_FileCursor(file.GetCache(), std::make_shared(file.GetFilename())); + } else { + return mpt::IO::make_FileCursor(file.GetStream(), std::make_shared(file.GetFilename())); + } +} + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_READ_INPUTFILE_FILECURSOR_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_basename.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_basename.hpp new file mode 100644 index 000000000..f3e79f2bc --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_basename.hpp @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP +#define MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/random/default_engines.hpp" +#include "mpt/random/device.hpp" +#include "mpt/string_transcode/transcode.hpp" +#include "mpt/uuid/uuid.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +class unique_basename { + +private: + mpt::os_path m_Basename; + +private: + static mpt::good_engine make_prng() { + mpt::sane_random_device rd; + return mpt::make_prng(rd); + } + + static mpt::UUID make_uuid() { + mpt::good_engine rng = make_prng(); + return mpt::UUID::Generate(rng); + } + +public: + explicit unique_basename(mpt::UUID uuid) + : m_Basename(mpt::transcode(uuid.ToUString())) { + return; + } + + explicit unique_basename(const mpt::os_path & prefix, mpt::UUID uuid) + : m_Basename((prefix.empty() ? prefix : prefix + MPT_OS_PATH("-")) + mpt::transcode(uuid.ToUString())) { + return; + } + + template + explicit unique_basename(Trng & rng) + : m_Basename(mpt::transcode(mpt::UUID::Generate(rng).ToUString())) { + return; + } + + template + explicit unique_basename(const mpt::os_path & prefix, Trng & rng) + : m_Basename((prefix.empty() ? prefix : prefix + MPT_OS_PATH("-")) + mpt::transcode(mpt::UUID::Generate(rng).ToUString())) { + return; + } + + explicit unique_basename() + : m_Basename(mpt::transcode(make_uuid().ToUString())) { + return; + } + +public: + operator mpt::os_path() const { + return m_Basename; + } + +}; // class unique_basename + + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_UNIQUE_UNIQUE_BASENAME_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_tempfilename.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_tempfilename.hpp new file mode 100644 index 000000000..2cc54c778 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_file_unique/unique_tempfilename.hpp @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP +#define MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/io_file_unique/unique_basename.hpp" +#include "mpt/fs/common_directories.hpp" +#include "mpt/fs/fs.hpp" +#include "mpt/path/native_path.hpp" +#include "mpt/path/os_path.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace IO { + + + +class unique_tempfilename { + +private: + mpt::os_path m_Filename; + +public: + unique_tempfilename(const unique_basename & basename, const mpt::os_path & extension = MPT_OS_PATH("tmp")) + : m_Filename(mpt::common_directories::get_temp_directory().WithTrailingSlash() + static_cast(basename) + (extension.empty() ? extension : MPT_OS_PATH(".") + extension)) { + return; + } + +public: + operator mpt::os_path() const { + return m_Filename; + } + +}; // class unique_tempfilename + + + +} // namespace IO + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_IO_FILE_UNIQUE_UNIQUE_TEMPFILENAME_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor.hpp index 5c0f862ed..788f0c9f8 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor.hpp @@ -215,7 +215,7 @@ protected: if (readableLength == 0) { return FileCursor(); } - return FileCursor(CreateChunkImpl(SharedDataContainer(), position, std::min(length, DataContainer().GetLength() - position))); + return FileCursor(CreateChunkImpl(SharedDataContainer(), position, readableLength)); } public: @@ -345,40 +345,16 @@ public: return PinnedView(*this, size, true); } - // Returns raw stream data at cursor position. - // Should only be used if absolutely necessary, for example for sample reading, or when used with a small chunk of the file retrieved by ReadChunk(). - // Use GetPinnedView(size) whenever possible. - MPT_FILECURSOR_DEPRECATED mpt::const_byte_span GetRawData() const { - // deprecated because in case of an unseekable std::istream, this triggers caching of the whole file - return mpt::span(DataContainer().GetRawData() + streamPos, DataContainer().GetLength() - streamPos); - } - template - MPT_FILECURSOR_DEPRECATED mpt::span GetRawData() const { - // deprecated because in case of an unseekable std::istream, this triggers caching of the whole file - return mpt::span(mpt::byte_cast(DataContainer().GetRawData() + streamPos), DataContainer().GetLength() - streamPos); - } - - mpt::byte_span GetRawWithOffset(std::size_t offset, mpt::byte_span dst) const { - return DataContainer().Read(streamPos + offset, dst); - } template Tspan GetRawWithOffset(std::size_t offset, Tspan dst) const { return mpt::byte_cast(DataContainer().Read(streamPos + offset, mpt::byte_cast(dst))); } - mpt::byte_span GetRaw(mpt::byte_span dst) const { - return DataContainer().Read(streamPos, dst); - } template Tspan GetRaw(Tspan dst) const { return mpt::byte_cast(DataContainer().Read(streamPos, mpt::byte_cast(dst))); } - mpt::byte_span ReadRaw(mpt::byte_span dst) { - mpt::byte_span result = DataContainer().Read(streamPos, dst); - streamPos += result.size(); - return result; - } template Tspan ReadRaw(Tspan dst) { Tspan result = mpt::byte_cast(DataContainer().Read(streamPos, mpt::byte_cast(dst))); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_callbackstream.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_callbackstream.hpp index 14fccef7f..55363ba31 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_callbackstream.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_callbackstream.hpp @@ -8,8 +8,8 @@ #include "mpt/base/namespace.hpp" #include "mpt/io_read/callbackstream.hpp" #include "mpt/io_read/filecursor.hpp" -#include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" +#include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filedata_callbackstream.hpp" #include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_filename_traits.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_filename_traits.hpp index b16212661..11016a1eb 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_filename_traits.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_filename_traits.hpp @@ -41,10 +41,13 @@ public: using filename_type = Tpath; using shared_filename_type = std::shared_ptr; - static std::optional get_optional_filename(shared_filename_type filename) { + static std::optional get_optional_filename(const shared_filename_type & filename) { if (!filename) { return std::nullopt; } + if ((*filename) == Tpath{}) { + return std::nullopt; + } return *filename; } }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_memory.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_memory.hpp index 78d954d14..2624b1588 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_memory.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_memory.hpp @@ -8,8 +8,8 @@ #include "mpt/base/namespace.hpp" #include "mpt/base/span.hpp" #include "mpt/io_read/filecursor.hpp" -#include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" +#include "mpt/io_read/filecursor_traits_filedata.hpp" #include #include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_stdstream.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_stdstream.hpp index b68d9e9a9..e2a258cc6 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_stdstream.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filecursor_stdstream.hpp @@ -7,8 +7,8 @@ #include "mpt/base/namespace.hpp" #include "mpt/io_read/filecursor.hpp" -#include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filecursor_filename_traits.hpp" +#include "mpt/io_read/filecursor_traits_filedata.hpp" #include "mpt/io_read/filedata_stdstream.hpp" #include diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata.hpp index 25c2bb640..3f079d588 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata.hpp @@ -25,7 +25,7 @@ namespace IO { class IFileData { public: - typedef std::size_t pos_type; + using pos_type = std::size_t; protected: IFileData() = default; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_base.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_base.hpp index a75dd694c..7b89086b1 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_base.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_base.hpp @@ -71,7 +71,7 @@ public: return data->IsValid(); } bool HasFastGetLength() const override { - return data->HasFastGetLength(); + return true; } bool HasPinnedView() const override { return data->HasPinnedView(); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_stdstream.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_stdstream.hpp index e7f72b12b..580df2e51 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_stdstream.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filedata_stdstream.hpp @@ -42,7 +42,7 @@ public: stream.clear(); std::streampos oldpos = stream.tellg(); stream.seekg(0, std::ios::end); - std::streampos length = stream.tellg(); + std::streamoff length = static_cast(stream.tellg()); stream.seekg(oldpos); return mpt::saturate_cast(static_cast(length)); } @@ -66,9 +66,9 @@ private: mpt::byte_span InternalReadBuffered(pos_type pos, mpt::byte_span dst) const override { stream.clear(); // tellg needs eof and fail bits unset std::streampos currentpos = stream.tellg(); - if (currentpos == std::streampos(-1) || static_cast(pos) != currentpos) { + if ((currentpos == std::streampos(std::streamoff(-1))) || (static_cast(pos) != static_cast(currentpos))) { // inefficient istream implementations might invalidate their buffer when seeking, even when seeking to the current position - stream.seekg(pos); + stream.seekg(static_cast(pos), std::ios::beg); } stream.read(mpt::byte_cast(dst.data()), dst.size()); return dst.first(static_cast(stream.gcount())); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filereader.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filereader.hpp index 84a39d6a8..ab5541187 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filereader.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/io_read/filereader.hpp @@ -15,11 +15,13 @@ #include "mpt/io/base.hpp" #include "mpt/endian/floatingpoint.hpp" #include "mpt/endian/integer.hpp" +#include "mpt/endian/type_traits.hpp" #include "mpt/string/utility.hpp" #include #include #include +#include #include #include @@ -40,6 +42,192 @@ namespace IO { namespace FileReader { + + +// TFileCursor members begin + +template +std::optional GetOptionalFileName(const TFileCursor & f) { + return f.GetOptionalFileName(); +} + +// Returns true if the object points to a valid (non-empty) stream. +template +bool IsValid(const TFileCursor & f) { + return f.IsValid(); +} + +// Reset cursor to first byte in file. +template +void Rewind(TFileCursor & f) { + f.Rewind(); +} + +// Seek to a position in the mapped file. +// Returns false if position is invalid. +template +bool Seek(TFileCursor & f, typename TFileCursor::pos_type position) { + return f.Seek(position); +} + +// Increases position by skipBytes. +// Returns true if skipBytes could be skipped or false if the file end was reached earlier. +template +bool Skip(TFileCursor & f, typename TFileCursor::pos_type skipBytes) { + return f.Skip(skipBytes); +} + +// Decreases position by skipBytes. +// Returns true if skipBytes could be skipped or false if the file start was reached earlier. +template +bool SkipBack(TFileCursor & f, typename TFileCursor::pos_type skipBytes) { + return f.SkipBack(skipBytes); +} + +// Returns cursor position in the mapped file. +template +typename TFileCursor::pos_type GetPosition(const TFileCursor & f) { + return f.GetPosition(); +} + +// Return true IFF seeking and GetLength() is fast. +// In particular, it returns false for unseekable stream where GetLength() +// requires pre-caching. +template +bool HasFastGetLength(const TFileCursor & f) { + return f.HasFastGetLength(); +} + +#if 0 +// Returns size of the mapped file in bytes. +template +MPT_FILECURSOR_DEPRECATED typename TFileCursor::pos_type GetLength(const TFileCursor & f) { + return f.GetLength(); +} +#endif + +#if 0 +// Return byte count between cursor position and end of file, i.e. how many bytes can still be read. +template +MPT_FILECURSOR_DEPRECATED typename TFileCursor::pos_type BytesLeft(const TFileCursor & f) { + return f.BytesLeft(); +} +#endif + +template +bool EndOfFile(const TFileCursor & f) { + return f.EndOfFile(); +} + +template +bool NoBytesLeft(const TFileCursor & f) { + return f.NoBytesLeft(); +} + +// Check if "amount" bytes can be read from the current position in the stream. +template +bool CanRead(const TFileCursor & f, typename TFileCursor::pos_type amount) { + return f.CanRead(amount); +} + +// Check if file size is at least size, without potentially caching the whole file to query the exact file length. +template +bool LengthIsAtLeast(const TFileCursor & f, typename TFileCursor::pos_type size) { + return f.LengthIsAtLesat(size); +} + +// Check if file size is exactly size, without potentially caching the whole file if it is larger. +template +bool LengthIs(const TFileCursor & f, typename TFileCursor::pos_type size) { + return f.LengthIs(size); +} + +// Create a new FileCursor object for parsing a sub chunk at a given position with a given length. +// The file cursor is not modified. +template +TFileCursor GetChunkAt(const TFileCursor & f, typename TFileCursor::pos_type position, typename TFileCursor::pos_type length) { + return f.GetChunkAt(position, length); +} + +// Create a new FileCursor object for parsing a sub chunk at the current position with a given length. +// The file cursor is not advanced. +template +TFileCursor GetChunk(TFileCursor & f, typename TFileCursor::pos_type length) { + return f.GetChunk(length); +} + +// Create a new FileCursor object for parsing a sub chunk at the current position with a given length. +// The file cursor is advanced by "length" bytes. +template +TFileCursor ReadChunk(TFileCursor & f, typename TFileCursor::pos_type length) { + return f.ReadChunk(length); +} + +// Returns a pinned view into the remaining raw data from cursor position. +template +typename TFileCursor::PinnedView GetPinnedView(const TFileCursor & f) { + return f.GetPinnedView(); +} + +// Returns a pinned view into the remeining raw data from cursor position, clamped at size. +template +typename TFileCursor::PinnedView GetPinnedView(const TFileCursor & f, std::size_t size) { + return f.GetPinnedView(size); +} + +// Returns a pinned view into the remeining raw data from cursor position. +// File cursor is advaned by the size of the returned pinned view. +template +typename TFileCursor::PinnedView ReadPinnedView(TFileCursor & f) { + return f.ReadPinnedView(); +} + +// Returns a pinned view into the remeining raw data from cursor position, clamped at size. +// File cursor is advaned by the size of the returned pinned view. +template +typename TFileCursor::PinnedView ReadPinnedView(TFileCursor & f, std::size_t size) { + return f.ReadPinnedView(size); +} + +template +Tspan GetRawWithOffset(const TFileCursor & f, std::size_t offset, Tspan dst) { + return f.template GetRawWithOffset(offset, dst); +} + +template +Tspan GetRaw(const TFileCursor & f, Tspan dst) { + return f.template GetRaw(dst); +} + +template +Tspan ReadRaw(TFileCursor & f, Tspan dst) { + return f.template ReadRaw(dst); +} + +template +std::vector GetRawDataAsByteVector(const TFileCursor & f) { + return f.GetRawDataAsByteVector(); +} + +template +std::vector ReadRawDataAsByteVector(TFileCursor & f) { + return f.ReadRawDataAsByteVector(); +} + +template +std::vector GetRawDataAsByteVector(const TFileCursor & f, std::size_t size) { + return f.GetRawDataAsByteVector(size); +} + +template +std::vector ReadRawDataAsByteVector(TFileCursor & f, std::size_t size) { + return f.ReadRawDataAsByteVector(size); +} + +// TFileCursor members end + + + // Read a "T" object from the stream. // If not enough bytes can be read, false is returned. // If successful, the file cursor is advanced by the size of "T". @@ -578,6 +766,8 @@ ChunkList ReadChunksUntil(TFileCursor & f, typename T return result; } + + } // namespace FileReader @@ -586,6 +776,10 @@ ChunkList ReadChunksUntil(TFileCursor & f, typename T +namespace FR = mpt::IO::FileReader; + + + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/mutex/mutex.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/mutex/mutex.hpp index 2a38eacd2..856af4e4b 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/mutex/mutex.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/mutex/mutex.hpp @@ -13,8 +13,6 @@ #define MPT_MUTEX_NONE 1 #elif MPT_COMPILER_GENERIC #define MPT_MUTEX_STD 1 -#elif MPT_OS_WINDOWS && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS) -#define MPT_MUTEX_STD 1 #elif MPT_OS_WINDOWS && MPT_LIBCXX_GNU && !defined(_GLIBCXX_HAS_GTHREADS) #define MPT_MUTEX_WIN32 1 #else @@ -32,15 +30,11 @@ #endif #if MPT_MUTEX_STD -#if !MPT_COMPILER_GENERIC && (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS) -#include -#else #include #ifdef MPT_COMPILER_QUIRK_COMPLEX_STD_MUTEX #include #include #endif -#endif #elif MPT_MUTEX_WIN32 #include #endif // MPT_MUTEX @@ -63,7 +57,7 @@ using recursive_mutex = std::recursive_mutex; #elif MPT_MUTEX_WIN32 -#if (_WIN32_WINNT >= 0x0600) // _WIN32_WINNT_VISTA +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) // compatible with c++11 std::mutex, can eventually be replaced without touching any usage site class mutex { diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/class.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/class.hpp index 2c9979660..7cdf9a3a0 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/class.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/class.hpp @@ -50,24 +50,60 @@ inline mpt::osinfo::osclass get_class_from_sysname(const std::string & sysname) result = mpt::osinfo::osclass::BSD; } else if (sysname == "Haiku") { result = mpt::osinfo::osclass::Haiku; - } else if (sysname == "MS-DOS") { + } else if (sysname == "IBMPcDos" || sysname == "CompqDOS" || sysname == "MsoftDOS" || sysname == "AT&T DOS" || sysname == "ZenitDOS" || sysname == "HP DOS" || sysname == "GrBulDOS" || sysname == "PBellDOS" || sysname == "DEC DOS" || sysname == "OlivtDOS" || sysname == "TI DOS" || sysname == "Toshiba" || sysname == "NWin3Dev" || sysname == "MSWinDev" || sysname == "RxDOS" || sysname == "PTS-DOS" || sysname == "GenSoft" || sysname == "DR-DOS" || sysname == "NovelDOS" || sysname == "FreeDOS" || sysname == "MS-DOS") { result = mpt::osinfo::osclass::DOS; } return result; } +inline std::string get_sysname() { +#if MPT_OS_WINDOWS + return "Windows"; +#else // !MPT_OS_WINDOWS + utsname uname_result; + if (uname(&uname_result) != 0) { + return {}; + } + return mpt::ReadAutoBuf(uname_result.sysname); +#endif // MPT_OS_WINDOWS +} + inline mpt::osinfo::osclass get_class() { #if MPT_OS_WINDOWS return mpt::osinfo::osclass::Windows; #else // !MPT_OS_WINDOWS - utsname uname_result; - if (uname(&uname_result) != 0) { - return mpt::osinfo::osclass::Unknown; - } - return mpt::osinfo::get_class_from_sysname(mpt::ReadAutoBuf(uname_result.sysname)); + return mpt::osinfo::get_class_from_sysname(mpt::osinfo::get_sysname()); #endif // MPT_OS_WINDOWS } +inline std::string get_class_name(mpt::osinfo::osclass c) { + std::string result; + switch (c) { + case mpt::osinfo::osclass::Unknown: + result = "unknown"; + break; + case mpt::osinfo::osclass::Windows: + result = "Windows"; + break; + case mpt::osinfo::osclass::Linux: + result = "Linux"; + break; + case mpt::osinfo::osclass::Darwin: + result = "Darwin"; + break; + case mpt::osinfo::osclass::BSD: + result = "BSD"; + break; + case mpt::osinfo::osclass::Haiku: + result = "Haiku"; + break; + case mpt::osinfo::osclass::DOS: + result = "DOS"; + break; + } + return result; +} + } // namespace osinfo diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_memory.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_memory.hpp new file mode 100644 index 000000000..da782a7a0 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_memory.hpp @@ -0,0 +1,222 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_OSINFO_DOS_MEMORY_HPP +#define MPT_OSINFO_DOS_MEMORY_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" + +#if MPT_OS_DJGPP +#include "mpt/string/buffer.hpp" +#endif // MPT_OS_DJGPP + +#if MPT_OS_DJGPP +#include +#include +#include +#include +#endif // MPT_OS_DJGPP + +#if MPT_OS_DJGPP +#include +#endif // MPT_OS_DJGPP + +#if MPT_OS_DJGPP +#include +#endif // MPT_OS_DJGPP + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace osinfo { + +namespace dos { + + + +#if MPT_OS_DJGPP + +struct memory_info { + + std::optional total_virtual; + std::optional free_virtual; + std::optional free_contiguous_virtual; + + std::optional total_physical; + std::optional free_physical; + std::optional free_contiguous_physical; + + std::optional unlocked_physical; + + std::optional total_swap; + + inline std::optional get_virtual_total() const noexcept { + if (!total_virtual) { + if (total_physical && total_swap) { + return *total_physical + *total_swap; + } else if (total_physical) { + return total_physical; + } else { + return std::nullopt; + } + } + return total_virtual; + } + inline std::optional get_virtual_used() const noexcept { + if (!get_virtual_total() || !get_virtual_free()) { + return std::nullopt; + } + if (*get_virtual_total() < *get_virtual_free()) { + return 0; + } + return *get_virtual_total() - *get_virtual_free(); + } + inline std::optional get_virtual_free() const noexcept { + if (free_virtual) { + return free_virtual; + } else if (free_contiguous_virtual) { + return free_contiguous_virtual; + } else { + return std::nullopt; + } + } + inline std::optional get_virtual_external_fragmentation() const noexcept { + if (!get_virtual_free() || !free_contiguous_virtual) { + return std::nullopt; + } + if (*get_virtual_free() < *free_contiguous_virtual) { + return 0; + } + return *get_virtual_free() - *free_contiguous_virtual; + } + inline std::optional get_virtual_free_contiguous() const noexcept { + return free_contiguous_virtual; + } + + inline std::optional get_physical_total() const noexcept { + return total_physical; + } + inline std::optional get_physical_used() const noexcept { + if (!total_physical || !get_physical_free()) { + return std::nullopt; + } + if (*total_physical < *get_physical_free()) { + return 0; + } + return *total_physical - *get_physical_free(); + } + inline std::optional get_physical_free() const noexcept { + if (free_physical) { + return free_physical; + } else if (free_contiguous_physical) { + return free_contiguous_physical; + } else { + return std::nullopt; + } + } + inline std::optional get_physical_external_fragmentation() const noexcept { + if (!get_physical_free() || !free_contiguous_physical) { + return std::nullopt; + } + if (*get_physical_free() < *free_contiguous_physical) { + return 0; + } + return *get_physical_free() - *free_contiguous_physical; + } + inline std::optional get_physical_free_contiguous() const noexcept { + return free_contiguous_physical; + } + + inline std::optional get_physical_used_locked() const noexcept { + if (!total_physical || !unlocked_physical) { + return std::nullopt; + } + if (*total_physical < *unlocked_physical) { + return 0; + } + return *total_physical - *unlocked_physical; + } + inline std::optional get_physical_freeable() const noexcept { + if (!unlocked_physical) { + return get_physical_free(); + } + return unlocked_physical; + } + + inline std::optional get_swap_total() const noexcept { + return total_swap; + } +}; + +inline memory_info get_memory_info() { + memory_info result; + __dpmi_free_mem_info dpmi_free_mem_info{}; + if (__dpmi_get_free_memory_information(&dpmi_free_mem_info) == 0) { + unsigned long page_size = 0; + if (__dpmi_get_page_size(&page_size) != 0) { + page_size = 0; + } + if (dpmi_free_mem_info.largest_available_free_block_in_bytes != 0xffffffffu) { + result.free_contiguous_virtual = dpmi_free_mem_info.largest_available_free_block_in_bytes; + } else if ((dpmi_free_mem_info.maximum_unlocked_page_allocation_in_pages != 0xffffffffu) && (page_size > 0)) { + result.free_contiguous_virtual = dpmi_free_mem_info.maximum_unlocked_page_allocation_in_pages * page_size; + } + if (page_size > 0) { + if (dpmi_free_mem_info.maximum_locked_page_allocation_in_pages != 0xffffffffu) { + result.free_contiguous_physical = dpmi_free_mem_info.maximum_locked_page_allocation_in_pages * page_size; + } + if (dpmi_free_mem_info.linear_address_space_size_in_pages != 0xffffffffu) { + result.total_virtual = dpmi_free_mem_info.linear_address_space_size_in_pages * page_size; + } + if (dpmi_free_mem_info.total_number_of_unlocked_pages != 0xffffffffu) { + result.unlocked_physical = dpmi_free_mem_info.total_number_of_unlocked_pages * page_size; + int dpmi_flags = 0; + std::array dpmi_vendor = {}; + if (__dpmi_get_capabilities(&dpmi_flags, dpmi_vendor.data()) == 0) { + char buf[126] = {}; + std::memcpy(buf, dpmi_vendor.data() + 2, 126); + // CWSDPMI does not track locked memory, thus all physical is reported unlocked + if (std::string_view(mpt::ReadAutoBuf(buf)) == std::string_view("CWSDPMI")) { + result.unlocked_physical = std::nullopt; + } + } + } + if (dpmi_free_mem_info.total_number_of_free_pages != 0xffffffffu) { + result.free_physical = dpmi_free_mem_info.total_number_of_free_pages * page_size; + } + if (dpmi_free_mem_info.total_number_of_physical_pages != 0xffffffffu) { + result.total_physical = dpmi_free_mem_info.total_number_of_physical_pages * page_size; + } + if (dpmi_free_mem_info.free_linear_address_space_in_pages != 0xffffffffu) { + result.free_virtual = dpmi_free_mem_info.free_linear_address_space_in_pages * page_size; + } + if (dpmi_free_mem_info.size_of_paging_file_partition_in_pages != 0xffffffffu) { + result.total_swap = dpmi_free_mem_info.size_of_paging_file_partition_in_pages * page_size; + } + } + } + return result; +} + +#endif // MPT_OS_DJGPP + + + +} // namespace dos + +} // namespace osinfo + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_OSINFO_DOS_MEMORY_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_version.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_version.hpp new file mode 100644 index 000000000..70738ef6a --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/dos_version.hpp @@ -0,0 +1,425 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_OSINFO_DOS_VERSION_HPP +#define MPT_OSINFO_DOS_VERSION_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/integer.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/string/buffer.hpp" + +#include + +#if MPT_OS_DJGPP +#include +#include +#include +#include +#include +#endif // MPT_OS_DJGPP + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace osinfo { + +namespace dos { + + + +class Version { + +public: + + enum class Host { + DOS, + Win2, + Win3, + Win95, + Win98, + WinME, + WinNT, + OS2, + OS2Warp, + DOSEmu, + }; + + struct System { + uint8 Major = 0; + uint8 Minor = 0; + constexpr System() noexcept + : Major(0) + , Minor(0) { + } + explicit constexpr System(uint16 number) noexcept + : Major(static_cast((number >> 8) & 0xffu)) + , Minor(static_cast((number >> 0) & 0xffu)) { + } + explicit constexpr System(uint8 major, uint8 minor) noexcept + : Major(major) + , Minor(minor) { + } + constexpr operator uint16() const noexcept { + return (static_cast(Major) << 8) | (static_cast(Minor) << 0); + } + }; + + struct DPMI { + uint8 Major = 0; + uint8 Minor = 0; + constexpr DPMI() noexcept + : Major(0) + , Minor(0) { + } + explicit constexpr DPMI(uint8 major, uint8 minor) noexcept + : Major(major) + , Minor(minor) { + } + }; + +private: + bool m_SystemIsDos = false; + + std::string m_OEM{}; + System m_System; + System m_SystemEmulated; + + DPMI m_DPMI; + std::string m_DPMIVendor{}; + DPMI m_DPMIHost; + + Host m_Host = Host::DOS; + int m_HostVersion = 0; + int m_HostRevision = 0; + int m_HostPatch = 0; + bool m_HostMultitasking = false; + bool m_HostFixedTimer = false; + + std::string m_BIOSDate{}; + +private: + Version() { + return; + } + +public: + static Version NoDos() { + return Version(); + } + + Version(std::string oem, System version, System version_emulated, DPMI dpmi, std::string dpmi_vendor, DPMI dpmi_host, Host host, int host_version, int host_revision, int host_patch, bool multitasking, bool fixedtimer, std::string bios_date) + : m_SystemIsDos(true) + , m_OEM(oem) + , m_System(version) + , m_SystemEmulated(version_emulated) + , m_DPMI(dpmi) + , m_DPMIVendor(dpmi_vendor) + , m_DPMIHost(dpmi_host) + , m_Host(host) + , m_HostVersion(host_version) + , m_HostRevision(host_revision) + , m_HostPatch(host_patch) + , m_HostMultitasking(multitasking) + , m_HostFixedTimer(fixedtimer) + , m_BIOSDate(bios_date) { + return; + } + +public: + +#if MPT_OS_DJGPP + static mpt::osinfo::dos::Version GatherDosVersion() { + uint16 dos_version = _get_dos_version(0); + uint16 dos_version_emulated = dos_version; + if (dos_version >= 0x0500) { + dos_version = _get_dos_version(1); + } + uint8 dpmi_version_major = 0; + uint8 dpmi_version_minor = 0; + __dpmi_version_ret dpmi_version{}; + if (__dpmi_get_version(&dpmi_version) == 0) { + dpmi_version_major = dpmi_version.major; + dpmi_version_minor = dpmi_version.minor; + } + std::string dpmi_host_vendor; + uint8 dpmi_host_major = 0; + uint8 dpmi_host_minor = 0; + /* if (dpmi_version_major >= 1) */ { + int dpmi_flags = 0; + std::array dpmi_vendor = {}; + if (__dpmi_get_capabilities(&dpmi_flags, dpmi_vendor.data()) == 0) { + char buf[126] = {}; + std::memcpy(buf, dpmi_vendor.data() + 2, 126); + dpmi_host_vendor = mpt::ReadAutoBuf(buf); + dpmi_host_major = dpmi_vendor[0]; + dpmi_host_minor = dpmi_vendor[1]; + } + } + if (dpmi_host_vendor.empty()) { + dpmi_host_vendor = "unknown"; + } + bool detected = false; + Host host = Host::DOS; + int host_version = 0; + int host_revision = 0; + int host_patch = 0; + bool host_multitasking = false; + bool host_fixedtimer = false; + if (!detected) { + char * os = std::getenv("OS"); + if (os) { + if (std::string(os) == std::string("Windows_NT")) { + host = Host::WinNT; + host_version = 0; + host_revision = 0; + host_patch = 0; + host_multitasking = true; + host_fixedtimer = true; + detected = true; + } + } + } + if (!detected) { + __dpmi_regs r{}; + r.x.ax = 0x1600; + __dpmi_int(0x2f, &r); + if ((r.h.al == 0x01) || (r.h.al == 0xFF)) { + host = Host::Win2; + host_version = 2; + host_revision = 0; + host_patch = 0; + host_multitasking = true; + host_fixedtimer = true; + detected = true; + } else if ((r.h.al != 0x00) && (r.h.al != 0x01) && (r.h.al != 0x80) && (r.h.al != 0xFF)) { + host_version = r.h.al; + host_revision = r.h.ah; + host_patch = 0; + if (host_version > 4) { + host = Host::WinME; + } else if ((host_version == 4) && (host_revision >= 90)) { + host = Host::WinME; + } else if ((host_version == 4) && (host_revision >= 10)) { + host = Host::Win98; + } else if (host_version == 4) { + host = Host::Win95; + } else { + host = Host::Win3; + } + host_multitasking = true; + host_fixedtimer = true; + detected = true; + } + } + if (!detected) { + __dpmi_regs r{}; + r.x.ax = 0x4010; + __dpmi_int(0x2f, &r); + if (r.x.ax != 0x4010) { + if (r.x.ax == 0x0000u) { + host = Host::OS2Warp; + } else { + host = Host::OS2; + } + host_version = r.h.bh; + host_revision = r.h.bl; + host_patch = 0; + host_multitasking = true; + host_fixedtimer = true; + detected = true; + } + } + if (!detected) { + char buf[9] = {}; + for (uint32 i = 0; i < 8; ++i) { + buf[i] = _farpeekb(_dos_ds, (0xF000u * 16) + (0xfff5u + i)); + } + buf[8] = '\0'; + if (std::string(mpt::ReadAutoBuf(buf)) == std::string("02/25/93")) { + __dpmi_regs r{}; + r.x.ax = 0; + __dpmi_int(0xe6, &r); + if (r.x.ax == 0xaa55u) { + host = Host::DOSEmu; + host_version = r.h.bh; + host_revision = r.h.bl; + host_patch = r.x.cx; + host_multitasking = true; + host_fixedtimer = true; + detected = true; + } + } + } + if (!detected) { + __dpmi_regs r{}; + r.x.ax = 0x3000; + __dpmi_int(0x21, &r); + host = Host::DOS; + host_version = r.h.al; + host_revision = r.h.ah; + host_patch = 0; + host_multitasking = false; + host_fixedtimer = false; + detected = true; + } + if (!host_multitasking) { + errno = 0; + __dpmi_yield(); + if (errno == 0) { + host_multitasking = true; + } + errno = 0; + } + std::string bios_date{}; + { + { + char buf[8 + 1] = {}; + for (uint32 i = 0; i < 8; ++i) { + buf[i] = _farpeekb(_dos_ds, (0xf000u * 16) + (0xfff5u + i)); + } + bios_date = mpt::ReadAutoBuf(buf); + } + } + return mpt::osinfo::dos::Version( + _os_flavor, + mpt::osinfo::dos::Version::System(dos_version), + mpt::osinfo::dos::Version::System(dos_version_emulated), + mpt::osinfo::dos::Version::DPMI(dpmi_version_major, dpmi_version_minor), + dpmi_host_vendor, + mpt::osinfo::dos::Version::DPMI(dpmi_host_major, dpmi_host_minor), + host, + host_version, + host_revision, + host_patch, + host_multitasking, + host_fixedtimer, + bios_date); + } + +#endif // MPT_OS_DJGPP + +public: + static inline mpt::osinfo::dos::Version Current() { +#if MPT_OS_DJGPP + static mpt::osinfo::dos::Version s_cachedVersion = GatherDosVersion(); + return s_cachedVersion; +#else // !MPT_OS_DJGPP + return mpt::osinfo::dos::Version::NoDos(); +#endif // MPT_OS_DJGPP + } + +public: + bool IsDos() const noexcept { + return m_SystemIsDos; + } + + std::string GetOEM() const { + return m_OEM; + } + + mpt::osinfo::dos::Version::System GetSystem() const noexcept { + return m_System; + } + + mpt::osinfo::dos::Version::System GetSystemEmulated() const noexcept { + return m_SystemEmulated; + } + + mpt::osinfo::dos::Version::DPMI GetDPMI() const noexcept { + return m_DPMI; + } + + std::string GetDPMIVendor() const { + return m_DPMIVendor; + } + + mpt::osinfo::dos::Version::DPMI GetDPMIHost() const noexcept { + return m_DPMIHost; + } + + mpt::osinfo::dos::Version::Host GetHost() const noexcept { + return m_Host; + } + + std::string GetHostName() const { + std::string result{}; + switch (m_Host) { + case Host::DOS: + result = "DOS"; + break; + case Host::Win2: + result = "Windows/386 2.x"; + break; + case Host::Win3: + result = "Windows 3.x"; + break; + case Host::Win95: + result = "Windows 95"; + break; + case Host::Win98: + result = "Windows 98"; + break; + case Host::WinME: + result = "Windows ME"; + break; + case Host::WinNT: + result = "Windows NT"; + break; + case Host::OS2: + result = "OS/2"; + break; + case Host::OS2Warp: + result = "OS/2 Warp"; + break; + case Host::DOSEmu: + result = "DOSEmu"; + break; + } + return result; + } + + int GetHostVersion() const noexcept { + return m_HostVersion; + } + + int GetHostRevision() const noexcept { + return m_HostRevision; + } + + int GetHostPatch() const noexcept { + return m_HostPatch; + } + + bool IsHostMultitasking() const noexcept { + return m_HostMultitasking; + } + + bool HasHostFixedTimer() const noexcept { + return m_HostFixedTimer; + } + + std::string GetBIOSDate() const { + return m_BIOSDate; + } + +}; // class Version + + +} // namespace dos + +} // namespace osinfo + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_OSINFO_DOS_VERSION_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp index 291c62678..a1acb14c9 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_version.hpp @@ -130,60 +130,56 @@ public: static mpt::osinfo::windows::Version FromSDK() noexcept { // Initialize to used SDK version -#if defined(NTDDI_VERSION) -#if NTDDI_VERSION >= 0x0A00000C // NTDDI_WIN10_NI Win11 22H2 +#if MPT_WINNT_AT_LEAST(MPT_WIN_11_22H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22621, 0); -#elif NTDDI_VERSION >= 0x0A00000B // NTDDI_WIN10_CO Win11 21H2 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_11) // 21H2 return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 22000, 0); //#elif // 22H2 // return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19045, 0); -#elif NTDDI_VERSION >= 0x0A00000A // NTDDI_WIN10_FE 21H2 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_21H2) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19044, 0); //#elif // 21H1 // return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19043, 0); //#elif // 20H2 // return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19042, 0); -#elif NTDDI_VERSION >= 0x0A000009 // NTDDI_WIN10_MN 2004/20H1 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_2004) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 19041, 0); -#elif NTDDI_VERSION >= 0x0A000008 // NTDDI_WIN10_VB 1909/19H2 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1909) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 18363, 0); -#elif NTDDI_VERSION >= 0x0A000007 // NTDDI_WIN10_19H1 1903/19H1 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1903) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 18362, 0); -#elif NTDDI_VERSION >= 0x0A000006 // NTDDI_WIN10_RS5 1809 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1809) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 17763, 0); -#elif NTDDI_VERSION >= 0x0A000005 // NTDDI_WIN10_RS4 1803 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1803) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 17134, 0); -#elif NTDDI_VERSION >= 0x0A000004 // NTDDI_WIN10_RS3 1709 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1709) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 16299, 0); -#elif NTDDI_VERSION >= 0x0A000003 // NTDDI_WIN10_RS2 1703 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1703) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 15063, 0); -#elif NTDDI_VERSION >= 0x0A000002 // NTDDI_WIN10_RS1 1607 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1607) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 14393, 0); -#elif NTDDI_VERSION >= 0x0A000001 // NTDDI_WIN10_TH2 1511 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10_1511) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 10586, 0); -#elif NTDDI_VERSION >= 0x0A000000 // NTDDI_WIN10 1507 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_10) // 1507 return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win10, mpt::osinfo::windows::Version::ServicePack(0, 0), 10240, 0); -#elif NTDDI_VERSION >= 0x06030000 // NTDDI_WINBLUE +#elif MPT_WINNT_AT_LEAST(MPT_WIN_81) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win81, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= 0x06020000 // NTDDI_WIN8 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_8) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win8, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= 0x06010000 // NTDDI_WIN7 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_7) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win7, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= 0x06000000 // NTDDI_VISTA +#elif MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinVista, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= 0x05020000 // NTDDI_WS03 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_XP64) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinXP64, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= NTDDI_WINXP +#elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinXP, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#elif NTDDI_VERSION >= NTDDI_WIN2K +#elif MPT_WINNT_AT_LEAST(MPT_WIN_2000) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::Win2000, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#else +#elif MPT_WINNT_AT_LEAST(MPT_WIN_NT4) return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::WinNT4, mpt::osinfo::windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 0); -#endif -#elif defined(_WIN32_WINNT) - return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::System((static_cast(_WIN32_WINNT) & 0xff00u) >> 8, (static_cast(_WIN32_WINNT) & 0x00ffu) >> 0), mpt::osinfo::windows::Version::ServicePack(0, 0), 0, 0); #else - return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::System(0, 0), mpt::osinfo::windows::Version::ServicePack(0, 0), 0, 0); + return mpt::osinfo::windows::Version(mpt::osinfo::windows::Version::System((static_cast(MPT_WIN_VERSION) & 0xff000000u) >> 24, (static_cast(MPT_WIN_VERSION) & 0x00ff0000u) >> 16), mpt::osinfo::windows::Version::ServicePack((static_cast(MPT_WIN_VERSION) & 0x0000ff00u) >> 8, (static_cast(MPT_WIN_VERSION) & 0x000000ffu) >> 0), 0, 0); #endif } @@ -210,12 +206,12 @@ public: #endif // MPT_COMPILER_MSVC #if MPT_COMPILER_CLANG #pragma clang diagnostic pop -#endif // MPT_COMPILER_CLANG +#endif // MPT_COMPILER_CLANG if (versioninfoex.dwPlatformId != VER_PLATFORM_WIN32_NT) { return mpt::osinfo::windows::Version::FromSDK(); } DWORD dwProductType = 0; -#if (_WIN32_WINNT >= 0x0600) // _WIN32_WINNT_VISTA +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) dwProductType = PRODUCT_UNDEFINED; if (GetProductInfo(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion, versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor, &dwProductType) == FALSE) { dwProductType = PRODUCT_UNDEFINED; @@ -232,9 +228,10 @@ public: #endif // MPT_OS_WINDOWS public: - static mpt::osinfo::windows::Version Current() noexcept { + static inline mpt::osinfo::windows::Version Current() noexcept { #if MPT_OS_WINDOWS - return GatherWindowsVersion(); + static mpt::osinfo::windows::Version s_cachedVersion = GatherWindowsVersion(); + return s_cachedVersion; #else // !MPT_OS_WINDOWS return mpt::osinfo::windows::Version::NoWindows(); #endif // MPT_OS_WINDOWS @@ -377,77 +374,6 @@ public: -namespace wine { - -class version { -protected: - bool valid = false; - uint8 vmajor = 0; - uint8 vminor = 0; - uint8 vupdate = 0; - -public: - version() { - return; - } - version(uint8 vmajor_, uint8 vminor_, uint8 vupdate_) - : valid(true) - , vmajor(vmajor_) - , vminor(vminor_) - , vupdate(vupdate_) { - return; - } - -public: - bool IsValid() const { - return valid; - } - -private: - static mpt::osinfo::windows::wine::version FromInteger(uint32 version) { - mpt::osinfo::windows::wine::version result; - result.valid = (version <= 0xffffff); - result.vmajor = static_cast(version >> 16); - result.vminor = static_cast(version >> 8); - result.vupdate = static_cast(version >> 0); - return result; - } - uint32 AsInteger() const { - uint32 version = 0; - version |= static_cast(vmajor) << 16; - version |= static_cast(vminor) << 8; - version |= static_cast(vupdate) << 0; - return version; - } - -public: - bool IsBefore(mpt::osinfo::windows::wine::version other) const { - if (!IsValid()) { - return false; - } - return (AsInteger() < other.AsInteger()); - } - bool IsAtLeast(mpt::osinfo::windows::wine::version other) const { - if (!IsValid()) { - return false; - } - return (AsInteger() >= other.AsInteger()); - } - uint8 GetMajor() const { - return vmajor; - } - uint8 GetMinor() const { - return vminor; - } - uint8 GetUpdate() const { - return vupdate; - } -}; - -} // namespace wine - - - } // namespace windows } // namespace osinfo diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_wine_version.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_wine_version.hpp new file mode 100644 index 000000000..d0e6afd89 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/osinfo/windows_wine_version.hpp @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_OSINFO_WINDOWS_WINE_VERSION_HPP +#define MPT_OSINFO_WINDOWS_WINE_VERSION_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/integer.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/osinfo/windows_version.hpp" + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace osinfo { + +namespace windows { + + + +inline bool current_is_wine() { + bool result = false; +#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT + bool hasKB2533623 = false; + mpt::osinfo::windows::Version WindowsVersion = mpt::osinfo::windows::Version::Current(); + if (WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::Win8)) { + hasKB2533623 = true; + } else if (WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::WinVista)) { + HMODULE hKernel32DLL = ::LoadLibrary(TEXT("kernel32.dll")); + if (hKernel32DLL) { + if (::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr) { + hasKB2533623 = true; + } + ::FreeLibrary(hKernel32DLL); + hKernel32DLL = NULL; + } + } + HMODULE hNTDLL = NULL; + MPT_MAYBE_CONSTANT_IF (hasKB2533623) { +#if defined(LOAD_LIBRARY_SEARCH_SYSTEM32) + hNTDLL = ::LoadLibraryEx(TEXT("ntdll.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); +#else + hNTDLL = ::LoadLibraryEx(TEXT("ntdll.dll"), NULL, 0x00000800); +#endif + } else { + hNTDLL = ::LoadLibrary(TEXT("ntdll.dll")); + } + if (hNTDLL) { + result = (::GetProcAddress(hNTDLL, "wine_get_version") != NULL); + ::FreeLibrary(hNTDLL); + } +#endif // MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT + return result; +} + + + +namespace wine { + +class version { +protected: + bool valid = false; + uint8 vmajor = 0; + uint8 vminor = 0; + uint8 vupdate = 0; + +public: + version() { + return; + } + version(uint8 vmajor_, uint8 vminor_, uint8 vupdate_) + : valid(true) + , vmajor(vmajor_) + , vminor(vminor_) + , vupdate(vupdate_) { + return; + } + +public: + bool IsValid() const { + return valid; + } + +private: + static mpt::osinfo::windows::wine::version FromInteger(uint32 version) { + mpt::osinfo::windows::wine::version result; + result.valid = (version <= 0xffffff); + result.vmajor = static_cast(version >> 16); + result.vminor = static_cast(version >> 8); + result.vupdate = static_cast(version >> 0); + return result; + } + uint32 AsInteger() const { + uint32 version = 0; + version |= static_cast(vmajor) << 16; + version |= static_cast(vminor) << 8; + version |= static_cast(vupdate) << 0; + return version; + } + +public: + bool IsBefore(mpt::osinfo::windows::wine::version other) const { + if (!IsValid()) { + return false; + } + return (AsInteger() < other.AsInteger()); + } + bool IsAtLeast(mpt::osinfo::windows::wine::version other) const { + if (!IsValid()) { + return false; + } + return (AsInteger() >= other.AsInteger()); + } + uint8 GetMajor() const { + return vmajor; + } + uint8 GetMinor() const { + return vminor; + } + uint8 GetUpdate() const { + return vupdate; + } +}; + +} // namespace wine + + + +} // namespace windows + +} // namespace osinfo + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_OSINFO_WINDOWS_WINE_VERSION_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/parse.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/parse.hpp index fe27191a2..3fdf1b678 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/parse.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/parse.hpp @@ -47,31 +47,62 @@ inline std::string parse_as_internal_string_type(const Tstring & s) { template -inline T ConvertStringTo(const Tstring & str) { +inline bool parse_into(T & dst, const Tstring & str) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(std::locale::classic()); - T value; + if constexpr (std::is_same::value) { + signed int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = tmp ? true : false; + } else if constexpr (std::is_same::value) { + signed int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = static_cast(tmp); + } else if constexpr (std::is_same::value) { + unsigned int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = static_cast(tmp); + } else { + if (!(stream >> dst)) { + return false; + } + } + return true; +} + + +template +inline T parse_or(const Tstring & str, T def) { + std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); + stream.imbue(std::locale::classic()); + T value = def; if constexpr (std::is_same::value) { int tmp; if (!(stream >> tmp)) { - return T{}; + return def; } value = tmp ? true : false; } else if constexpr (std::is_same::value) { signed int tmp; if (!(stream >> tmp)) { - return T{}; + return def; } value = static_cast(tmp); } else if constexpr (std::is_same::value) { unsigned int tmp; if (!(stream >> tmp)) { - return T{}; + return def; } value = static_cast(tmp); } else { if (!(stream >> value)) { - return T{}; + return def; } } return value; @@ -79,7 +110,82 @@ inline T ConvertStringTo(const Tstring & str) { template -inline T ConvertHexStringTo(const Tstring & str) { +inline T parse(const Tstring & str) { + return mpt::parse_or(str, T{}); +} + + +template +inline bool locale_parse_into(const std::locale & loc, T & dst, const Tstring & str) { + std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); + stream.imbue(loc); + if constexpr (std::is_same::value) { + int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = tmp ? true : false; + } else if constexpr (std::is_same::value) { + signed int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = static_cast(tmp); + } else if constexpr (std::is_same::value) { + unsigned int tmp; + if (!(stream >> tmp)) { + return false; + } + dst = static_cast(tmp); + } else { + if (!(stream >> dst)) { + return false; + } + } + return true; +} + + +template +inline T locale_parse_or(const std::locale & loc, const Tstring & str, T def) { + std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); + stream.imbue(loc); + T value = def; + if constexpr (std::is_same::value) { + signed int tmp; + if (!(stream >> tmp)) { + return def; + } + value = tmp ? true : false; + } else if constexpr (std::is_same::value) { + signed int tmp; + if (!(stream >> tmp)) { + return def; + } + value = static_cast(tmp); + } else if constexpr (std::is_same::value) { + unsigned int tmp; + if (!(stream >> tmp)) { + return def; + } + value = static_cast(tmp); + } else { + if (!(stream >> value)) { + return def; + } + } + return value; +} + + +template +inline T locale_parse(const std::locale & loc, const Tstring & str) { + return mpt::parse_or(loc, str, T{}); +} + + +template +inline T parse_hex(const Tstring & str) { std::basic_istringstream stream(mpt::parse_as_internal_string_type(mpt::as_string(str))); stream.imbue(std::locale::classic()); T value; diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/split.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/split.hpp index 9166ad7ef..1be76e2a6 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/split.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/split.hpp @@ -25,11 +25,11 @@ std::vector split_parse(const Tstring & str, const Tstring & sep = Tstring(1, std::vector vals; std::size_t pos = 0; while (str.find(sep, pos) != std::string::npos) { - vals.push_back(mpt::ConvertStringTo(str.substr(pos, str.find(sep, pos) - pos))); + vals.push_back(mpt::parse(str.substr(pos, str.find(sep, pos) - pos))); pos = str.find(sep, pos) + sep.length(); } if (!vals.empty() || (str.substr(pos).length() > 0)) { - vals.push_back(mpt::ConvertStringTo(str.substr(pos))); + vals.push_back(mpt::parse(str.substr(pos))); } return vals; } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/tests/tests_parse.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/tests/tests_parse.hpp index 5f4eea292..964da2d35 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/tests/tests_parse.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/parse/tests/tests_parse.hpp @@ -35,45 +35,45 @@ MPT_TEST_GROUP_INLINE("mpt/parse") #pragma clang diagnostic pop #endif { - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("1"), true); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("0"), false); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("2"), true); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-0"), false); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-1"), true); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("586"), 586u); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("586"), 586u); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("2147483647"), (uint32)std::numeric_limits::max()); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("4294967295"), std::numeric_limits::max()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("1"), true); + MPT_TEST_EXPECT_EQUAL(mpt::parse("0"), false); + MPT_TEST_EXPECT_EQUAL(mpt::parse("2"), true); + MPT_TEST_EXPECT_EQUAL(mpt::parse("-0"), false); + MPT_TEST_EXPECT_EQUAL(mpt::parse("-1"), true); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-9223372036854775808"), std::numeric_limits::min()); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-159"), -159); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("9223372036854775807"), std::numeric_limits::max()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("586"), 586u); + MPT_TEST_EXPECT_EQUAL(mpt::parse("2147483647"), (uint32)std::numeric_limits::max()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("4294967295"), std::numeric_limits::max()); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("85059"), 85059u); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("9223372036854775807"), (uint64)std::numeric_limits::max()); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("18446744073709551615"), std::numeric_limits::max()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("-9223372036854775808"), std::numeric_limits::min()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("-159"), -159); + MPT_TEST_EXPECT_EQUAL(mpt::parse("9223372036854775807"), std::numeric_limits::max()); - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-87.0"), -87.0f); + MPT_TEST_EXPECT_EQUAL(mpt::parse("85059"), 85059u); + MPT_TEST_EXPECT_EQUAL(mpt::parse("9223372036854775807"), (uint64)std::numeric_limits::max()); + MPT_TEST_EXPECT_EQUAL(mpt::parse("18446744073709551615"), std::numeric_limits::max()); + + MPT_TEST_EXPECT_EQUAL(mpt::parse("-87.0"), -87.0f); #if !MPT_OS_DJGPP - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("-0.5e-6"), -0.5e-6); + MPT_TEST_EXPECT_EQUAL(mpt::parse("-0.5e-6"), -0.5e-6); #endif #if !MPT_OS_DJGPP - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo("58.65403492763"), 58.65403492763); + MPT_TEST_EXPECT_EQUAL(mpt::parse("58.65403492763"), 58.65403492763); #else - MPT_TEST_EXPECT_EQUAL(std::abs(mpt::ConvertStringTo("58.65403492763") - 58.65403492763) <= 0.0001, true); + MPT_TEST_EXPECT_EQUAL(std::abs(mpt::parse("58.65403492763") - 58.65403492763) <= 0.0001, true); #endif - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo(mpt::format::val(-87.0)), -87.0f); + MPT_TEST_EXPECT_EQUAL(mpt::parse(mpt::format::val(-87.0)), -87.0f); #if !MPT_OS_DJGPP - MPT_TEST_EXPECT_EQUAL(mpt::ConvertStringTo(mpt::format::val(-0.5e-6)), -0.5e-6); + MPT_TEST_EXPECT_EQUAL(mpt::parse(mpt::format::val(-0.5e-6)), -0.5e-6); #endif - MPT_TEST_EXPECT_EQUAL(mpt::ConvertHexStringTo("fe"), 254); + MPT_TEST_EXPECT_EQUAL(mpt::parse_hex("fe"), 254); #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) - MPT_TEST_EXPECT_EQUAL(mpt::ConvertHexStringTo(L"fe"), 254); + MPT_TEST_EXPECT_EQUAL(mpt::parse_hex(L"fe"), 254); #endif // !MPT_COMPILER_QUIRK_NO_WCHAR - MPT_TEST_EXPECT_EQUAL(mpt::ConvertHexStringTo(MPT_USTRING("ffff")), 65535u); + MPT_TEST_EXPECT_EQUAL(mpt::parse_hex(MPT_USTRING("ffff")), 65535u); } } // namespace parse diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/path/basic_path.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/basic_path.hpp new file mode 100644 index 000000000..df919c0f2 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/basic_path.hpp @@ -0,0 +1,1139 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_PATH_BASIC_PATH_HPP +#define MPT_PATH_BASIC_PATH_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/macros.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/detect/mfc.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#include +#include +#include +#include +#include + +#include + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +namespace path_literals { + +template +struct literals; + +template +MPT_CONSTEVAL Tchar L(char x) { + return path_literals::literals::L(x); +} + +template +MPT_CONSTEVAL const Tchar * L(const char (&x)[N]) { + return path_literals::literals::L(x); +} + +template <> +struct literals { + using char_type = char; + static MPT_CONSTEVAL char_type L(char c) { + if (c == '\0') + return '\0'; + if (c == '\\') + return '\\'; + if (c == '/') + return '/'; + if (c == '.') + return '.'; + if (c == ':') + return ':'; + if (c == '?') + return '?'; + if (c == '*') + return '*'; + if (c == '|') + return '|'; + if (c == '<') + return '<'; + if (c == '>') + return '>'; + if (c == '\"') + return '\"'; + if (c == '_') + return '_'; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? 0 : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } + template + static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { + if (std::string_view(s) == std::string_view("")) + return ""; + if (std::string_view(s) == std::string_view("/")) + return "/"; + if (std::string_view(s) == std::string_view(".")) + return "."; + if (std::string_view(s) == std::string_view("\\")) + return "\\"; + if (std::string_view(s) == std::string_view("..")) + return ".."; + if (std::string_view(s) == std::string_view("//")) + return "//"; + if (std::string_view(s) == std::string_view("./")) + return "./"; + if (std::string_view(s) == std::string_view(".\\")) + return ".\\"; + if (std::string_view(s) == std::string_view("\\/")) + return "\\/"; + if (std::string_view(s) == std::string_view("/\\")) + return "/\\"; + if (std::string_view(s) == std::string_view("\\\\")) + return "\\\\"; + if (std::string_view(s) == std::string_view("\\\\?\\")) + return "\\\\?\\"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC")) + return "\\\\?\\UNC"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) + return "\\\\?\\UNC\\"; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? nullptr : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } +}; + +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +template <> +struct literals { + using char_type = wchar_t; + static MPT_CONSTEVAL char_type L(char c) { + if (c == '\0') + return L'\0'; + if (c == '\\') + return L'\\'; + if (c == '/') + return L'/'; + if (c == '.') + return L'.'; + if (c == ':') + return L':'; + if (c == '?') + return L'?'; + if (c == '*') + return L'*'; + if (c == '|') + return L'|'; + if (c == '<') + return L'<'; + if (c == '>') + return L'>'; + if (c == '\"') + return L'\"'; + if (c == '_') + return L'_'; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? 0 : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } + template + static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { + if (std::string_view(s) == std::string_view("")) + return L""; + if (std::string_view(s) == std::string_view("/")) + return L"/"; + if (std::string_view(s) == std::string_view(".")) + return L"."; + if (std::string_view(s) == std::string_view("\\")) + return L"\\"; + if (std::string_view(s) == std::string_view("..")) + return L".."; + if (std::string_view(s) == std::string_view("//")) + return L"//"; + if (std::string_view(s) == std::string_view("./")) + return L"./"; + if (std::string_view(s) == std::string_view(".\\")) + return L".\\"; + if (std::string_view(s) == std::string_view("\\/")) + return L"\\/"; + if (std::string_view(s) == std::string_view("/\\")) + return L"/\\"; + if (std::string_view(s) == std::string_view("\\\\")) + return L"\\\\"; + if (std::string_view(s) == std::string_view("\\\\?\\")) + return L"\\\\?\\"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC")) + return L"\\\\?\\UNC"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) + return L"\\\\?\\UNC\\"; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? nullptr : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } +}; +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + +#if MPT_CXX_AT_LEAST(20) +template <> +struct literals { + using char_type = char8_t; + static MPT_CONSTEVAL char_type L(char c) { + if (c == '\0') + return u8'\0'; + if (c == '\\') + return u8'\\'; + if (c == '/') + return u8'/'; + if (c == '.') + return u8'.'; + if (c == ':') + return u8':'; + if (c == '?') + return u8'?'; + if (c == '*') + return u8'*'; + if (c == '|') + return u8'|'; + if (c == '<') + return u8'<'; + if (c == '>') + return u8'>'; + if (c == '\"') + return u8'\"'; + if (c == '_') + return u8'_'; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? 0 : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } + template + static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { + if (std::string_view(s) == std::string_view("")) + return u8""; + if (std::string_view(s) == std::string_view("/")) + return u8"/"; + if (std::string_view(s) == std::string_view(".")) + return u8"."; + if (std::string_view(s) == std::string_view("\\")) + return u8"\\"; + if (std::string_view(s) == std::string_view("..")) + return u8".."; + if (std::string_view(s) == std::string_view("//")) + return u8"//"; + if (std::string_view(s) == std::string_view("./")) + return u8"./"; + if (std::string_view(s) == std::string_view(".\\")) + return u8".\\"; + if (std::string_view(s) == std::string_view("\\/")) + return u8"\\/"; + if (std::string_view(s) == std::string_view("/\\")) + return u8"/\\"; + if (std::string_view(s) == std::string_view("\\\\")) + return u8"\\\\"; + if (std::string_view(s) == std::string_view("\\\\?\\")) + return u8"\\\\?\\"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC")) + return u8"\\\\?\\UNC"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) + return u8"\\\\?\\UNC\\"; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? nullptr : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } +}; +#endif // C++20 + +template <> +struct literals { + using char_type = char16_t; + static MPT_CONSTEVAL char_type L(char c) { + if (c == '\0') + return u'\0'; + if (c == '\\') + return u'\\'; + if (c == '/') + return u'/'; + if (c == '.') + return u'.'; + if (c == ':') + return u':'; + if (c == '?') + return u'?'; + if (c == '*') + return u'*'; + if (c == '|') + return u'|'; + if (c == '<') + return u'<'; + if (c == '>') + return u'>'; + if (c == '\"') + return u'\"'; + if (c == '_') + return u'_'; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? 0 : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } + template + static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { + if (std::string_view(s) == std::string_view("")) + return u""; + if (std::string_view(s) == std::string_view("/")) + return u"/"; + if (std::string_view(s) == std::string_view(".")) + return u"."; + if (std::string_view(s) == std::string_view("\\")) + return u"\\"; + if (std::string_view(s) == std::string_view("..")) + return u".."; + if (std::string_view(s) == std::string_view("//")) + return u"//"; + if (std::string_view(s) == std::string_view("./")) + return u"./"; + if (std::string_view(s) == std::string_view(".\\")) + return u".\\"; + if (std::string_view(s) == std::string_view("\\/")) + return u"\\/"; + if (std::string_view(s) == std::string_view("/\\")) + return u"/\\"; + if (std::string_view(s) == std::string_view("\\\\")) + return u"\\\\"; + if (std::string_view(s) == std::string_view("\\\\?\\")) + return u"\\\\?\\"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC")) + return u"\\\\?\\UNC"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) + return u"\\\\?\\UNC\\"; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? nullptr : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } +}; + +template <> +struct literals { + using char_type = char32_t; + static MPT_CONSTEVAL char_type L(char c) { + if (c == '\0') + return U'\0'; + if (c == '\\') + return U'\\'; + if (c == '/') + return U'/'; + if (c == '.') + return U'.'; + if (c == ':') + return U':'; + if (c == '?') + return U'?'; + if (c == '*') + return U'*'; + if (c == '|') + return U'|'; + if (c == '<') + return U'<'; + if (c == '>') + return U'>'; + if (c == '\"') + return U'\"'; + if (c == '_') + return U'_'; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? 0 : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } + template + static MPT_CONSTEVAL const char_type * L(const char (&s)[N]) { + if (std::string_view(s) == std::string_view("")) + return U""; + if (std::string_view(s) == std::string_view("/")) + return U"/"; + if (std::string_view(s) == std::string_view(".")) + return U"."; + if (std::string_view(s) == std::string_view("\\")) + return U"\\"; + if (std::string_view(s) == std::string_view("..")) + return U".."; + if (std::string_view(s) == std::string_view("//")) + return U"//"; + if (std::string_view(s) == std::string_view("./")) + return U"./"; + if (std::string_view(s) == std::string_view(".\\")) + return U".\\"; + if (std::string_view(s) == std::string_view("\\/")) + return U"\\/"; + if (std::string_view(s) == std::string_view("/\\")) + return U"/\\"; + if (std::string_view(s) == std::string_view("\\\\")) + return U"\\\\"; + if (std::string_view(s) == std::string_view("\\\\?\\")) + return U"\\\\?\\"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC")) + return U"\\\\?\\UNC"; + if (std::string_view(s) == std::string_view("\\\\?\\UNC\\")) + return U"\\\\?\\UNC\\"; +#if defined(MPT_COMPILER_QUIRK_NO_CONSTEXPR_THROW) + else + return false ? nullptr : throw std::domain_error("invalid path literal"); +#else + throw std::domain_error("invalid path literal"); +#endif + } +}; + +} // namespace path_literals + + + +enum class PathStyle { + Posix, + DOS_DJGPP, + Windows9x, + WindowsNT, +}; + +template +struct PathStyleTag { + static inline constexpr PathStyle path_style = EStyle; +}; + + + +template +struct PathTraits { + + + + static inline constexpr PathStyle path_style = PathStyleTag::path_style; + using raw_path_type = TRawPath; + using char_type = typename raw_path_type::value_type; + + + + static bool IsPathSeparator(char_type c) { + using namespace path_literals; + bool result{}; + if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { + result = (c == L('\\')) || (c == L('/')); + } else if constexpr (path_style == PathStyle::Posix) { + result = (c == L('/')); + } else { + //static_assert(false); + } + return result; + } + + + + static char_type GetDefaultPathSeparator() { + using namespace path_literals; + char_type result{}; + if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { + result = L('\\'); + } else if constexpr (path_style == PathStyle::Posix) { + result = L('/'); + } else { + //static_assert(false); + } + return result; + } + + + + static bool IsValidComponentChar(char_type c) { + using namespace path_literals; + bool result = true; + if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { + if (c == L('\\') || c == L('\"') || c == L('/') || c == L(':') || c == L('?') || c == L('<') || c == L('>') || c == L('|') || c == L('*')) { + result = false; + } else { + result = true; + } + } else if constexpr (path_style == PathStyle::Posix) { + result = (c != L('/')); + } else { + // nothing + } + return result; + } + + + + static char_type InvalidComponentCharReplacement() { + using namespace path_literals; + return L('_'); + } + + + +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +// Work-around / +// . +#pragma GCC push_options +#pragma GCC optimize("O1") +// Work-around brain-damaged GCC warning 'void operator delete(void*, std::size_t)' called on a pointer to an unallocated object '"\\\000\\\000\000"'. +// Probably a duplicate of one of the many incarnations of . +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfree-nonheap-object" +#endif + static void SplitPath(raw_path_type p, raw_path_type * prefix, raw_path_type * drive, raw_path_type * dir, raw_path_type * fbase, raw_path_type * fext) { + + using namespace path_literals; + + if (prefix) { + *prefix = raw_path_type(); + } + if (drive) { + *drive = raw_path_type(); + } + if (dir) { + *dir = raw_path_type(); + } + if (fbase) { + *fbase = raw_path_type(); + } + if (fext) { + *fext = raw_path_type(); + } + + if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { + + // We cannot use CRT splitpath here, because: + // * limited to _MAX_PATH or similar + // * no support for UNC paths + // * no support for \\?\ prefixed paths + + if constexpr (path_style == PathStyle::WindowsNT) { + // remove \\?\\ prefix + if (p.substr(0, 8) == L("\\\\?\\UNC\\")) { + if (prefix) { + *prefix = L("\\\\?\\UNC"); + } + p = L("\\\\") + p.substr(8); + } else if (p.substr(0, 4) == L("\\\\?\\")) { + if (prefix) { + *prefix = L("\\\\?\\"); + } + p = p.substr(4); + } + } + + MPT_MAYBE_CONSTANT_IF (((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x)) && (p.length() >= 2) && (p.substr(0, 2) == L("\\\\") || p.substr(0, 2) == L("\\/") || p.substr(0, 2) == L("/\\") || p.substr(0, 2) == L("//"))) { + // UNC + typename raw_path_type::size_type first_slash = p.substr(2).find_first_of(L("\\/")); + if (first_slash != raw_path_type::npos) { + typename raw_path_type::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(L("\\/")); + if (second_slash != raw_path_type::npos) { + if (drive) { + *drive = p.substr(0, 2 + first_slash + 1 + second_slash); + } + p = p.substr(2 + first_slash + 1 + second_slash); + } else { + if (drive) { + *drive = p; + } + p = raw_path_type(); + } + } else { + if (drive) { + *drive = p; + } + p = raw_path_type(); + } + } else { + // local + if (p.length() >= 2 && (p[1] == L(':'))) { + if (drive) { + *drive = p.substr(0, 2); + } + p = p.substr(2); + } else { + if (drive) { + *drive = raw_path_type(); + } + } + } + typename raw_path_type::size_type last_slash = p.find_last_of(L("\\/")); + if (last_slash != raw_path_type::npos) { + if (dir) { + *dir = p.substr(0, last_slash + 1); + } + p = p.substr(last_slash + 1); + } else { + if (dir) { + *dir = raw_path_type(); + } + } + typename raw_path_type::size_type last_dot = p.find_last_of(L(".")); + if (last_dot == raw_path_type::npos) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else if (last_dot == 0) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else if (p == L(".") || p == L("..")) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else { + if (fbase) { + *fbase = p.substr(0, last_dot); + } + if (fext) { + *fext = p.substr(last_dot); + } + } + + } else if constexpr (path_style == PathStyle::Posix) { + + typename raw_path_type::size_type last_slash = p.find_last_of(L("/")); + if (last_slash != raw_path_type::npos) { + if (dir) { + *dir = p.substr(0, last_slash + 1); + } + p = p.substr(last_slash + 1); + } else { + if (dir) { + *dir = raw_path_type(); + } + } + typename raw_path_type::size_type last_dot = p.find_last_of(L(".")); + if (last_dot == raw_path_type::npos) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else if (last_dot == 0) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else if (p == L(".") || p == L("..")) { + if (fbase) { + *fbase = p; + } + if (fext) { + *fext = raw_path_type(); + } + } else { + if (fbase) { + *fbase = p.substr(0, last_dot); + } + if (fext) { + *fext = p.substr(last_dot); + } + } + + } else { + + //static_assert(false); + } + } +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +#pragma GCC diagnostic pop +#pragma GCC pop_options +#endif + + + +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +// Work-around / +// . +#pragma GCC push_options +#pragma GCC optimize("O1") +#endif + // Convert a path to its simplified form, i.e. remove ".\" and "..\" entries + // Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH + // and unlimited versions are only available on Windows 8 and later. + // Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes. + static raw_path_type Simplify(const raw_path_type & path) { + + using namespace path_literals; + + raw_path_type result{}; + + if (path.empty()) { + return result; + } + + std::vector components; + + if constexpr ((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x) || (path_style == PathStyle::DOS_DJGPP)) { + + raw_path_type root; + typename raw_path_type::size_type startPos = 0; + if (path.size() >= 2 && path[1] == L(':')) { + // Drive letter + root = path.substr(0, 2) + L('\\'); + startPos = 2; + } else MPT_MAYBE_CONSTANT_IF (((path_style == PathStyle::WindowsNT) || (path_style == PathStyle::Windows9x)) && (path.substr(0, 2) == L("\\\\"))) { + // Network share + root = L("\\\\"); + startPos = 2; + } else if (path.substr(0, 2) == L(".\\") || path.substr(0, 2) == L("./")) { + // Special case for relative paths + root = L(".\\"); + startPos = 2; + } else if (path.size() >= 1 && (path[0] == L('\\') || path[0] == L('/'))) { + // Special case for relative paths + root = L("\\"); + startPos = 1; + } + + while (startPos < path.size()) { + auto pos = path.find_first_of(L("\\/"), startPos); + if (pos == raw_path_type::npos) { + pos = path.size(); + } + raw_path_type dir = path.substr(startPos, pos - startPos); + if (dir == L("..")) { + // Go back one directory + if (!components.empty()) { + components.pop_back(); + } + } else if (dir == L(".")) { + // nop + } else if (!dir.empty()) { + components.push_back(std::move(dir)); + } + startPos = pos + 1; + } + + result = root; + result.reserve(path.size()); + for (const auto & component : components) { + result += component + L("\\"); + } + if (!components.empty()) { + result.pop_back(); + } + + } else if constexpr (path_style == PathStyle::Posix) { + + raw_path_type root; + typename raw_path_type::size_type startPos = 0; + if (path.substr(0, 2) == L("./")) { + // Special case for relative paths + root = L("./"); + startPos = 2; + } else if (path.size() >= 1 && (path[0] == L('/'))) { + // Special case for relative paths + root = L("/"); + startPos = 1; + } + + while (startPos < path.size()) { + auto pos = path.find_first_of(L("/"), startPos); + if (pos == raw_path_type::npos) { + pos = path.size(); + } + raw_path_type dir = path.substr(startPos, pos - startPos); + if (dir == L("..")) { + // Go back one directory + if (!components.empty()) { + components.pop_back(); + } + } else if (dir == L(".")) { + // nop + } else if (!dir.empty()) { + components.push_back(std::move(dir)); + } + startPos = pos + 1; + } + + result = root; + result.reserve(path.size()); + for (const auto & component : components) { + result += component + L("/"); + } + if (!components.empty()) { + result.pop_back(); + } + + } else { + + //static_assert(false); + } + + return result; + } +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +#pragma GCC pop_options +#endif + + + +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +// Work-around / +// . +#pragma GCC push_options +#pragma GCC optimize("O1") +#endif + static bool IsAbsolute(const raw_path_type & path) { + using namespace path_literals; + bool result{}; + if constexpr (path_style == PathStyle::WindowsNT) { + if (path.substr(0, 8) == L("\\\\?\\UNC\\")) { + return true; + } + if (path.substr(0, 4) == L("\\\\?\\")) { + return true; + } + if (path.substr(0, 2) == L("\\\\")) { + return true; // UNC + } + if (path.substr(0, 2) == L("//")) { + return true; // UNC + } + result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); + } else if constexpr (path_style == PathStyle::Windows9x) { + if (path.substr(0, 2) == L("\\\\")) { + return true; // UNC + } + if (path.substr(0, 2) == L("//")) { + return true; // UNC + } + result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); + } else if constexpr (path_style == PathStyle::DOS_DJGPP) { + result = (path.length()) >= 3 && (path[1] == L(':')) && IsPathSeparator(path[2]); + } else if constexpr (path_style == PathStyle::Posix) { + result = (path.length() >= 1) && IsPathSeparator(path[0]); + } else { + //static_assert(false); + } + return result; + } +#if MPT_GCC_AT_LEAST(12, 0, 0) && MPT_GCC_BEFORE(13, 1, 0) +#pragma GCC pop_options +#endif +}; + + + +template +class BasicPathString { + +public: + + using path_traits = Traits; + using raw_path_type = typename path_traits::raw_path_type; + using char_type = typename raw_path_type::value_type; + +private: + + raw_path_type path; + +public: + + template ::value, bool>::type = true> + BasicPathString(const Tpath & path_) + : path(path_) { + return; + } + + template ::value, bool>::type = true> + operator Tpath() const { + return path; + } + +public: + + BasicPathString() = default; + BasicPathString(const BasicPathString &) = default; + BasicPathString(BasicPathString &&) noexcept = default; + + BasicPathString & assign(const BasicPathString & other) { + path = other.path; + return *this; + } + + BasicPathString & assign(BasicPathString && other) noexcept { + path = std::move(other.path); + return *this; + } + + BasicPathString & operator=(const BasicPathString & other) { + return assign(other); + } + + BasicPathString & operator=(BasicPathString && other) noexcept { + return assign(std::move(other)); + } + + BasicPathString & append(const BasicPathString & other) { + path.append(other.path); + return *this; + } + + BasicPathString & operator+=(const BasicPathString & other) { + return append(other); + } + + friend BasicPathString operator+(const BasicPathString & a, const BasicPathString & b) { + return BasicPathString(a).append(b); + } + + friend bool operator<(const BasicPathString & a, const BasicPathString & b) { + return a.AsNative() < b.AsNative(); + } + + friend bool operator==(const BasicPathString & a, const BasicPathString & b) { + return a.AsNative() == b.AsNative(); + } + + friend bool operator!=(const BasicPathString & a, const BasicPathString & b) { + return a.AsNative() != b.AsNative(); + } + + bool empty() const { + return path.empty(); + } + + std::size_t length() const { + return path.size(); + } + + std::size_t Length() const { + return path.size(); + } + +public: + + raw_path_type AsNative() const { + return path; + } + + static BasicPathString FromNative(const raw_path_type & path) { + return BasicPathString(path); + } + + mpt::ustring ToUnicode() const { + return mpt::transcode(path); + } + + static BasicPathString FromUnicode(const mpt::ustring & path) { + return BasicPathString(mpt::transcode(path)); + } + + std::string ToUTF8() const { + return mpt::transcode(mpt::common_encoding::utf8, path); + } + + static BasicPathString FromUTF8(const std::string & path) { + return BasicPathString(mpt::transcode(mpt::common_encoding::utf8, path)); + } + +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + + std::wstring ToWide() const { + return mpt::transcode(path); + } + + static BasicPathString FromWide(const std::wstring & path) { + return BasicPathString(mpt::transcode(path)); + } + +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + + template ::type = true> + std::string ToLocale() const { + return mpt::transcode(mpt::logical_encoding::locale, path); + } + + template ::type = true> + static BasicPathString FromLocale(const std::string & path) { + return BasicPathString(mpt::transcode(mpt::logical_encoding::locale, path)); + } + +#if MPT_DETECTED_MFC + + CString ToCString() const { + return mpt::transcode(path); + } + + static BasicPathString FromCString(const CString & path) { + return BasicPathString(mpt::transcode(path)); + } + +#endif // MPT_DETECTED_MFC + +public: + + static bool IsPathSeparator(char_type c) { + return path_traits::IsPathSeparator(c); + } + + static char_type GetDefaultPathSeparator() { + return path_traits::GetDefaultPathSeparator(); + } + + bool HasTrailingSlash() const { + if (path.empty()) { + return false; + } + char_type c = path[path.length() - 1]; + return IsPathSeparator(c); + } + + BasicPathString AsSanitizedComponent() const { + BasicPathString result = *this; + for (auto & c : result.path) { + if (!path_traits::IsValidComponentChar(c)) { + c = path_traits::InvalidComponentCharReplacement(); + } + } + return result; + } + + BasicPathString WithoutTrailingSlash() const { + BasicPathString result = *this; + while (result.HasTrailingSlash()) { + if (result.Length() == 1) { + return result; + } + result = BasicPathString(result.AsNative().substr(0, result.AsNative().length() - 1)); + } + return result; + } + + BasicPathString WithTrailingSlash() const { + BasicPathString result = *this; + if (!result.empty() && !result.HasTrailingSlash()) { + result.path += GetDefaultPathSeparator(); + } + return result; + } + + void SplitPath(BasicPathString * prefix, BasicPathString * drive, BasicPathString * dir, BasicPathString * fbase, BasicPathString * fext) const { + path_traits::SplitPath(path, prefix ? &prefix->path : nullptr, drive ? &drive->path : nullptr, dir ? &dir->path : nullptr, fbase ? &fbase->path : nullptr, fext ? &fext->path : nullptr); + } + + // \\?\ or \\?\\UNC or empty + BasicPathString GetPrefix() const { + BasicPathString prefix; + SplitPath(&prefix, nullptr, nullptr, nullptr, nullptr); + return prefix; + } + + // Drive letter + colon, e.g. "C:" or \\server\share + BasicPathString GetDrive() const { + BasicPathString drive; + SplitPath(nullptr, &drive, nullptr, nullptr, nullptr); + return drive; + } + + // Directory, e.g. "\OpenMPT\" + BasicPathString GetDirectory() const { + BasicPathString dir; + SplitPath(nullptr, nullptr, &dir, nullptr, nullptr); + return dir; + } + + // Drive + Dir, e.g. "C:\OpenMPT\" + BasicPathString GetDirectoryWithDrive() const { + BasicPathString drive, dir; + SplitPath(nullptr, &drive, &dir, nullptr, nullptr); + return drive + dir; + } + + // File name without extension, e.g. "OpenMPT" + BasicPathString GetFilenameBase() const { + BasicPathString fname; + SplitPath(nullptr, nullptr, nullptr, &fname, nullptr); + return fname; + } + + // Extension including dot, e.g. ".exe" + BasicPathString GetFilenameExtension() const { + BasicPathString ext; + SplitPath(nullptr, nullptr, nullptr, nullptr, &ext); + return ext; + } + + // File name + extension, e.g. "OpenMPT.exe" + BasicPathString GetFilename() const { + BasicPathString name, ext; + SplitPath(nullptr, nullptr, nullptr, &name, &ext); + return name + ext; + } + + // Return the same path string with a different (or appended) extension (including "."), e.g. "foo.bar",".txt" -> "foo.txt" or "C:\OpenMPT\foo",".txt" -> "C:\OpenMPT\foo.txt" + BasicPathString ReplaceExtension(const BasicPathString & newExt) const { + return GetDirectoryWithDrive() + GetFilenameBase() + newExt; + } + + // Convert a path to its simplified form, i.e. remove ".\" and "..\" entries, similar to std::fs::path::lexically_normal + BasicPathString Simplify() const { + return BasicPathString::FromNative(path_traits::Simplify(path)); + } + + bool IsAbsolute() const { + return path_traits::IsAbsolute(path); + } + + bool is_absolute() const { + return path_traits::IsAbsolute(path); + } + + bool is_relative() const { + return !path_traits::IsAbsolute(path); + } +}; + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_PATH_BASIC_PATH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/path/native_path.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/native_path.hpp new file mode 100644 index 000000000..886630bb3 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/native_path.hpp @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_PATH_NATIVE_PATH_HPP +#define MPT_PATH_NATIVE_PATH_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/macros.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/path/basic_path.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/string/types.hpp" + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +struct NativePathStyleTag { +#if MPT_OS_WINDOWS_WINNT + static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::WindowsNT; +#elif MPT_OS_WINDOWS_WIN9X + static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Windows9x; +#elif MPT_OS_WINDOWS + static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Windows9x; +#elif MPT_OS_DJGPP + static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::DOS_DJGPP; +#else + static inline constexpr mpt::PathStyle path_style = mpt::PathStyle::Posix; +#endif +}; + +struct NativePathTraits : public PathTraits { +}; + +struct Utf8PathTraits : public PathTraits { +}; + +using native_path = BasicPathString; + +#define MPT_NATIVE_PATH(x) \ + mpt::native_path { \ + MPT_OS_PATH(x) \ + } + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_PATH_NATIVE_PATH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path.hpp new file mode 100644 index 000000000..d653484d4 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path.hpp @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_PATH_OS_PATH_HPP +#define MPT_PATH_OS_PATH_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/string/types.hpp" + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +// mpt::os_path is an alias to a string type that represents native operating system path encoding. +// Note that this differs from std::filesystem::path::string_type on both Windows and Posix. +// On Windows, we actually honor UNICODE and thus allow os_path.c_str() to be usable with WinAPI functions. +// On Posix, we use a type-safe string type in locale encoding, in contrast to the encoding-confused supposedly UTF8 std::string in std::filesystem::path. + +#if MPT_OS_WINDOWS +using os_path = mpt::winstring; +#else // !MPT_OS_WINDOWS +using os_path = mpt::lstring; +#endif // MPT_OS_WINDOWS + + + +// mpt::os_path literals that do not involve runtime conversion. + +#if MPT_OS_WINDOWS +#define MPT_OS_PATH_CHAR(x) TEXT(x) +#define MPT_OS_PATH_LITERAL(x) TEXT(x) +#define MPT_OS_PATH(x) \ + mpt::winstring { \ + TEXT(x) \ + } +#else // !MPT_OS_WINDOWS +#define MPT_OS_PATH_CHAR(x) x +#define MPT_OS_PATH_LITERAL(x) x +#define MPT_OS_PATH(x) \ + mpt::lstring { \ + x \ + } +#endif // MPT_OS_WINDOWS + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_PATH_OS_PATH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path_long.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path_long.hpp new file mode 100644 index 000000000..80cbcb6e3 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/os_path_long.hpp @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_PATH_OS_PATH_LONG_HPP +#define MPT_PATH_OS_PATH_LONG_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/string/types.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +inline mpt::os_path support_long_path(const mpt::os_path & path) { +#if MPT_OS_WINDOWS +#if !MPT_OS_WINDOWS_WINRT +#define MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX +#else // MPT_OS_WINDOWS_WINRT +// For WinRT on Windows 8, there is no official wy to determine an absolute path. +#if MPT_WINRT_AT_LEAST(MPT_WIN_10) +#define MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX +#endif // Windows >= 10 +#endif // !MPT_OS_WINDOWS_WINRT +#endif // MPT_OS_WINDOWS +#if defined(MPT_PATH_OS_PATH_USE_WINDOWS_LONG_PATH_PREFIX) + if (path.length() < MAX_PATH) { + // path is short enough + return path; + } + if (path.substr(0, 4) == MPT_OS_PATH_LITERAL("\\\\?\\")) { + // path is already in prefixed form + return path; + } + mpt::os_path absolute_path = path; + DWORD size = GetFullPathName(path.c_str(), 0, nullptr, nullptr); + if (size != 0) { + std::vector fullPathName(size, TEXT('\0')); + if (GetFullPathName(path.c_str(), size, fullPathName.data(), nullptr) != 0) { + absolute_path = fullPathName.data(); + } + } + if (absolute_path.substr(0, 2) == MPT_OS_PATH_LITERAL("\\\\")) { + // Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar + return MPT_OS_PATH_LITERAL("\\\\?\\UNC") + absolute_path.substr(1); + } else { + // Regular file: C:\foo.bar -> \\?\C:\foo.bar + return MPT_OS_PATH_LITERAL("\\\\?\\") + absolute_path; + } +#else + return path; +#endif +} + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_PATH_OS_PATH_LONG_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/path/path.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/path.hpp new file mode 100644 index 000000000..c5ea27bf6 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/path/path.hpp @@ -0,0 +1,478 @@ +/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ + +#ifndef MPT_PATH_PATH_HPP +#define MPT_PATH_PATH_HPP + + + +#include "mpt/base/detect.hpp" +#include "mpt/base/namespace.hpp" +#include "mpt/path/os_path.hpp" +#include "mpt/string/types.hpp" +#include "mpt/string_transcode/transcode.hpp" + +#if !defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) +#include +#endif // !MPT_COMPILER_QUIRK_NO_FILESYSTEM +#include +#include +#if MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) +#include +#endif // MPT_OS_WINDOWS && MPT_COMPILER_QUIRK_NO_FILESYSTEM + +#if MPT_OS_WINDOWS +#include +#endif // MPT_OS_WINDOWS + + + +namespace mpt { +inline namespace MPT_INLINE_NS { + + + +#if defined(MPT_COMPILER_QUIRK_NO_FILESYSTEM) + + + +using path = mpt::os_path; +#define MPT_PATH_CHAR(x) MPT_OSPATH_CHAR(x) +#define MPT_PATH_LITERAL(x) MPT_OSPATH_LITERAL(x) +#define MPT_PATH(x) MPT_OSPATH(x) + + + + +#else // !MPT_COMPILER_QUIRK_NO_FILESYSTEM + + + +template <> +struct make_string_type { + using type = std::filesystem::path; +}; + + +template <> +struct is_string_type : public std::true_type { }; + + + +template <> +struct string_transcoder { + using string_type = std::filesystem::path; + static inline mpt::widestring decode(const string_type & src) { + if constexpr (std::is_same::value) { + // In contrast to standard recommendation and cppreference, + // native encoding on unix-like systems with libstdc++ or libc++ is actually *NOT* UTF8, + // but instead the conventional std::locale::locale("") encoding (which happens to be UTF8 on all modern systems, but this is not guaranteed). + // Note: libstdc++ and libc++ however assume that their internal representation is UTF8, + // which implies that wstring/u32string/u16string/u8string conversions are actually broken and MUST NOT be used, ever. + return mpt::transcode(mpt::logical_encoding::locale, src.string()); +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + } else if constexpr (std::is_same::value) { + return mpt::transcode(src.wstring()); +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + } else if constexpr (std::is_same::value) { + return mpt::transcode(src.u32string()); + } else if constexpr (std::is_same::value) { + return mpt::transcode(src.u16string()); +#if MPT_CXX_AT_LEAST(20) + } else if constexpr (std::is_same::value) { + return mpt::transcode(src.u8string()); +#endif + } else { +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + return mpt::transcode(src.wstring()); +#elif MPT_OS_WINDOWS + return mpt::transcode(mpt::logical_encoding::locale, src.string()); +#else + // completely unknown implementation, assume it can sanely convert to/from UTF16/UTF32 + if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { + return mpt::transcode(src.u32string()); + } else if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { + return mpt::transcode(src.u16string()); + } else { + return mpt::transcode(src.u32string()); + } +#endif + } + } + static inline string_type encode(const mpt::widestring & src, std::filesystem::path::format fmt) { + if constexpr (std::is_same::value) { + // In contrast to standard recommendation and cppreference, + // native encoding on unix-like systems with libstdc++ or libc++ is actually *NOT* UTF8, + // but instead the conventional std::locale::locale("") encoding (which happens to be UTF8 on all modern systems, but this is not guaranteed). + // Note: libstdc++ and libc++ however assume that their internal representation is UTF8, + // which implies that wstring/u32string/u16string/u8string conversions are actually broken and MUST NOT be used, ever. + return std::filesystem::path{mpt::transcode(mpt::logical_encoding::locale, src), fmt}; +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + } else if constexpr (std::is_same::value) { + return std::filesystem::path{mpt::transcode(src), fmt}; +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + } else if constexpr (std::is_same::value) { + return std::filesystem::path{mpt::transcode(src), fmt}; + } else if constexpr (std::is_same::value) { + return std::filesystem::path{mpt::transcode(src), fmt}; +#if MPT_CXX_AT_LEAST(20) + } else if constexpr (std::is_same::value) { + return std::filesystem::path{mpt::transcode(src), fmt}; +#endif + } else { +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + return std::filesystem::path{mpt::transcode(src), fmt}; +#elif MPT_OS_WINDOWS + return std::filesystem::path{mpt::transcode(mpt::logical_encoding::locale, src), fmt}; +#else + // completely unknown implementation, assume it can sanely convert to/from UTF16/UTF32 + if constexpr (sizeof(mpt::widechar) == sizeof(char32_t)) { + return std::filesystem::path{mpt::transcode(src), fmt}; + } else if constexpr (sizeof(mpt::widechar) == sizeof(char16_t)) { + return std::filesystem::path{mpt::transcode(src), fmt}; + } else { + return std::filesystem::path{mpt::transcode(src), fmt}; + } +#endif + } + } + static inline string_type encode(const mpt::widestring & src) { + return encode(src, std::filesystem::path::auto_format); + } +}; + + + +// Best heuristics we can come up with to define std::filesystem::path literals that do not involve (or at least only non-lossy) runtime conversion. + +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +#define MPT_STDPATH_CHAR(x) L##x +#define MPT_STDPATH_LITERAL(x) L##x +#define MPT_STDPATH(x) \ + std::filesystem::path { \ + L##x \ + } +#elif MPT_OS_WINDOWS +#define MPT_STDPATH_CHAR(x) x +#define MPT_STDPATH_LITERAL(x) x +#define MPT_STDPATH(x) \ + std::filesystem::path { \ + x \ + } +#elif MPT_CXX_AT_LEAST(20) +#define MPT_STDPATH_CHAR(x) u8##x +#define MPT_STDPATH_LITERAL(x) u8##x +#define MPT_STDPATH(x) \ + std::filesystem::path { \ + u8##x \ + } +#else +#define MPT_STDPATH_CHAR(x) U##x +#define MPT_STDPATH_LITERAL(x) U##x +#define MPT_STDPATH(x) \ + std::filesystem::path { \ + U##x \ + } +#endif + + + +// std::filesystem::path offers implicit conversions to/from types of which it is confused about their encodings. +// The only way to work around this problem is to implement our own mpt::path that does not do such broken nonsense. +// We offer no implicit conversions and only explicit conversions from std::filesystem::path and mpt::os_path. + +class path { +public: + using format = std::filesystem::path::format; + using std_value_type = std::filesystem::path::value_type; + using std_string_type = std::filesystem::path; + static constexpr inline std_value_type std_preferred_separator = std::filesystem::path::preferred_separator; + using os_value_type = os_path::value_type; + using os_string_type = os_path; + static constexpr inline os_value_type os_preferred_separator = static_cast(std::filesystem::path::preferred_separator); + +private: + std::filesystem::path m_path; + +private: + template ::value, bool> = true> + explicit path(const path_type & p) + : m_path(p) { + return; + } + template ::value, bool> = true> + explicit path(path_type && p) + : m_path(std::forward(p)) { + return; + } + +public: + struct internal { + static inline path make_path(std::filesystem::path && p) { + return path{std::move(p)}; + } + }; + +public: + template ::value, bool> = true> + static path from_stdpath(const path_type & p) { + return path{p}; + } + static std::filesystem::path to_stdpath(const path & p) { + return p.m_path; + } + static os_path to_ospath(const path & p) { + return mpt::transcode(p.m_path); + } + static std::filesystem::path from_ospath(const os_path & s, std::filesystem::path::format fmt = std::filesystem::path::auto_format) { + return string_transcoder{}.encode(mpt::transcode(s), fmt); + } + +public: + path() noexcept = default; + path(const path & p) + : m_path(p.m_path) { + return; + } + path(path && p) + : m_path(std::move(p.m_path)) { + return; + } + explicit path(const os_path & s, std::filesystem::path::format fmt = std::filesystem::path::auto_format) + : m_path(from_ospath(s, fmt)) { + return; + } + path & operator=(const path & p) { + m_path = p.m_path; + return *this; + } + path & operator=(path && p) { + m_path = std::move(p.m_path); + return *this; + } + path & assign(const path & p) { + m_path = p.m_path; + return *this; + } + path & assign(path && p) { + m_path = std::move(p.m_path); + return *this; + } + path & operator/=(const path & p) { + m_path /= p.m_path; + return *this; + } + path & operator/=(path && p) { + m_path /= std::move(p.m_path); + return *this; + } + // concatenation + path & append(const path & p) { + m_path /= p.m_path; + return *this; + } + path & append(path && p) { + m_path /= std::move(p.m_path); + return *this; + } + path & operator+=(const path & p) { + m_path += p.m_path; + return *this; + } + path & operator+=(path && p) { + m_path += std::move(p.m_path); + return *this; + } + path & concat(const path & p) { + m_path += p.m_path; + return *this; + } + path & concat(path && p) { + m_path += std::move(p.m_path); + return *this; + } + // modifiers + void clear() noexcept { + m_path.clear(); + } + path & make_preferred() { + m_path.make_preferred(); + return *this; + } + path & remove_filename() { + m_path.remove_filename(); + return *this; + } + path & replace_filename(const path & replacement) { + m_path.replace_filename(replacement.m_path); + return *this; + } + path & replace_extension(const path & replacement = path()) { + m_path.replace_extension(replacement.m_path); + return *this; + } + void swap(path & other) { + m_path.swap(other.m_path); + } + // format observers + std::filesystem::path stdpath() const { + return m_path; + } + os_path ospath() const { + return to_ospath(*this); + } + // compare + int compare(const path & p) const noexcept { + return m_path.compare(p.m_path); + } + // generation + path lexically_normal() const { + return path{m_path.lexically_normal()}; + } + path lexically_relative(const path & base) const { + return path{m_path.lexically_relative(base.m_path)}; + } + path lexically_proximate(const path & base) const { + return path{m_path.lexically_proximate(base.m_path)}; + } + // decomposition + path root_name() const { + return path{m_path.root_name()}; + } + path root_directory() const { + return path{m_path.root_directory()}; + } + path root_path() const { + return path{m_path.root_path()}; + } + path relative_path() const { + return path{m_path.relative_path()}; + } + path parent_path() const { + return path{m_path.parent_path()}; + } + path filename() const { + return path{m_path.filename()}; + } + path stem() const { + return path{m_path.stem()}; + } + path extension() const { + return path{m_path.extension()}; + } + // queries + [[nodiscard]] bool empty() const noexcept { + return m_path.empty(); + } + bool has_root_path() const { + return m_path.has_root_path(); + } + bool has_root_name() const { + return m_path.has_root_name(); + } + bool has_root_directory() const { + return m_path.has_root_directory(); + } + bool has_relative_path() const { + return m_path.has_relative_path(); + } + bool has_parent_path() const { + return m_path.has_parent_path(); + } + bool has_filename() const { + return m_path.has_filename(); + } + bool has_stem() const { + return m_path.has_stem(); + } + bool has_extension() const { + return m_path.has_extension(); + } + bool is_absolute() const { + return m_path.is_absolute(); + } + bool is_relative() const { + return m_path.is_relative(); + } + // comparison operators + friend bool operator==(const path & lhs, const path & rhs) noexcept { + return lhs.m_path == rhs.m_path; + } + friend bool operator!=(const path & lhs, const path & rhs) noexcept { + return lhs.m_path != rhs.m_path; + } + friend bool operator<(const path & lhs, const path & rhs) noexcept { + return lhs.m_path < rhs.m_path; + } + friend bool operator<=(const path & lhs, const path & rhs) noexcept { + return lhs.m_path <= rhs.m_path; + } + friend bool operator>(const path & lhs, const path & rhs) noexcept { + return lhs.m_path > rhs.m_path; + } + friend bool operator>=(const path & lhs, const path & rhs) noexcept { + return lhs.m_path >= rhs.m_path; + } + // copncatenation operator + friend path operator/(const path & lhs, const path & rhs) { + return path{lhs.m_path / rhs.m_path}; + } +}; + + + +// Best heuristics we can come up with to define mpt::path literals that do not involve (or at least only non-lossy) runtime conversion. + +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +#define MPT_PATH_CHAR(x) L##x +#define MPT_PATH_LITERAL(x) L##x +#define MPT_PATH(x) mpt::path::internal::make_path(L##x) +#elif MPT_OS_WINDOWS +#define MPT_PATH_CHAR(x) x +#define MPT_PATH_LITERAL(x) x +#define MPT_PATH(x) mpt::path::internal::make_path(x) +#elif MPT_CXX_AT_LEAST(20) +#define MPT_PATH_CHAR(x) u8##x +#define MPT_PATH_LITERAL(x) u8##x +#define MPT_PATH(x) mpt::path::internal::make_path(u8##x) +#else +#define MPT_PATH_CHAR(x) U##x +#define MPT_PATH_LITERAL(x) U##x +#define MPT_PATH(x) mpt::path::internal::make_path(U##x) +#endif + + + +template <> +struct make_string_type { + using type = mpt::path; +}; + + +template <> +struct is_string_type : public std::true_type { }; + + + +template <> +struct string_transcoder { + using string_type = mpt::path; + static inline mpt::widestring decode(const string_type & src) { + return mpt::transcode(src.ospath()); + } + static inline string_type encode(const mpt::widestring & src) { + return mpt::path{mpt::transcode(src)}; + } +}; + + + +#endif // MPT_COMPILER_QUIRK_NO_FILESYSTEM + + + +} // namespace MPT_INLINE_NS +} // namespace mpt + + + +#endif // MPT_PATH_PATH_HPP diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp index b87d8405c..eafa65c76 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/buffer.hpp @@ -10,6 +10,7 @@ #include "mpt/base/saturate_cast.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string/types.hpp" +#include "mpt/string/utility.hpp" #include #include @@ -53,19 +54,19 @@ public: StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return std::basic_string_view(buf, buf + len); } bool empty() const { - return buf[0] == Tchar('\0'); + return buf[0] == char_constants::null; } StringBufRefImpl & operator=(const Tstring & str) { std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf); - std::fill(buf + std::min(str.length(), size - 1), buf + size, Tchar('\0')); + std::fill(buf + std::min(str.length(), size - 1), buf + size, char_constants::null); return *this; } }; @@ -90,18 +91,28 @@ public: StringBufRefImpl & operator=(const StringBufRefImpl &) = delete; StringBufRefImpl & operator=(StringBufRefImpl &&) = delete; operator Tstring() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return Tstring(buf, buf + len); } explicit operator std::basic_string_view() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return std::basic_string_view(buf, len); } bool empty() const { - return buf[0] == Tchar('\0'); + return buf[0] == char_constants::null; } }; +template +struct make_string_type> { + using type = Tstring; +}; + +template +struct make_string_view_type> { + using type = typename mpt::make_string_view_type::type; +}; + template @@ -210,12 +221,12 @@ public: CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } CStringBufRefImpl & operator=(const CString & str) { std::copy(str.GetString(), str.GetString() + std::min(static_cast(str.GetLength()), size - 1), buf); - std::fill(buf + std::min(static_cast(str.GetLength()), size - 1), buf + size, Tchar('\0')); + std::fill(buf + std::min(static_cast(str.GetLength()), size - 1), buf + size, char_constants::null); return *this; } }; @@ -239,11 +250,21 @@ public: CStringBufRefImpl & operator=(const CStringBufRefImpl &) = delete; CStringBufRefImpl & operator=(CStringBufRefImpl &&) = delete; operator CString() const { - std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0 + std::size_t len = std::find(buf, buf + size, char_constants::null) - buf; // terminate at \0 return CString(buf, mpt::saturate_cast(len)); } }; +template +struct make_string_type> { + using type = CString; +}; + +template +struct make_string_view_type> { + using type = CString; +}; + template inline CStringBufRefImpl::type> ReadCStringBuf(const std::array & buf) { return CStringBufRefImpl::type>(buf.data(), size); @@ -289,7 +310,7 @@ public: public: charbuf() { - std::fill(std::begin(buf), std::end(buf), Tchar('\0')); + std::fill(std::begin(buf), std::end(buf), char_constants::null); } charbuf(const charbuf &) = default; charbuf(charbuf &&) = default; @@ -336,6 +357,16 @@ public: } }; +template +struct make_string_type> { + using type = std::string; +}; + +template +struct make_string_view_type> { + using type = std::string_view; +}; + } // namespace MPT_INLINE_NS } // namespace mpt diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/types.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/types.hpp index 64df0c203..a446739dd 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/types.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/types.hpp @@ -12,7 +12,9 @@ #include "mpt/detect/mfc.hpp" #include +#include #include +#include #include @@ -32,11 +34,26 @@ enum class common_encoding { ascii, // strictly 7-bit ASCII iso8859_1, iso8859_15, - cp850, cp437, + cp737, + cp775, + cp850, + cp852, + cp855, + cp857, + cp860, + cp861, + cp862, + cp863, + cp864, + cp865, + cp866, + cp869, + cp874, windows1252, amiga, riscos, + atarist, iso8859_1_no_c1, iso8859_15_no_c1, amiga_no_c1, @@ -61,7 +78,7 @@ inline constexpr auto stdio_encoding = logical_encoding::locale; inline constexpr auto environment_encoding = logical_encoding::locale; // std::exception::what() -inline constexpr auto exception_encoding = logical_encoding::active_locale; +inline constexpr auto exception_encoding = logical_encoding::locale; @@ -166,12 +183,14 @@ constexpr Tdstchar unsafe_char_convert(Tsrcchar src) noexcept { #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) using widestring = std::wstring; +using widestring_view = std::wstring_view; using widechar = wchar_t; #define MPT_WIDECHAR(x) L##x #define MPT_WIDELITERAL(x) L##x #define MPT_WIDESTRING(x) std::wstring(L##x) #else // MPT_COMPILER_QUIRK_NO_WCHAR using widestring = std::u32string; +using widestring_view = std::u32string_view; using widechar = char32_t; #define MPT_WIDECHAR(x) U##x #define MPT_WIDELITERAL(x) U##x @@ -180,39 +199,80 @@ using widechar = char32_t; -template -struct common_encoding_char_traits : std::char_traits { +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +// Work-around for VS2017 auto template argument ICE. +// Use as encoding_char_traits::type, foo> instead of encoding_char_traits +template +struct encoding_char_traits : std::char_traits { static constexpr auto encoding() noexcept { - return common_encoding_tag; + return encoding_tag; } }; - -template -struct logical_encoding_char_traits : std::char_traits { +#else +template +struct encoding_char_traits : std::char_traits { static constexpr auto encoding() noexcept { - return logical_encoding_tag; + return encoding_tag; } }; +#endif -using lstring = std::basic_string>; +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +using lstring = std::basic_string>; +using lstring_view = std::basic_string_view>; +#else +using lstring = std::basic_string>; +using lstring_view = std::basic_string_view>; +#endif -using source_string = std::basic_string>; -using exception_string = std::basic_string>; +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +using utf8string = std::basic_string>; +using utf8string_view = std::basic_string_view>; +#else +using utf8string = std::basic_string>; +using utf8string_view = std::basic_string_view>; +#endif + +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +using source_string = std::basic_string::type, source_encoding>>; +using source_string_view = std::basic_string_view::type, source_encoding>>; +#else +using source_string = std::basic_string>; +using source_string_view = std::basic_string_view>; +#endif + +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +using exception_string = std::basic_string::type, exception_encoding>>; +using exception_string_view = std::basic_string_view::type, exception_encoding>>; +#else +using exception_string = std::basic_string>; +using exception_string_view = std::basic_string_view>; +#endif #if MPT_OS_WINDOWS template struct windows_char_traits { }; template <> -struct windows_char_traits { using string_type = mpt::lstring; }; +struct windows_char_traits { + using string_type = mpt::lstring; + using string_view_type = mpt::lstring_view; +}; +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> -struct windows_char_traits { using string_type = std::wstring; }; +struct windows_char_traits { + using string_type = std::wstring; + using string_view_type = std::wstring_view; +}; +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR using tstring = windows_char_traits::string_type; +using tstring_view = windows_char_traits::string_view_type; using winstring = mpt::tstring; +using winstring_view = mpt::tstring_view; #endif // MPT_OS_WINDOWS @@ -221,18 +281,27 @@ using winstring = mpt::tstring; #if MPT_CXX_AT_LEAST(20) using u8string = std::u8string; +using u8string_view = std::u8string_view; using u8char = char8_t; -#define MPT_U8CHAR(x) u8##x -#define MPT_U8LITERAL(x) u8##x -#define MPT_U8STRING(x) std::u8string(u8##x) +#define MPT_U8CHAR(x) u8##x +#define MPT_U8LITERAL(x) u8##x +#define MPT_U8STRING(x) std::u8string(u8##x) +#define MPT_U8STRINVIEW(x) std::u8string_view(u8##x) #else // !C++20 -using u8string = std::basic_string>; +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +using u8string = std::basic_string>; +using u8string_view = std::basic_string_view>; +#else +using u8string = std::basic_string>; +using u8string_view = std::basic_string_view>; +#endif using u8char = char; -#define MPT_U8CHAR(x) x -#define MPT_U8LITERAL(x) x -#define MPT_U8STRING(x) mpt::u8string(x) +#define MPT_U8CHAR(x) x +#define MPT_U8LITERAL(x) x +#define MPT_U8STRING(x) mpt::u8string(x) +#define MPT_U8STRINGVIEW(x) mpt::u8string_view(x) // mpt::u8string is a moderately type-safe string that is meant to contain // UTF-8 encoded char bytes. @@ -252,7 +321,7 @@ using u8char = char; -#if !defined(MPT_USTRING_MODE_UTF8_FORCE) && (MPT_COMPILER_MSVC || (MPT_DETECTED_MFC && defined(UNICODE))) +#if !defined(MPT_USTRING_MODE_UTF8_FORCE) && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) && (MPT_COMPILER_MSVC || (MPT_DETECTED_MFC && defined(UNICODE))) // Use wide strings for MSVC because this is the native encoding on // microsoft platforms. #define MPT_USTRING_MODE_WIDE 1 @@ -283,29 +352,31 @@ using u8char = char; // these are used on mpt::ustring objects. However, compiling in the // respectively other mpt::ustring mode will catch most of these anyway. -#if MPT_USTRING_MODE_WIDE -#if MPT_USTRING_MODE_UTF8 +#if MPT_USTRING_MODE_WIDE && MPT_USTRING_MODE_UTF8 #error "MPT_USTRING_MODE_WIDE and MPT_USTRING_MODE_UTF8 are mutually exclusive." #endif +#if MPT_USTRING_MODE_WIDE + using ustring = std::wstring; +using ustring_view = std::wstring_view; using uchar = wchar_t; -#define MPT_UCHAR(x) L##x -#define MPT_ULITERAL(x) L##x -#define MPT_USTRING(x) std::wstring(L##x) +#define MPT_UCHAR(x) L##x +#define MPT_ULITERAL(x) L##x +#define MPT_USTRING(x) std::wstring(L##x) +#define MPT_USTRINGVIEW(x) std::wstring_view(L##x) #endif // MPT_USTRING_MODE_WIDE #if MPT_USTRING_MODE_UTF8 -#if MPT_USTRING_MODE_WIDE -#error "MPT_USTRING_MODE_WIDE and MPT_USTRING_MODE_UTF8 are mutually exclusive." -#endif using ustring = mpt::u8string; +using ustring_view = mpt::u8string_view; using uchar = mpt::u8char; -#define MPT_UCHAR(x) MPT_U8CHAR(x) -#define MPT_ULITERAL(x) MPT_U8LITERAL(x) -#define MPT_USTRING(x) MPT_U8STRING(x) +#define MPT_UCHAR(x) MPT_U8CHAR(x) +#define MPT_ULITERAL(x) MPT_U8LITERAL(x) +#define MPT_USTRING(x) MPT_U8STRING(x) +#define MPT_USTRINGVIEW(x) MPT_U8STRINGVIEW(x) #endif // MPT_USTRING_MODE_UTF8 @@ -319,6 +390,11 @@ struct make_string_type> { using type = std::basic_string; }; +template +struct make_string_type> { + using type = std::basic_string; +}; + template struct make_string_type { using type = std::basic_string; @@ -350,6 +426,50 @@ struct make_string_type { +template +struct make_string_view_type { }; + +template +struct make_string_view_type> { + using type = std::basic_string_view; +}; + +template +struct make_string_view_type> { + using type = std::basic_string_view; +}; + +template +struct make_string_view_type { + using type = std::basic_string_view; +}; + +template +struct make_string_view_type { + using type = std::basic_string_view; +}; + +template +struct make_string_view_type { + using type = typename make_string_view_type::type; +}; + +#if MPT_DETECTED_MFC + +template <> +struct make_string_view_type { + using type = CStringW; +}; + +template <> +struct make_string_view_type { + using type = CStringA; +}; + +#endif // MPT_DETECTED_MFC + + + template struct is_string_type : public std::false_type { }; template <> @@ -378,11 +498,37 @@ struct is_string_type> : public std::true_type { } template -inline typename mpt::make_string_type::type as_string(const T & str) { - if constexpr (std::is_pointer::type>::value) { - return str ? typename mpt::make_string_type::type{str} : typename mpt::make_string_type::type{}; +struct is_string_view_type : public std::false_type { }; +template +struct is_string_view_type> : public std::true_type { }; + + + +template +inline typename mpt::make_string_type::type>::type as_string(T && str) { + if constexpr (std::is_pointer::type>::type>::value) { + return str ? typename mpt::make_string_type::type>::type{std::forward(str)} : typename mpt::make_string_type::type>::type{}; + } else if constexpr (std::is_pointer::type>::value) { + return typename mpt::make_string_type::type>::type{std::forward(str)}; + } else if constexpr (mpt::is_string_view_type::type>::value) { + return typename mpt::make_string_type::type>::type{std::forward(str)}; } else { - return str; + return std::forward(str); + } +} + + + +template +inline typename mpt::make_string_view_type::type>::type as_string_view(T && str) { + if constexpr (std::is_pointer::type>::type>::value) { + return str ? typename mpt::make_string_view_type::type>::type{std::forward(str)} : typename mpt::make_string_view_type::type>::type{}; + } else if constexpr (std::is_pointer::type>::value) { + return typename mpt::make_string_view_type::type>::type{std::forward(str)}; + } else if constexpr (mpt::is_string_view_type::type>::value) { + return typename mpt::make_string_view_type::type>::type{std::forward(str)}; + } else { + return std::forward(str); } } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/utility.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/utility.hpp index 116388cc6..3d578dd60 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string/utility.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string/utility.hpp @@ -26,6 +26,109 @@ inline namespace MPT_INLINE_NS { +template +struct char_constants { }; + +template <> +struct char_constants { + static inline constexpr char null = '\0'; + static inline constexpr char tab = '\t'; + static inline constexpr char lf = '\n'; + static inline constexpr char cr = '\r'; + static inline constexpr char space = ' '; + static inline constexpr char plus = '+'; + static inline constexpr char comma = ','; + static inline constexpr char minus = '-'; + static inline constexpr char number0 = '0'; + static inline constexpr char number1 = '1'; + static inline constexpr char number9 = '9'; + static inline constexpr char A = 'A'; + static inline constexpr char Z = 'Z'; + static inline constexpr char a = 'a'; + static inline constexpr char z = 'z'; +}; + +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) +template <> +struct char_constants { + static inline constexpr wchar_t null = L'\0'; + static inline constexpr wchar_t tab = L'\t'; + static inline constexpr wchar_t lf = L'\n'; + static inline constexpr wchar_t cr = L'\r'; + static inline constexpr wchar_t space = L' '; + static inline constexpr wchar_t plus = L'+'; + static inline constexpr wchar_t comma = L','; + static inline constexpr wchar_t minus = L'-'; + static inline constexpr wchar_t number0 = L'0'; + static inline constexpr wchar_t number1 = L'1'; + static inline constexpr wchar_t number9 = L'9'; + static inline constexpr wchar_t A = L'A'; + static inline constexpr wchar_t Z = L'Z'; + static inline constexpr wchar_t a = L'a'; + static inline constexpr wchar_t z = L'z'; +}; +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + +#if MPT_CXX_AT_LEAST(20) +template <> +struct char_constants { + static inline constexpr char8_t null = u8'\0'; + static inline constexpr char8_t tab = u8'\t'; + static inline constexpr char8_t lf = u8'\n'; + static inline constexpr char8_t cr = u8'\r'; + static inline constexpr char8_t space = u8' '; + static inline constexpr char8_t plus = u8'+'; + static inline constexpr char8_t comma = u8','; + static inline constexpr char8_t minus = u8'-'; + static inline constexpr char8_t number0 = u8'0'; + static inline constexpr char8_t number1 = u8'1'; + static inline constexpr char8_t number9 = u8'9'; + static inline constexpr char8_t A = u8'A'; + static inline constexpr char8_t Z = u8'Z'; + static inline constexpr char8_t a = u8'a'; + static inline constexpr char8_t z = u8'z'; +}; +#endif + +template <> +struct char_constants { + static inline constexpr char16_t null = u'\0'; + static inline constexpr char16_t tab = u'\t'; + static inline constexpr char16_t lf = u'\n'; + static inline constexpr char16_t cr = u'\r'; + static inline constexpr char16_t space = u' '; + static inline constexpr char16_t plus = u'+'; + static inline constexpr char16_t comma = u','; + static inline constexpr char16_t minus = u'-'; + static inline constexpr char16_t number0 = u'0'; + static inline constexpr char16_t number1 = u'1'; + static inline constexpr char16_t number9 = u'9'; + static inline constexpr char16_t A = u'A'; + static inline constexpr char16_t Z = u'Z'; + static inline constexpr char16_t a = u'a'; + static inline constexpr char16_t z = u'z'; +}; + +template <> +struct char_constants { + static inline constexpr char32_t null = U'\0'; + static inline constexpr char32_t tab = U'\t'; + static inline constexpr char32_t lf = U'\n'; + static inline constexpr char32_t cr = U'\r'; + static inline constexpr char32_t space = U' '; + static inline constexpr char32_t plus = U'+'; + static inline constexpr char32_t comma = U','; + static inline constexpr char32_t minus = U'-'; + static inline constexpr char32_t number0 = U'0'; + static inline constexpr char32_t number1 = U'1'; + static inline constexpr char32_t number9 = U'9'; + static inline constexpr char32_t A = U'A'; + static inline constexpr char32_t Z = U'Z'; + static inline constexpr char32_t a = U'a'; + static inline constexpr char32_t z = U'z'; +}; + + // string_traits abstract the API of underlying string classes, in particular they allow adopting to CString without having to specialize for CString explicitly template @@ -34,6 +137,7 @@ struct string_traits { using string_type = Tstring; using size_type = typename string_type::size_type; using char_type = typename string_type::value_type; + using unsigned_char_type = typename std::make_unsigned::type; static inline std::size_t length(const string_type & str) { return str.length(); @@ -43,19 +147,26 @@ struct string_traits { str.reserve(size); } - static inline string_type & append(string_type & str, const string_type & a) { - return str.append(a); + static inline void set_at(string_type & str, size_type pos, char_type c) { + str.data()[pos] = c; } - static inline string_type & append(string_type & str, string_type && a) { - return str.append(std::move(a)); + + static inline void append(string_type & str, const string_type & a) { + str.append(a); } - static inline string_type & append(string_type & str, std::size_t count, char_type c) { - return str.append(count, c); + static inline void append(string_type & str, string_type && a) { + str.append(std::move(a)); + } + static inline void append(string_type & str, std::size_t count, char_type c) { + str.append(count, c); + } + static inline void append(string_type & str, char_type c) { + str.append(1, c); } static inline string_type pad(string_type str, std::size_t left, std::size_t right) { - str.insert(str.begin(), left, char_type(' ')); - str.insert(str.end(), right, char_type(' ')); + str.insert(str.begin(), left, char_constants::space); + str.insert(str.end(), right, char_constants::space); return str; } }; @@ -68,6 +179,7 @@ struct string_traits { using string_type = CStringA; using size_type = int; using char_type = typename CStringA::XCHAR; + using unsigned_char_type = typename std::make_unsigned::type; static inline size_type length(const string_type & str) { return str.GetLength(); @@ -77,25 +189,30 @@ struct string_traits { str.Preallocate(size); } - static inline string_type & append(string_type & str, const string_type & a) { - str += a; - return str; + static inline void set_at(string_type & str, size_type pos, char_type c) { + str.SetAt(pos, c); } - static inline string_type & append(string_type & str, size_type count, char_type c) { + + static inline void append(string_type & str, const string_type & a) { + str.Append(a); + } + static inline void append(string_type & str, size_type count, char_type c) { while (count--) { str.AppendChar(c); } - return str; + } + static inline void append(string_type & str, char_type c) { + str.AppendChar(c); } static inline string_type pad(const string_type & str, size_type left, size_type right) { string_type tmp; while (left--) { - tmp.AppendChar(char_type(' ')); + tmp.AppendChar(char_constants::space); } tmp += str; while (right--) { - tmp.AppendChar(char_type(' ')); + tmp.AppendChar(char_constants::space); } return tmp; } @@ -107,6 +224,7 @@ struct string_traits { using string_type = CStringW; using size_type = int; using char_type = typename CStringW::XCHAR; + using unsigned_char_type = typename std::make_unsigned::type; static inline size_type length(const string_type & str) { return str.GetLength(); @@ -116,25 +234,30 @@ struct string_traits { str.Preallocate(size); } - static inline string_type & append(string_type & str, const string_type & a) { - str += a; - return str; + static inline void set_at(string_type & str, size_type pos, char_type c) { + str.SetAt(pos, c); } - static inline string_type & append(string_type & str, size_type count, char_type c) { + + static inline void append(string_type & str, const string_type & a) { + str.Append(a); + } + static inline void append(string_type & str, size_type count, char_type c) { while (count--) { str.AppendChar(c); } - return str; + } + static inline void append(string_type & str, char_type c) { + str.AppendChar(c); } static inline string_type pad(const string_type & str, size_type left, size_type right) { string_type tmp; while (left--) { - tmp.AppendChar(char_type(' ')); + tmp.AppendChar(char_constants::space); } tmp += str; while (right--) { - tmp.AppendChar(char_type(' ')); + tmp.AppendChar(char_constants::space); } return tmp; } @@ -143,89 +266,6 @@ struct string_traits { #endif // MPT_DETECTED_MFC -template -struct char_constants { - static inline constexpr Tchar space = ' '; - static inline constexpr Tchar a = 'a'; - static inline constexpr Tchar z = 'z'; - static inline constexpr Tchar A = 'A'; - static inline constexpr Tchar Z = 'Z'; - static inline constexpr Tchar lf = '\n'; - static inline constexpr Tchar cr = '\r'; - static inline constexpr Tchar tab = '\t'; - static inline constexpr Tchar comma = ','; -}; - -template <> -struct char_constants { - static inline constexpr char space = ' '; - static inline constexpr char a = 'a'; - static inline constexpr char z = 'z'; - static inline constexpr char A = 'A'; - static inline constexpr char Z = 'Z'; - static inline constexpr char lf = '\n'; - static inline constexpr char cr = '\r'; - static inline constexpr char tab = '\t'; - static inline constexpr char comma = ','; -}; - -#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) -template <> -struct char_constants { - static inline constexpr wchar_t space = L' '; - static inline constexpr wchar_t a = L'a'; - static inline constexpr wchar_t z = L'z'; - static inline constexpr wchar_t A = L'A'; - static inline constexpr wchar_t Z = L'Z'; - static inline constexpr wchar_t lf = L'\n'; - static inline constexpr wchar_t cr = L'\r'; - static inline constexpr wchar_t tab = L'\t'; - static inline constexpr wchar_t comma = L','; -}; -#endif // !MPT_COMPILER_QUIRK_NO_WCHAR - -#if MPT_CXX_AT_LEAST(20) -template <> -struct char_constants { - static inline constexpr char8_t space = u8' '; - static inline constexpr char8_t a = u8'a'; - static inline constexpr char8_t z = u8'z'; - static inline constexpr char8_t A = u8'A'; - static inline constexpr char8_t Z = u8'Z'; - static inline constexpr char8_t lf = u8'\n'; - static inline constexpr char8_t cr = u8'\r'; - static inline constexpr char8_t tab = u8'\t'; - static inline constexpr char8_t comma = u8','; -}; -#endif - -template <> -struct char_constants { - static inline constexpr char16_t space = u' '; - static inline constexpr char16_t a = u'a'; - static inline constexpr char16_t z = u'z'; - static inline constexpr char16_t A = u'A'; - static inline constexpr char16_t Z = u'Z'; - static inline constexpr char16_t lf = u'\n'; - static inline constexpr char16_t cr = u'\r'; - static inline constexpr char16_t tab = u'\t'; - static inline constexpr char16_t comma = u','; -}; - -template <> -struct char_constants { - static inline constexpr char32_t space = U' '; - static inline constexpr char32_t a = U'a'; - static inline constexpr char32_t z = U'z'; - static inline constexpr char32_t A = U'A'; - static inline constexpr char32_t Z = U'Z'; - static inline constexpr char32_t lf = U'\n'; - static inline constexpr char32_t cr = U'\r'; - static inline constexpr char32_t tab = U'\t'; - static inline constexpr char32_t comma = U','; -}; - - template constexpr bool is_any_line_ending(Tchar c) noexcept { return (c == char_constants::cr) || (c == char_constants::lf); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/tests/tests_string_transcode.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/tests/tests_string_transcode.hpp index ba4398751..6b852c9f1 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/tests/tests_string_transcode.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/tests/tests_string_transcode.hpp @@ -14,6 +14,7 @@ #include "mpt/test/test_macros.hpp" #include +#include @@ -234,6 +235,14 @@ MPT_TEST_GROUP_INLINE("mpt/string_transcode") #endif #endif // !MPT_COMPILER_QUIRK_NO_WCHAR + + // string_view + MPT_TEST_EXPECT_EQUAL(mpt::transcode(U"foo"), MPT_USTRING("foo")); + MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::u32string_view(U"foo")), MPT_USTRING("foo")); + MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::u32string(U"foo")), MPT_USTRING("foo")); + + // bogus unknown -> unknown transcode + MPT_TEST_EXPECT_EQUAL(mpt::transcode(std::string("foo")), std::string("foo")); } } // namespace string_transcode diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp index cdb53b611..7f19adbf2 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/string_transcode/transcode.hpp @@ -12,18 +12,23 @@ #include "mpt/base/saturate_cast.hpp" #include "mpt/detect/mfc.hpp" #include "mpt/string/types.hpp" +#include "mpt/string/utility.hpp" #include #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #include #endif // !MPT_COMPILER_QUIRK_NO_WCHAR +#include #include #include #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) #include #endif // !MPT_COMPILER_QUIRK_NO_WCHAR +#include #include +#include + #if MPT_OS_DJGPP #include #endif // MPT_OS_DJGPP @@ -44,6 +49,9 @@ inline namespace MPT_INLINE_NS { + +inline constexpr char32_t UCS4ud = 0xffffffffu; + // default 1:1 mapping inline constexpr char32_t CharsetTableISO8859_1[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, @@ -99,23 +107,28 @@ inline constexpr char32_t CharsetTableWindows1252[256] = { 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; -inline constexpr char32_t CharsetTableCP850[256] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00F8, 0x00a3, 0x00D8, 0x00D7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00AE, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00A2, 0x00A5, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00E3, 0x00C3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00A4, - 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250c, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, - 0x00D3, 0x00df, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00b5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, - 0x00AD, 0x00b1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00f7, 0x00B8, 0x00b0, 0x00A8, 0x00b7, 0x00B9, 0x00B3, 0x00b2, 0x25a0, 0x00a0}; +// cat CP437.TXT | grep -v '^#' | head -n 256 | awk '{print $2;}' | ./tablerize.py > cp437.h +/* +#!/usr/bin/env python3 + +import fileinput + +i = 0 +for line in fileinput.input(): + if i % 16 == 0: + print("\t", end='') + print(line.strip(), end='') + i = i + 1 + if i % 256 != 0: + print(",", end='') + if i % 16 != 0: + print(" ", end='') + if i % 16 == 0: + if i % 256 == 0: + print("};\n", end='') + else: + print("\n", end='') +*/ inline constexpr char32_t CharsetTableCP437[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, @@ -125,7 +138,7 @@ inline constexpr char32_t CharsetTableCP437[256] = { 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, @@ -135,6 +148,276 @@ inline constexpr char32_t CharsetTableCP437[256] = { 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; +inline constexpr char32_t CharsetTableCP737[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, + 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, + 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03c9, 0x03ac, 0x03ad, 0x03ae, 0x03ca, 0x03af, 0x03cc, 0x03cd, 0x03cb, 0x03ce, 0x0386, 0x0388, 0x0389, 0x038a, 0x038c, 0x038e, + 0x038f, 0x00b1, 0x2265, 0x2264, 0x03aa, 0x03ab, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP775[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0106, 0x00fc, 0x00e9, 0x0101, 0x00e4, 0x0123, 0x00e5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012b, 0x0179, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x014d, 0x00f6, 0x0122, 0x00a2, 0x015a, 0x015b, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x00a4, + 0x0100, 0x012a, 0x00f3, 0x017b, 0x017c, 0x017a, 0x201d, 0x00a6, 0x00a9, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x0141, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010c, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255d, 0x012e, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0172, 0x016a, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x017d, + 0x0105, 0x010d, 0x0119, 0x0117, 0x012f, 0x0161, 0x0173, 0x016b, 0x017e, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x00d3, 0x00df, 0x014c, 0x0143, 0x00f5, 0x00d5, 0x00b5, 0x0144, 0x0136, 0x0137, 0x013b, 0x013c, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00ad, 0x00b1, 0x201c, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x201e, 0x00b0, 0x2219, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP850[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, + 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, + 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4, + 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP852[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x016f, 0x0107, 0x00e7, 0x0142, 0x00eb, 0x0150, 0x0151, 0x00ee, 0x0179, 0x00c4, 0x0106, + 0x00c9, 0x0139, 0x013a, 0x00f4, 0x00f6, 0x013d, 0x013e, 0x015a, 0x015b, 0x00d6, 0x00dc, 0x0164, 0x0165, 0x0141, 0x00d7, 0x010d, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x0104, 0x0105, 0x017d, 0x017e, 0x0118, 0x0119, 0x00ac, 0x017a, 0x010c, 0x015f, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x011a, 0x015e, 0x2563, 0x2551, 0x2557, 0x255d, 0x017b, 0x017c, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x0102, 0x0103, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, + 0x0111, 0x0110, 0x010e, 0x00cb, 0x010f, 0x0147, 0x00cd, 0x00ce, 0x011b, 0x2518, 0x250c, 0x2588, 0x2584, 0x0162, 0x016e, 0x2580, + 0x00d3, 0x00df, 0x00d4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00da, 0x0155, 0x0170, 0x00fd, 0x00dd, 0x0163, 0x00b4, + 0x00ad, 0x02dd, 0x02db, 0x02c7, 0x02d8, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x02d9, 0x0171, 0x0158, 0x0159, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP855[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045a, 0x040a, 0x045b, 0x040b, 0x045c, 0x040c, 0x045e, 0x040e, 0x045f, 0x040f, 0x044e, 0x042e, 0x044a, 0x042a, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255d, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x043a, 0x041a, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, + 0x043b, 0x041b, 0x043c, 0x041c, 0x043d, 0x041d, 0x043e, 0x041e, 0x043f, 0x2518, 0x250c, 0x2588, 0x2584, 0x041f, 0x044f, 0x2580, + 0x042f, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044c, 0x042c, 0x2116, + 0x00ad, 0x044b, 0x042b, 0x0437, 0x0417, 0x0448, 0x0428, 0x044d, 0x042d, 0x0449, 0x0429, 0x0447, 0x0427, 0x00a7, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP857[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x0131, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x0130, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x015e, 0x015f, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x011e, 0x011f, 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4, + 0x00ba, 0x00aa, 0x00ca, 0x00cb, 0x00c8, UCS4ud, 0x00cd, 0x00ce, 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580, + 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, UCS4ud, 0x00d7, 0x00da, 0x00db, 0x00d9, 0x00ec, 0x00ff, 0x00af, 0x00b4, + 0x00ad, 0x00b1, UCS4ud, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8, 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP860[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e3, 0x00e0, 0x00c1, 0x00e7, 0x00ea, 0x00ca, 0x00e8, 0x00cd, 0x00d4, 0x00ec, 0x00c3, 0x00c2, + 0x00c9, 0x00c0, 0x00c8, 0x00f4, 0x00f5, 0x00f2, 0x00da, 0x00f9, 0x00cc, 0x00d5, 0x00dc, 0x00a2, 0x00a3, 0x00d9, 0x20a7, 0x00d3, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00d2, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP861[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00d0, 0x00f0, 0x00de, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00fe, 0x00fb, 0x00dd, 0x00fd, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00c1, 0x00cd, 0x00d3, 0x00da, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP862[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP863[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00c2, 0x00e0, 0x00b6, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x2017, 0x00c0, 0x00a7, + 0x00c9, 0x00c8, 0x00ca, 0x00f4, 0x00cb, 0x00cf, 0x00fb, 0x00f9, 0x00a4, 0x00d4, 0x00dc, 0x00a2, 0x00a3, 0x00d9, 0x00db, 0x0192, + 0x00a6, 0x00b4, 0x00f3, 0x00fa, 0x00a8, 0x00b8, 0x00b3, 0x00af, 0x00ce, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00be, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP864[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066a, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00b0, 0x00b7, 0x2219, 0x221a, 0x2592, 0x2500, 0x2502, 0x253c, 0x2524, 0x252c, 0x251c, 0x2534, 0x2510, 0x250c, 0x2514, 0x2518, + 0x03b2, 0x221e, 0x03c6, 0x00b1, 0x00bd, 0x00bc, 0x2248, 0x00ab, 0x00bb, 0xfef7, 0xfef8, UCS4ud, UCS4ud, 0xfefb, 0xfefc, UCS4ud, + 0x00a0, 0x00ad, 0xfe82, 0x00a3, 0x00a4, 0xfe84, UCS4ud, UCS4ud, 0xfe8e, 0xfe8f, 0xfe95, 0xfe99, 0x060c, 0xfe9d, 0xfea1, 0xfea5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xfed1, 0x061b, 0xfeb1, 0xfeb5, 0xfeb9, 0x061f, + 0x00a2, 0xfe80, 0xfe81, 0xfe83, 0xfe85, 0xfeca, 0xfe8b, 0xfe8d, 0xfe91, 0xfe93, 0xfe97, 0xfe9b, 0xfe9f, 0xfea3, 0xfea7, 0xfea9, + 0xfeab, 0xfead, 0xfeaf, 0xfeb3, 0xfeb7, 0xfebb, 0xfebf, 0xfec1, 0xfec5, 0xfecb, 0xfecf, 0x00a6, 0x00ac, 0x00f7, 0x00d7, 0xfec9, + 0x0640, 0xfed3, 0xfed7, 0xfedb, 0xfedf, 0xfee3, 0xfee7, 0xfeeb, 0xfeed, 0xfeef, 0xfef3, 0xfebd, 0xfecc, 0xfece, 0xfecd, 0xfee1, + 0xfe7d, 0x0651, 0xfee5, 0xfee9, 0xfeec, 0xfef0, 0xfef2, 0xfed0, 0xfed5, 0xfef5, 0xfef6, 0xfedd, 0xfed9, 0xfef1, 0x25a0, UCS4ud}; + +inline constexpr char32_t CharsetTableCP865[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00a4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP866[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040e, 0x045e, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x2116, 0x00a4, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP869[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x0386, UCS4ud, 0x00b7, 0x00ac, 0x00a6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038a, 0x03aa, 0x038c, UCS4ud, UCS4ud, 0x038e, 0x03ab, 0x00a9, 0x038f, 0x00b2, 0x00b3, 0x03ac, 0x00a3, 0x03ad, 0x03ae, 0x03af, + 0x03ca, 0x0390, 0x03cc, 0x03cd, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00bd, 0x0398, 0x0399, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039a, 0x039b, 0x039c, 0x039d, 0x2563, 0x2551, 0x2557, 0x255d, 0x039e, 0x039f, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x03a0, 0x03a1, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x03a3, + 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x2518, 0x250c, 0x2588, 0x2584, 0x03b4, 0x03b5, 0x2580, + 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x0384, + 0x00ad, 0x00b1, 0x03c5, 0x03c6, 0x03c7, 0x00a7, 0x03c8, 0x0385, 0x00b0, 0x00a8, 0x03c9, 0x03cb, 0x03b0, 0x03ce, 0x25a0, 0x00a0}; + +inline constexpr char32_t CharsetTableCP874[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x2026, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, + UCS4ud, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, UCS4ud, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, UCS4ud, UCS4ud, UCS4ud, UCS4ud, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, UCS4ud, UCS4ud, UCS4ud, UCS4ud}; + // inline constexpr char32_t CharsetTableAmiga[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, @@ -174,6 +457,25 @@ inline constexpr char32_t CharsetTableRISC_OS[256] = { 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff}; +// +inline constexpr char32_t CharsetTableAtariST[256] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x00DF, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x00E3, 0x00F5, 0x00D8, 0x00F8, 0x0153, 0x0152, 0x00C0, 0x00C3, 0x00D5, 0x00A8, 0x00B4, 0x2020, 0x00B6, 0x00A9, 0x00AE, 0x2122, + 0x0133, 0x0132, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DB, 0x05DC, 0x05DE, 0x05E0, + 0x05E1, 0x05E2, 0x05E4, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05DF, 0x05DA, 0x05DD, 0x05E3, 0x05E5, 0x00A7, 0x2227, 0x221E, + 0x03B1, 0x03B2, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x222E, 0x03C6, 0x2208, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x00B3, 0x00AF}; + template inline mpt::widestring decode_8bit(const Tsrcstring & str, const char32_t (&table)[256], mpt::widechar replacement = MPT_WIDECHAR('\uFFFD')) { mpt::widestring res; @@ -457,11 +759,11 @@ inline Tdststring encode_utf8(const mpt::widestring & str, typename Tdststring:: std::size_t charsleft = numchars; while (charsleft > 0) { if (charsleft == numchars) { - out.push_back(utf8[charsleft - 1] | (((1 << numchars) - 1) << (8 - numchars))); + out.push_back(static_cast(utf8[charsleft - 1] | (((1 << numchars) - 1) << (8 - numchars)))); } else { // cppcheck false-positive // cppcheck-suppress arrayIndexOutOfBounds - out.push_back(utf8[charsleft - 1] | 0x80); + out.push_back(static_cast(utf8[charsleft - 1] | 0x80u)); } charsleft--; } @@ -553,11 +855,53 @@ inline bool windows_has_encoding(common_encoding encoding) { case common_encoding::iso8859_15: result = has_codepage(28605); break; + case common_encoding::cp437: + result = has_codepage(437); + break; + case common_encoding::cp737: + result = has_codepage(737); + break; + case common_encoding::cp775: + result = has_codepage(775); + break; case common_encoding::cp850: result = has_codepage(850); break; - case common_encoding::cp437: - result = has_codepage(437); + case common_encoding::cp852: + result = has_codepage(852); + break; + case common_encoding::cp855: + result = has_codepage(855); + break; + case common_encoding::cp857: + result = has_codepage(857); + break; + case common_encoding::cp860: + result = has_codepage(860); + break; + case common_encoding::cp861: + result = has_codepage(861); + break; + case common_encoding::cp862: + result = has_codepage(862); + break; + case common_encoding::cp863: + result = has_codepage(863); + break; + case common_encoding::cp864: + result = has_codepage(864); + break; + case common_encoding::cp865: + result = has_codepage(865); + break; + case common_encoding::cp866: + result = has_codepage(866); + break; + case common_encoding::cp869: + result = has_codepage(869); + break; + case common_encoding::cp874: + result = has_codepage(874); break; case common_encoding::windows1252: result = has_codepage(1252); @@ -568,6 +912,9 @@ inline bool windows_has_encoding(common_encoding encoding) { case common_encoding::riscos: result = false; break; + case common_encoding::atarist: + result = false; + break; case common_encoding::iso8859_1_no_c1: result = false; break; @@ -622,11 +969,53 @@ inline UINT codepage_from_encoding(common_encoding encoding) { case common_encoding::iso8859_15: result = 28605; break; + case common_encoding::cp437: + result = 437; + break; + case common_encoding::cp737: + result = 737; + break; + case common_encoding::cp775: + result = 775; + break; case common_encoding::cp850: result = 850; break; - case common_encoding::cp437: - result = 437; + case common_encoding::cp852: + result = 852; + break; + case common_encoding::cp855: + result = 855; + break; + case common_encoding::cp857: + result = 857; + break; + case common_encoding::cp860: + result = 860; + break; + case common_encoding::cp861: + result = 861; + break; + case common_encoding::cp862: + result = 862; + break; + case common_encoding::cp863: + result = 863; + break; + case common_encoding::cp864: + result = 864; + break; + case common_encoding::cp865: + result = 865; + break; + case common_encoding::cp866: + result = 866; + break; + case common_encoding::cp869: + result = 869; + break; + case common_encoding::cp874: + result = 874; break; case common_encoding::windows1252: result = 1252; @@ -637,6 +1026,9 @@ inline UINT codepage_from_encoding(common_encoding encoding) { case common_encoding::riscos: throw std::domain_error("unsupported encoding"); break; + case common_encoding::atarist: + throw std::domain_error("unsupported encoding"); + break; case common_encoding::iso8859_1_no_c1: throw std::domain_error("unsupported encoding"); break; @@ -650,6 +1042,89 @@ inline UINT codepage_from_encoding(common_encoding encoding) { return result; } +inline std::optional optional_encoding_from_codepage(UINT codepage) { + std::optional result = std::nullopt; + switch (codepage) { + case CP_UTF8: + result = common_encoding::utf8; + break; + case 20127: + result = common_encoding::ascii; + break; + case 28591: + result = common_encoding::iso8859_1; + break; + case 28605: + result = common_encoding::iso8859_15; + break; + case 437: + result = common_encoding::cp437; + break; + case 737: + result = common_encoding::cp737; + break; + case 775: + result = common_encoding::cp775; + break; + case 850: + result = common_encoding::cp850; + break; + case 852: + result = common_encoding::cp852; + break; + case 855: + result = common_encoding::cp855; + break; + case 857: + result = common_encoding::cp857; + break; + case 860: + result = common_encoding::cp860; + break; + case 861: + result = common_encoding::cp861; + break; + case 862: + result = common_encoding::cp862; + break; + case 863: + result = common_encoding::cp863; + break; + case 864: + result = common_encoding::cp864; + break; + case 865: + result = common_encoding::cp865; + break; + case 866: + result = common_encoding::cp866; + break; + case 869: + result = common_encoding::cp869; + break; + case 874: + result = common_encoding::cp874; + break; + case 1252: + result = common_encoding::windows1252; + break; + default: + result = std::nullopt; + break; + } + return result; +} + +inline common_encoding encoding_from_codepage(UINT codepage) { + std::optional optional_result = optional_encoding_from_codepage(codepage); + if (!optional_result) { + throw std::domain_error("unsupported encoding"); + } + return *optional_result; +} + +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + template inline Tdststring encode_codepage(UINT codepage, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); @@ -676,6 +1151,8 @@ inline mpt::widestring decode_codepage(UINT codepage, const Tsrcstring & src) { return decoded_string; } +#endif // !MPT_COMPILER_QUIRK_NO_WCHAR + #endif // MPT_OS_WINDOWS @@ -700,12 +1177,68 @@ inline common_encoding djgpp_get_locale_encoding() { result = common_encoding::cp437; } else if (active_codepage == 437) { result = common_encoding::cp437; + } else if (active_codepage == 737) { + result = common_encoding::cp737; + } else if (active_codepage == 775) { + result = common_encoding::cp775; } else if (active_codepage == 850) { result = common_encoding::cp850; + } else if (active_codepage == 852) { + result = common_encoding::cp852; + } else if (active_codepage == 855) { + result = common_encoding::cp855; + } else if (active_codepage == 857) { + result = common_encoding::cp857; + } else if (active_codepage == 860) { + result = common_encoding::cp860; + } else if (active_codepage == 861) { + result = common_encoding::cp861; + } else if (active_codepage == 862) { + result = common_encoding::cp862; + } else if (active_codepage == 863) { + result = common_encoding::cp863; + } else if (active_codepage == 864) { + result = common_encoding::cp864; + } else if (active_codepage == 865) { + result = common_encoding::cp865; + } else if (active_codepage == 866) { + result = common_encoding::cp866; + } else if (active_codepage == 869) { + result = common_encoding::cp869; + } else if (active_codepage == 874) { + result = common_encoding::cp874; } else if (system_codepage == 437) { result = common_encoding::cp437; + } else if (system_codepage == 737) { + result = common_encoding::cp737; + } else if (system_codepage == 775) { + result = common_encoding::cp775; } else if (system_codepage == 850) { result = common_encoding::cp850; + } else if (system_codepage == 852) { + result = common_encoding::cp852; + } else if (system_codepage == 855) { + result = common_encoding::cp855; + } else if (system_codepage == 857) { + result = common_encoding::cp857; + } else if (system_codepage == 860) { + result = common_encoding::cp860; + } else if (system_codepage == 861) { + result = common_encoding::cp861; + } else if (system_codepage == 862) { + result = common_encoding::cp862; + } else if (system_codepage == 863) { + result = common_encoding::cp863; + } else if (system_codepage == 864) { + result = common_encoding::cp864; + } else if (system_codepage == 865) { + result = common_encoding::cp865; + } else if (system_codepage == 866) { + result = common_encoding::cp866; + } else if (system_codepage == 869) { + result = common_encoding::cp869; + } else if (system_codepage == 874) { + result = common_encoding::cp874; } else { result = common_encoding::cp437; } @@ -716,6 +1249,91 @@ inline common_encoding djgpp_get_locale_encoding() { +inline std::optional optional_encoding_from_codepage(uint16 codepage) { + std::optional result = std::nullopt; + switch (codepage) { + case 65001: + result = common_encoding::utf8; + break; + case 20127: + result = common_encoding::ascii; + break; + case 28591: + result = common_encoding::iso8859_1; + break; + case 28605: + result = common_encoding::iso8859_15; + break; + case 437: + result = common_encoding::cp437; + break; + case 737: + result = common_encoding::cp737; + break; + case 775: + result = common_encoding::cp775; + break; + case 850: + result = common_encoding::cp850; + break; + case 852: + result = common_encoding::cp852; + break; + case 855: + result = common_encoding::cp855; + break; + case 857: + result = common_encoding::cp857; + break; + case 860: + result = common_encoding::cp860; + break; + case 861: + result = common_encoding::cp861; + break; + case 862: + result = common_encoding::cp862; + break; + case 863: + result = common_encoding::cp863; + break; + case 864: + result = common_encoding::cp864; + break; + case 865: + result = common_encoding::cp865; + break; + case 866: + result = common_encoding::cp866; + break; + case 869: + result = common_encoding::cp869; + break; + case 874: + result = common_encoding::cp874; + break; + case 1252: + result = common_encoding::windows1252; + break; + default: + result = std::nullopt; + break; + } + return result; +} + +inline common_encoding encoding_from_codepage(uint16 codepage) { + std::optional optional_result = optional_encoding_from_codepage(codepage); + if (!optional_result) { + throw std::domain_error("unsupported encoding"); + } + return *optional_result; +} + + + + + #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // Note: @@ -893,14 +1511,14 @@ inline Tdststring encode_locale(const std::locale & locale, const mpt::widestrin -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template inline Tdststring encode(UINT codepage, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); return encode_codepage(codepage, src); } -#endif // MPT_OS_WINDOWS +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template @@ -922,11 +1540,11 @@ template inline Tdststring encode(common_encoding encoding, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return encode_codepage(codepage_from_encoding(encoding), src); } -#endif +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR switch (encoding) { case common_encoding::utf8: return encode_utf8(src); @@ -943,9 +1561,51 @@ inline Tdststring encode(common_encoding encoding, const mpt::widestring & src) case common_encoding::cp437: return encode_8bit(src, CharsetTableCP437); break; + case common_encoding::cp737: + return encode_8bit(src, CharsetTableCP737); + break; + case common_encoding::cp775: + return encode_8bit(src, CharsetTableCP775); + break; case common_encoding::cp850: return encode_8bit(src, CharsetTableCP850); break; + case common_encoding::cp852: + return encode_8bit(src, CharsetTableCP852); + break; + case common_encoding::cp855: + return encode_8bit(src, CharsetTableCP855); + break; + case common_encoding::cp857: + return encode_8bit(src, CharsetTableCP857); + break; + case common_encoding::cp860: + return encode_8bit(src, CharsetTableCP860); + break; + case common_encoding::cp861: + return encode_8bit(src, CharsetTableCP861); + break; + case common_encoding::cp862: + return encode_8bit(src, CharsetTableCP862); + break; + case common_encoding::cp863: + return encode_8bit(src, CharsetTableCP863); + break; + case common_encoding::cp864: + return encode_8bit(src, CharsetTableCP864); + break; + case common_encoding::cp865: + return encode_8bit(src, CharsetTableCP865); + break; + case common_encoding::cp866: + return encode_8bit(src, CharsetTableCP866); + break; + case common_encoding::cp869: + return encode_8bit(src, CharsetTableCP869); + break; + case common_encoding::cp874: + return encode_8bit(src, CharsetTableCP874); + break; case common_encoding::windows1252: return encode_8bit(src, CharsetTableWindows1252); break; @@ -955,6 +1615,9 @@ inline Tdststring encode(common_encoding encoding, const mpt::widestring & src) case common_encoding::riscos: return encode_8bit(src, CharsetTableRISC_OS); break; + case common_encoding::atarist: + return encode_8bit(src, CharsetTableAtariST); + break; case common_encoding::iso8859_1_no_c1: return encode_8bit_no_c1(src, CharsetTableISO8859_1); break; @@ -972,11 +1635,21 @@ template inline Tdststring encode(logical_encoding encoding, const mpt::widestring & src) { static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return encode_codepage(codepage_from_encoding(encoding), src); } -#endif +#elif MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_WCHAR) + switch (encoding) { + case logical_encoding::locale: + return encode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); + break; + case logical_encoding::active_locale: + return encode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); + break; + } + throw std::domain_error("unsupported encoding"); +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_OS_DJGPP switch (encoding) { case logical_encoding::locale: @@ -1002,6 +1675,13 @@ inline Tdststring encode(logical_encoding encoding, const mpt::widestring & src) #endif } +template +inline auto encode(Ttranscoder transcoder, const mpt::widestring & src) -> decltype(transcoder.template encode(src)) { + static_assert(sizeof(typename Tdststring::value_type) == sizeof(char)); + static_assert(mpt::is_character::value); + return transcoder.template encode(src); +} + #if MPT_OS_WINDOWS template inline mpt::widestring decode(UINT codepage, const Tsrcstring & src) { @@ -1031,11 +1711,11 @@ template inline mpt::widestring decode(common_encoding encoding, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return decode_codepage(codepage_from_encoding(encoding), src); } -#endif +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR switch (encoding) { case common_encoding::utf8: return decode_utf8(src); @@ -1052,9 +1732,51 @@ inline mpt::widestring decode(common_encoding encoding, const Tsrcstring & src) case common_encoding::cp437: return decode_8bit(src, CharsetTableCP437); break; + case common_encoding::cp737: + return decode_8bit(src, CharsetTableCP737); + break; + case common_encoding::cp775: + return decode_8bit(src, CharsetTableCP775); + break; case common_encoding::cp850: return decode_8bit(src, CharsetTableCP850); break; + case common_encoding::cp852: + return decode_8bit(src, CharsetTableCP852); + break; + case common_encoding::cp855: + return decode_8bit(src, CharsetTableCP855); + break; + case common_encoding::cp857: + return decode_8bit(src, CharsetTableCP857); + break; + case common_encoding::cp860: + return decode_8bit(src, CharsetTableCP860); + break; + case common_encoding::cp861: + return decode_8bit(src, CharsetTableCP861); + break; + case common_encoding::cp862: + return decode_8bit(src, CharsetTableCP862); + break; + case common_encoding::cp863: + return decode_8bit(src, CharsetTableCP863); + break; + case common_encoding::cp864: + return decode_8bit(src, CharsetTableCP864); + break; + case common_encoding::cp865: + return decode_8bit(src, CharsetTableCP865); + break; + case common_encoding::cp866: + return decode_8bit(src, CharsetTableCP866); + break; + case common_encoding::cp869: + return decode_8bit(src, CharsetTableCP869); + break; + case common_encoding::cp874: + return decode_8bit(src, CharsetTableCP874); + break; case common_encoding::windows1252: return decode_8bit(src, CharsetTableWindows1252); break; @@ -1064,6 +1786,9 @@ inline mpt::widestring decode(common_encoding encoding, const Tsrcstring & src) case common_encoding::riscos: return decode_8bit(src, CharsetTableRISC_OS); break; + case common_encoding::atarist: + return decode_8bit(src, CharsetTableAtariST); + break; case common_encoding::iso8859_1_no_c1: return decode_8bit_no_c1(src, CharsetTableISO8859_1); break; @@ -1081,11 +1806,21 @@ template inline mpt::widestring decode(logical_encoding encoding, const Tsrcstring & src) { static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); static_assert(mpt::is_character::value); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) if (windows_has_encoding(encoding)) { return decode_codepage(codepage_from_encoding(encoding), src); } -#endif +#elif MPT_OS_WINDOWS && defined(MPT_COMPILER_QUIRK_NO_WCHAR) + switch (encoding) { + case logical_encoding::locale: + return decode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); + break; + case logical_encoding::active_locale: + return decode(optional_encoding_from_codepage(GetACP()).value_or(common_encoding::windows1252), src); + break; + } + throw std::domain_error("unsupported encoding"); +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_OS_DJGPP switch (encoding) { case logical_encoding::locale: @@ -1111,6 +1846,13 @@ inline mpt::widestring decode(logical_encoding encoding, const Tsrcstring & src) #endif } +template +inline auto decode(Ttranscoder transcoder, const Tsrcstring & src) -> decltype(transcoder.template decode(src)) { + static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char)); + static_assert(mpt::is_character::value); + return transcoder.template decode(src); +} + inline bool is_utf8(const std::string & str) { @@ -1123,9 +1865,10 @@ template struct string_transcoder { }; -template -struct string_transcoder>> { - using string_type = std::basic_string>; +#if defined(MPT_COMPILER_QUIRK_NO_AUTO_TEMPLATE_ARGUMENT) +template +struct string_transcoder>> { + using string_type = std::basic_string>; static inline mpt::widestring decode(const string_type & src) { return mpt::decode(encoding, src); } @@ -1133,10 +1876,10 @@ struct string_transcoder(encoding, src); } }; - -template -struct string_transcoder>> { - using string_type = std::basic_string>; +#else +template +struct string_transcoder>> { + using string_type = std::basic_string>; static inline mpt::widestring decode(const string_type & src) { return mpt::decode(encoding, src); } @@ -1144,6 +1887,7 @@ struct string_transcoder(encoding, src); } }; +#endif #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> @@ -1248,28 +1992,61 @@ struct string_transcoder { #endif // MPT_DETECTED_MFC -template ::type>::value, bool> = true> -inline Tdststring transcode(const Tsrcstring & src) { - if constexpr (std::is_same::type>::value) { - return mpt::as_string(src); +template ::type>::type>::value, bool> = true> +inline Tdststring transcode(Tsrcstring && src) { + if constexpr (std::is_same::type>::type>::value) { + return mpt::as_string(std::forward(src)); } else { - return string_transcoder::encode(string_transcoder::decode(mpt::as_string(src))); + return string_transcoder::encode(string_transcoder(src)))>::decode(mpt::as_string(std::forward(src)))); } } -template ::value, bool> = true, std::enable_if_t::type>::value, bool> = true> -inline Tdststring transcode(Tencoding to, const Tsrcstring & src) { - return mpt::encode(to, string_transcoder::decode(mpt::as_string(src))); +template ::value, bool> = true, std::enable_if_t::type>::type>::value, bool> = true> +inline Tdststring transcode(Tencoding to, Tsrcstring && src) { + if constexpr (std::is_same::value) { + if constexpr (std::is_same(src))), mpt::u8string>::value) { + if (to == mpt::common_encoding::utf8) { + auto src_ = mpt::as_string(std::forward(src)); + Tdststring dst; + mpt::string_traits::reserve(dst, mpt::string_traits(src)))>::length(src_)); + for (std::size_t i = 0; i < mpt::saturate_cast(mpt::string_traits(src)))>::length(src_)); ++i) { + mpt::string_traits::append(dst, static_cast::unsigned_char_type>(static_cast(src)))>::unsigned_char_type>(src_[i]))); + } + return dst; + } + } + } + return mpt::encode(to, string_transcoder(src)))>::decode(mpt::as_string(std::forward(src)))); } -template ::type, std::string>::value, bool> = true, std::enable_if_t::type>::value, bool> = true> -inline Tdststring transcode(Tencoding from, const Tsrcstring & src) { - return string_transcoder::encode(mpt::decode(from, mpt::as_string(src))); +template ::type>::type, std::string>::value, bool> = true, std::enable_if_t::type>::type>::value, bool> = true> +inline Tdststring transcode(Tencoding from, Tsrcstring && src) { + if constexpr (std::is_same::value) { + if constexpr (std::is_same::value) { + if (from == mpt::common_encoding::utf8) { + auto src_ = mpt::as_string(std::forward(src)); + Tdststring dst; + mpt::string_traits::reserve(dst, mpt::string_traits(src)))>::length(src_)); + for (std::size_t i = 0; i < mpt::saturate_cast(mpt::string_traits(src)))>::length(src_)); ++i) { + mpt::string_traits::append(dst, static_cast::unsigned_char_type>(static_cast(src)))>::unsigned_char_type>(src_[i]))); + } + return dst; + } + } + } + return string_transcoder::encode(mpt::decode(src)))>(from, mpt::as_string(std::forward(src)))); } -template ::type>::value, bool> = true> -inline Tdststring transcode(Tto to, Tfrom from, const Tsrcstring & src) { - return mpt::encode(to, mpt::decode(from, mpt::as_string(src))); +template ::type>::type>::value, bool> = true> +inline Tdststring transcode(Tto to, Tfrom from, Tsrcstring && src) { + if constexpr (std::is_same::value) { + if constexpr (std::is_same(src))), Tdststring>::value) { + if (to == from) { + return mpt::as_string(std::forward(src)); + } + } + } + return mpt::encode(to, mpt::decode(src)))>(from, mpt::as_string(std::forward(src)))); } diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/test/test.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/test/test.hpp index babb52146..8ae0d9aec 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/test/test.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/test/test.hpp @@ -5,7 +5,6 @@ -#include "mpt/base/detect.hpp" #include "mpt/base/namespace.hpp" #include "mpt/base/source_location.hpp" @@ -43,7 +42,7 @@ template inline auto format(const T & x) -> typename std::enable_if::value, std::string>::type { std::ostringstream s; s << x; - return s.str(); + return std::move(s).str(); } template diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/guid.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/guid.hpp index b941b7536..b8a7b110c 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/guid.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/guid.hpp @@ -16,9 +16,9 @@ #include #if MPT_OS_WINDOWS -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #include -#endif // _WIN32_WINNT +#endif // MPT_WIN_VISTA #include #include #endif // MPT_OS_WINDOWS @@ -30,7 +30,7 @@ inline namespace MPT_INLINE_NS { -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) @@ -274,7 +274,7 @@ inline bool IsValid(::UUID uuid) { -#endif // MPT_OS_WINDOWS +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/tests/tests_uuid.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/tests/tests_uuid.hpp index 7d1f00077..ef96cb671 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/tests/tests_uuid.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/tests/tests_uuid.hpp @@ -40,7 +40,7 @@ MPT_TEST_GROUP_INLINE("mpt/uuid") using namespace mpt::uuid_literals; MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull).ToUString(), MPT_USTRING("2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32")); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) constexpr mpt::UUID uuid_tmp = "2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32"_uuid; MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), uuid_tmp); MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x2ed6593au, 0xdfe6, 0x4cf8, 0xb2e575ad7f600c32ull), mpt::UUID(mpt::StringToGUID(TEXT("{2ed6593a-dfe6-4cf8-b2e5-75ad7f600c32}")))); @@ -49,12 +49,12 @@ MPT_TEST_GROUP_INLINE("mpt/uuid") MPT_TEST_EXPECT_EQUAL(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0xC899AABBCCDDEEFFull), mpt::UUID(mpt::StringToGUID(TEXT("{00112233-4455-6677-C899-AABBCCDDEEFF}")))); MPT_TEST_EXPECT_EQUAL(mpt::GUIDToString(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0x8899AABBCCDDEEFFull)), TEXT("{00112233-4455-6677-8899-AABBCCDDEEFF}")); MPT_TEST_EXPECT_EQUAL(mpt::GUIDToString(mpt::UUID(0x00112233u, 0x4455, 0x6677, 0xC899AABBCCDDEEFFull)), TEXT("{00112233-4455-6677-C899-AABBCCDDEEFF}")); -#endif // MPT_OS_WINDOWS +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR mpt::sane_random_device rd; mpt::good_engine prng = mpt::make_prng(rd); -#if MPT_OS_WINDOWS +#if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_TEST_EXPECT_EQUAL(mpt::IsValid(mpt::CreateGUID()), true); { mpt::UUID uuid = mpt::UUID::Generate(prng); @@ -70,7 +70,7 @@ MPT_TEST_GROUP_INLINE("mpt/uuid") MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, mpt::StringToIID(mpt::IIDToString(guid))), TRUE); MPT_TEST_EXPECT_EQUAL(IsEqualGUID(guid, mpt::StringToCLSID(mpt::CLSIDToString(guid))), TRUE); } -#endif // MPT_OS_WINDOWS +#endif // MPT_OS_WINDOWS && !MPT_COMPILER_QUIRK_NO_WCHAR MPT_TEST_EXPECT_EQUAL(mpt::UUID::Generate(prng).IsValid(), true); MPT_TEST_EXPECT_EQUAL(mpt::UUID::GenerateLocalUseOnly(prng).IsValid(), true); MPT_TEST_EXPECT_EQUAL(mpt::UUID::Generate(prng) != mpt::UUID::Generate(prng), true); diff --git a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/uuid.hpp b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/uuid.hpp index 06f17a814..eb506f9e7 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/uuid.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/mpt/uuid/uuid.hpp @@ -19,9 +19,9 @@ #include "mpt/string/utility.hpp" #if MPT_OS_WINDOWS -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) +#if MPT_WINNT_AT_LEAST(MPT_WIN_VISTA) #include -#endif // _WIN32_WINNT +#endif // MPT_WIN_VISTA #include #include #endif // MPT_OS_WINDOWS @@ -113,6 +113,10 @@ private: MPT_CONSTEXPRINLINE uint8 Nn() const noexcept { return static_cast((Data4 >> 56) & 0xffu); } +#if MPT_COMPILER_GCC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif // MPT_COMPILER_GCC void MakeRFC4122(uint8 version) noexcept { // variant uint8 Nn = static_cast((Data4 >> 56) & 0xffu); @@ -128,6 +132,9 @@ private: Mm |= (version << 4u); Data3 |= static_cast(Mm) << 8; } +#if MPT_COMPILER_GCC +#pragma GCC diagnostic pop +#endif // MPT_COMPILER_GCC #if MPT_OS_WINDOWS private: static mpt::UUID UUIDFromWin32(::UUID uuid) { @@ -234,18 +241,16 @@ public: // Create a UUID template static UUID Generate(Trng & rng) { -#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT -#if (_WIN32_WINNT >= 0x0602) +#if MPT_WINRT_AT_LEAST(MPT_WIN_8) ::GUID guid = ::GUID(); HRESULT result = CoCreateGuid(&guid); if (result != S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(guid); -#else +#elif MPT_WINRT_BEFORE(MPT_WIN_8) return mpt::UUID::RFC4122Random(rng); -#endif -#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT +#elif MPT_OS_WINDOWS ::UUID uuid = ::UUID(); RPC_STATUS status = ::UuidCreate(&uuid); if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) { @@ -267,19 +272,16 @@ public: // Safe for local use. May be faster. template static UUID GenerateLocalUseOnly(Trng & rng) { -#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT -#if (_WIN32_WINNT >= 0x0602) +#if MPT_WINRT_AT_LEAST(MPT_WIN_8) ::GUID guid = ::GUID(); HRESULT result = CoCreateGuid(&guid); if (result != S_OK) { return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(guid); -#else +#elif MPT_WINRT_BEFORE(MPT_WIN_8) return mpt::UUID::RFC4122Random(rng); -#endif -#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT -#if _WIN32_WINNT >= 0x0501 +#elif MPT_WINNT_AT_LEAST(MPT_WIN_XP) // Available since Win2000, but we check for WinXP in order to not use this // function in Win32old builds. It is not available on some non-fully // patched Win98SE installs in the wild. @@ -296,11 +298,10 @@ public: return mpt::UUID::RFC4122Random(rng); } return mpt::UUID::UUIDFromWin32(uuid); -#else +#elif MPT_OS_WINDOWS // Fallback to ::UuidCreate is safe as ::UuidCreateSequential is only a // tiny performance optimization. return Generate(rng); -#endif #else return RFC4122Random(rng); #endif @@ -343,25 +344,12 @@ public: return UUID(); } UUID result; - result.Data1 = mpt::ConvertHexStringTo(segments[0]); - result.Data2 = mpt::ConvertHexStringTo(segments[1]); - result.Data3 = mpt::ConvertHexStringTo(segments[2]); - result.Data4 = mpt::ConvertHexStringTo(segments[3] + segments[4]); + result.Data1 = mpt::parse_hex(segments[0]); + result.Data2 = mpt::parse_hex(segments[1]); + result.Data3 = mpt::parse_hex(segments[2]); + result.Data4 = mpt::parse_hex(segments[3] + segments[4]); return result; } - std::string ToAString() const { - return std::string() - + mpt::format::hex0<8>(GetData1()) - + std::string("-") - + mpt::format::hex0<4>(GetData2()) - + std::string("-") - + mpt::format::hex0<4>(GetData3()) - + std::string("-") - + mpt::format::hex0<4>(static_cast(GetData4() >> 48)) - + std::string("-") - + mpt::format::hex0<4>(static_cast(GetData4() >> 32)) - + mpt::format::hex0<8>(static_cast(GetData4() >> 0)); - } mpt::ustring ToUString() const { return mpt::ustring() + mpt::format::hex0<8>(GetData1()) @@ -388,27 +376,13 @@ MPT_CONSTEXPRINLINE bool operator!=(const mpt::UUID & a, const mpt::UUID & b) no namespace uuid_literals { -MPT_CONSTEXPRINLINE mpt::UUID operator"" _uuid(const char * str, std::size_t len) { +MPT_CONSTEVAL mpt::UUID operator"" _uuid(const char * str, std::size_t len) { return mpt::UUID::ParseLiteral(str, len); } } // namespace uuid_literals -template -inline Tstring uuid_to_string(mpt::UUID uuid) { - return mpt::transcode(uuid.ToUString()); -} - -template <> -inline std::string uuid_to_string(mpt::UUID uuid) { - return uuid.ToAString(); -} - -template ::value, bool> = true> -inline Tstring format_value_default(const T & x) { - return mpt::transcode(mpt::uuid_to_string::type>(x)); -} } // namespace MPT_INLINE_NS diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Endian.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Endian.hpp index eb177e0a2..772ec021a 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Endian.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Endian.hpp @@ -10,6 +10,7 @@ #include "mpt/base/memory.hpp" #include "mpt/endian/floatingpoint.hpp" #include "mpt/endian/integer.hpp" +#include "mpt/endian/type_traits.hpp" #include "openmpt/base/Types.hpp" @@ -18,23 +19,23 @@ OPENMPT_NAMESPACE_BEGIN -using int64le = mpt::packed; -using int32le = mpt::packed; -using int16le = mpt::packed; -using int8le = mpt::packed; -using uint64le = mpt::packed; -using uint32le = mpt::packed; -using uint16le = mpt::packed; -using uint8le = mpt::packed; +using int64le = mpt::packed; +using int32le = mpt::packed; +using int16le = mpt::packed; +using int8le = mpt::packed; +using uint64le = mpt::packed; +using uint32le = mpt::packed; +using uint16le = mpt::packed; +using uint8le = mpt::packed; -using int64be = mpt::packed; -using int32be = mpt::packed; -using int16be = mpt::packed; -using int8be = mpt::packed; -using uint64be = mpt::packed; -using uint32be = mpt::packed; -using uint16be = mpt::packed; -using uint8be = mpt::packed; +using int64be = mpt::packed; +using int32be = mpt::packed; +using int16be = mpt::packed; +using int8be = mpt::packed; +using uint64be = mpt::packed; +using uint32be = mpt::packed; +using uint16be = mpt::packed; +using uint8be = mpt::packed; diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Int24.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Int24.hpp index 6fcbb707d..562298950 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Int24.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/base/Int24.hpp @@ -26,6 +26,11 @@ static_assert(sizeof(int24) == 3); inline constexpr int32 int24_min = std::numeric_limits::min(); inline constexpr int32 int24_max = std::numeric_limits::max(); +using int24le = mpt::packed; +using uint24le = mpt::packed; +using int24be = mpt::packed; +using uint24be = mpt::packed; + OPENMPT_NAMESPACE_END diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvert.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvert.hpp index d10e25b1f..8da1f1d25 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvert.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvert.hpp @@ -590,7 +590,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return (static_cast(val) - 0x80) * (1.0f / static_cast(static_cast(1) << 7)); + return static_cast(static_cast(val) - 0x80) * (1.0f / static_cast(static_cast(1) << 7)); } }; @@ -601,7 +601,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0f / static_cast(static_cast(1) << 7)); + return static_cast(val) * (1.0f / static_cast(static_cast(1) << 7)); } }; @@ -612,7 +612,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0f / static_cast(static_cast(1) << 15)); + return static_cast(val) * (1.0f / static_cast(static_cast(1) << 15)); } }; @@ -623,7 +623,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0f / static_cast(static_cast(1) << 23)); + return static_cast(val) * (1.0f / static_cast(static_cast(1) << 23)); } }; @@ -634,7 +634,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0f / static_cast(static_cast(1) << 31)); + return static_cast(val) * (1.0f / static_cast(static_cast(1) << 31)); } }; @@ -645,7 +645,7 @@ struct Convert using output_t = float32; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0f / static_cast(static_cast(1) << 63)); + return static_cast(val) * (1.0f / static_cast(static_cast(1) << 63)); } }; @@ -656,7 +656,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return (static_cast(val) - 0x80) * (1.0 / static_cast(static_cast(1) << 7)); + return static_cast(static_cast(val) - 0x80) * (1.0 / static_cast(static_cast(1) << 7)); } }; @@ -667,7 +667,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0 / static_cast(static_cast(1) << 7)); + return static_cast(val) * (1.0 / static_cast(static_cast(1) << 7)); } }; @@ -678,7 +678,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0 / static_cast(static_cast(1) << 15)); + return static_cast(val) * (1.0 / static_cast(static_cast(1) << 15)); } }; @@ -689,7 +689,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0 / static_cast(static_cast(1) << 23)); + return static_cast(val) * (1.0 / static_cast(static_cast(1) << 23)); } }; @@ -700,7 +700,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0 / static_cast(static_cast(1) << 31)); + return static_cast(val) * (1.0 / static_cast(static_cast(1) << 31)); } }; @@ -711,7 +711,7 @@ struct Convert using output_t = double; MPT_FORCEINLINE output_t operator()(input_t val) { - return val * (1.0 / static_cast(static_cast(1) << 63)); + return static_cast(val) * (1.0 / static_cast(static_cast(1) << 63)); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvertFixedPoint.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvertFixedPoint.hpp index 65b5d9122..e757f4d42 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvertFixedPoint.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleConvertFixedPoint.hpp @@ -123,7 +123,7 @@ struct ConvertFixedPoint MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); - return val * factor; + return static_cast(val) * factor; } }; @@ -141,7 +141,7 @@ struct ConvertFixedPoint MPT_FORCEINLINE output_t operator()(input_t val) { static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1); - return val * factor; + return static_cast(val) * factor; } }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleDecode.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleDecode.hpp index 164004b09..6ae306436 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleDecode.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleDecode.hpp @@ -187,7 +187,7 @@ struct DecodeInt16 static constexpr std::size_t input_inc = 2; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { - return (mpt::byte_cast(inBuf[loByteIndex]) | (mpt::byte_cast(inBuf[hiByteIndex]) << 8)) - offset; + return static_cast((mpt::byte_cast(inBuf[loByteIndex]) | (mpt::byte_cast(inBuf[hiByteIndex]) << 8)) - offset); } }; @@ -204,7 +204,7 @@ struct DecodeInt16Delta } MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { - delta += mpt::byte_cast(inBuf[loByteIndex]) | (mpt::byte_cast(inBuf[hiByteIndex]) << 8); + delta += static_cast(static_cast(mpt::byte_cast(inBuf[loByteIndex])) | static_cast(mpt::byte_cast(inBuf[hiByteIndex]) << 8)); return static_cast(delta); } }; @@ -224,7 +224,7 @@ struct DecodeInt16Delta8 delta += mpt::byte_cast(inBuf[0]); int16 result = delta & 0xFF; delta += mpt::byte_cast(inBuf[1]); - result |= (delta << 8); + result |= static_cast(delta << 8); return result; } }; @@ -237,7 +237,12 @@ struct DecodeInt24 static constexpr std::size_t input_inc = 3; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { - return ((mpt::byte_cast(inBuf[loByteIndex]) << 8) | (mpt::byte_cast(inBuf[midByteIndex]) << 16) | (mpt::byte_cast(inBuf[hiByteIndex]) << 24)) - offset; + const uint32 tmp = (uint32(0) + | (static_cast(mpt::byte_cast(inBuf[loByteIndex])) << 8) + | (static_cast(mpt::byte_cast(inBuf[midByteIndex])) << 16) + | (static_cast(mpt::byte_cast(inBuf[hiByteIndex])) << 24)) + - offset; + return static_cast(tmp); } }; @@ -249,7 +254,13 @@ struct DecodeInt32 static constexpr std::size_t input_inc = 4; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { - return (mpt::byte_cast(inBuf[loLoByteIndex]) | (mpt::byte_cast(inBuf[loHiByteIndex]) << 8) | (mpt::byte_cast(inBuf[hiLoByteIndex]) << 16) | (mpt::byte_cast(inBuf[hiHiByteIndex]) << 24)) - offset; + const uint32 tmp = (uint32(0) + | (static_cast(mpt::byte_cast(inBuf[loLoByteIndex])) << 0) + | (static_cast(mpt::byte_cast(inBuf[loHiByteIndex])) << 8) + | (static_cast(mpt::byte_cast(inBuf[hiLoByteIndex])) << 16) + | (static_cast(mpt::byte_cast(inBuf[hiHiByteIndex])) << 24)) + - offset; + return static_cast(tmp); } }; @@ -261,16 +272,17 @@ struct DecodeInt64 static constexpr std::size_t input_inc = 8; MPT_FORCEINLINE output_t operator()(const input_t *inBuf) { - return (uint64(0) - | (static_cast(mpt::byte_cast(inBuf[b0])) << 0) - | (static_cast(mpt::byte_cast(inBuf[b1])) << 8) - | (static_cast(mpt::byte_cast(inBuf[b2])) << 16) - | (static_cast(mpt::byte_cast(inBuf[b3])) << 24) - | (static_cast(mpt::byte_cast(inBuf[b4])) << 32) - | (static_cast(mpt::byte_cast(inBuf[b5])) << 40) - | (static_cast(mpt::byte_cast(inBuf[b6])) << 48) - | (static_cast(mpt::byte_cast(inBuf[b7])) << 56)) - - offset; + const uint64 tmp = (uint64(0) + | (static_cast(mpt::byte_cast(inBuf[b0])) << 0) + | (static_cast(mpt::byte_cast(inBuf[b1])) << 8) + | (static_cast(mpt::byte_cast(inBuf[b2])) << 16) + | (static_cast(mpt::byte_cast(inBuf[b3])) << 24) + | (static_cast(mpt::byte_cast(inBuf[b4])) << 32) + | (static_cast(mpt::byte_cast(inBuf[b5])) << 40) + | (static_cast(mpt::byte_cast(inBuf[b6])) << 48) + | (static_cast(mpt::byte_cast(inBuf[b7])) << 56)) + - offset; + return static_cast(tmp); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleEncode.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleEncode.hpp index 837924282..27656091f 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleEncode.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleEncode.hpp @@ -34,18 +34,18 @@ struct EncodeuLaw MPT_FORCEINLINE output_t operator()(input_t val) { uint16 x = static_cast(val); - uint8 out = (x >> 8) & 0x80; - uint32 abs = x & 0x7fff; - if(x & 0x8000) + uint8 out = static_cast((x >> 8) & 0x80u); + uint32 abs = x & 0x7fffu; + if(x & 0x8000u) { - abs ^= 0x7fff; - abs += 1; + abs ^= 0x7fffu; + abs += 1u; } x = static_cast(std::clamp(static_cast(abs + (33 << 2)), static_cast(0), static_cast(0x7fff))); int index = mpt::countl_zero(x); out |= exp_table[index]; - out |= (x >> mant_table[index]) & 0x0f; - out ^= 0xff; + out |= (x >> mant_table[index]) & 0x0fu; + out ^= 0xffu; return mpt::byte_cast(out); } }; @@ -61,12 +61,12 @@ struct EncodeALaw { int16 sx = std::clamp(val, static_cast(-32767), static_cast(32767)); uint16 x = static_cast(sx); - uint8 out = ((x & 0x8000) ^ 0x8000) >> 8; + uint8 out = static_cast(((x & 0x8000u) ^ 0x8000u) >> 8); x = static_cast(std::abs(sx)); int index = mpt::countl_zero(x); out |= exp_table[index]; - out |= (x >> mant_table[index]) & 0x0f; - out ^= 0x55; + out |= (x >> mant_table[index]) & 0x0fu; + out ^= 0x55u; return mpt::byte_cast(out); } }; diff --git a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleFormat.hpp b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleFormat.hpp index 2ba2b18ba..403226a59 100644 --- a/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleFormat.hpp +++ b/Frameworks/OpenMPT/OpenMPT/src/openmpt/soundbase/SampleFormat.hpp @@ -29,7 +29,7 @@ public: Int32 = 32, // do not change value (for compatibility with old configuration settings) Float32 = 32 + 128, // do not change value (for compatibility with old configuration settings) Float64 = 64 + 128, // do not change value (for compatibility with old configuration settings) - Invalid = 0 + Default = Float32 }; static constexpr SampleFormat::Enum Unsigned8 = SampleFormat::Enum::Unsigned8; static constexpr SampleFormat::Enum Int8 = SampleFormat::Enum::Int8; @@ -38,7 +38,7 @@ public: static constexpr SampleFormat::Enum Int32 = SampleFormat::Enum::Int32; static constexpr SampleFormat::Enum Float32 = SampleFormat::Enum::Float32; static constexpr SampleFormat::Enum Float64 = SampleFormat::Enum::Float64; - static constexpr SampleFormat::Enum Invalid = SampleFormat::Enum::Invalid; + static constexpr SampleFormat::Enum Default = SampleFormat::Enum::Default; private: SampleFormat::Enum value; @@ -50,7 +50,7 @@ private: uT val = static_cast(x); if(!val) { - return SampleFormat::Enum::Invalid; + return SampleFormat::Enum::Default; } if(val == static_cast(-8)) { @@ -120,7 +120,7 @@ private: { if(is_unsigned(val) && is_float(val)) { - val = mpt::to_underlying(Enum::Invalid); + val = mpt::to_underlying(Enum::Default); } else if(is_unsigned(val)) { val = mpt::to_underlying(Enum::Unsigned8); @@ -129,7 +129,7 @@ private: val = mpt::to_underlying(Enum::Float32); } else { - val = mpt::to_underlying(Enum::Invalid); + val = mpt::to_underlying(Enum::Default); } } else if(!unique_size(val)) { @@ -182,7 +182,7 @@ private: public: MPT_CONSTEXPRINLINE SampleFormat() noexcept - : value(SampleFormat::Invalid) + : value(SampleFormat::Default) { } @@ -216,18 +216,6 @@ public: return a.value != b; } - MPT_CONSTEXPRINLINE bool IsValid() const noexcept - { - return false - || (value == SampleFormat::Unsigned8) - || (value == SampleFormat::Int8) - || (value == SampleFormat::Int16) - || (value == SampleFormat::Int24) - || (value == SampleFormat::Int32) - || (value == SampleFormat::Float32) - || (value == SampleFormat::Float64); - } - MPT_CONSTEXPRINLINE bool IsUnsigned() const noexcept { return false @@ -250,7 +238,7 @@ public: } MPT_CONSTEXPRINLINE uint8 GetSampleSize() const noexcept { - return !IsValid() ? 0 + return false ? 0 : (value == SampleFormat::Unsigned8) ? 1 : (value == SampleFormat::Int8) ? 1 : (value == SampleFormat::Int16) ? 2 @@ -262,7 +250,7 @@ public: } MPT_CONSTEXPRINLINE uint8 GetBitsPerSample() const noexcept { - return !IsValid() ? 0 + return false ? 0 : (value == SampleFormat::Unsigned8) ? 8 : (value == SampleFormat::Int8) ? 8 : (value == SampleFormat::Int16) ? 16 @@ -277,10 +265,6 @@ public: { return value; } - explicit MPT_CONSTEXPRINLINE operator std::underlying_type::type() const noexcept - { - return mpt::to_underlying(value); - } // backward compatibility, conversion to/from integers static MPT_CONSTEXPRINLINE SampleFormat FromInt(int x) noexcept @@ -291,10 +275,6 @@ public: { return mpt::to_underlying(x.value); } - MPT_CONSTEXPRINLINE int AsInt() const noexcept - { - return mpt::to_underlying(value); - } }; diff --git a/Frameworks/OpenMPT/OpenMPT/test/TestToolsLib.cpp b/Frameworks/OpenMPT/OpenMPT/test/TestToolsLib.cpp index b60ad6c11..fe58f8654 100644 --- a/Frameworks/OpenMPT/OpenMPT/test/TestToolsLib.cpp +++ b/Frameworks/OpenMPT/OpenMPT/test/TestToolsLib.cpp @@ -16,6 +16,8 @@ #ifndef MODPLUG_TRACKER +#include "mpt/string/utility.hpp" + #include #include @@ -31,56 +33,28 @@ namespace Test { void mpt_test_reporter::case_run(const mpt::source_location& loc) { - #if !MPT_OS_DJGPP - std::cout << "TEST..: " << MPT_AFORMAT("{}({}):")(loc.file_name() ? loc.file_name() : "", loc.line()) << ": " << std::endl; - #else - MPT_UNUSED(loc); - #endif + std::cout << "TEST..: " << MPT_AFORMAT("{}({}):")(loc.file_name() ? loc.file_name() : "", loc.line()) << ": " << std::endl; } void mpt_test_reporter::case_run(const mpt::source_location& loc, const char* text_e) { - #if !MPT_OS_DJGPP - std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e) << ": " << std::endl; - #else - MPT_UNUSED(loc); - MPT_UNUSED(text_e); - #endif + std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e) << ": " << std::endl; } void mpt_test_reporter::case_run(const mpt::source_location& loc, const char* text_ex, const char* text_e) { if(text_ex) { - #if !MPT_OS_DJGPP - std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} throws {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e, text_ex) << ": " << std::endl; - #else - MPT_UNUSED(loc); - MPT_UNUSED(text_ex); - MPT_UNUSED(text_e); - #endif + std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} throws {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e, text_ex) << ": " << std::endl; } else { - #if !MPT_OS_DJGPP - std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} throws")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e) << ": " << std::endl; - #else - MPT_UNUSED(loc); - MPT_UNUSED(text_ex); - MPT_UNUSED(text_e); - #endif + std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} throws")(loc.file_name() ? loc.file_name() : "", loc.line(), text_e) << ": " << std::endl; } } void mpt_test_reporter::case_run(const mpt::source_location& loc, const char* text_a, const char* text_cmp, const char* text_b) { - #if !MPT_OS_DJGPP - std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} {} {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_a, text_cmp, text_b) << ": " << std::endl; - #else - MPT_UNUSED(loc); - MPT_UNUSED(text_a); - MPT_UNUSED(text_cmp); - MPT_UNUSED(text_b); - #endif + std::cout << "TEST..: " << MPT_AFORMAT("{}({}): {} {} {}")(loc.file_name() ? loc.file_name() : "", loc.line(), text_a, text_cmp, text_b) << ": " << std::endl; } void mpt_test_reporter::case_result(const mpt::source_location& loc, const mpt::test::result& result) @@ -88,9 +62,7 @@ void mpt_test_reporter::case_result(const mpt::source_location& loc, const mpt:: MPT_UNUSED(loc); if(std::holds_alternative(result.info)) { - #if !MPT_OS_DJGPP - std::cout << "RESULT: PASS" << std::endl; - #endif + std::cout << "RESULT: PASS" << std::endl; } else if(std::holds_alternative(result.info)) { fail_count++; @@ -149,14 +121,10 @@ void Testcase::ShowStart() const case VerbosityQuiet: break; case VerbosityNormal: -#if !MPT_OS_DJGPP std::cout << "TEST..: " << AsString() << ": " << std::endl; -#endif break; case VerbosityVerbose: -#if !MPT_OS_DJGPP std::cout << "TEST..: " << AsString() << ": " << std::endl; -#endif break; } } @@ -171,11 +139,7 @@ void Testcase::ShowProgress(const char * text) const case VerbosityNormal: break; case VerbosityVerbose: -#if !MPT_OS_DJGPP std::cout << "TEST..: " << AsString() << ": " << text << std::endl; -#else - MPT_UNUSED_VARIABLE(text); -#endif break; } } @@ -188,14 +152,10 @@ void Testcase::ShowPass() const case VerbosityQuiet: break; case VerbosityNormal: -#if !MPT_OS_DJGPP std::cout << "RESULT: PASS" << std::endl; -#endif break; case VerbosityVerbose: -#if !MPT_OS_DJGPP std::cout << "PASS..: " << AsString() << std::endl; -#endif break; } } diff --git a/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.cpp b/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.cpp new file mode 100644 index 000000000..e4200ed4a --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.cpp @@ -0,0 +1,99 @@ +/* + * libopenmpt_test.cpp + * ------------------- + * Purpose: libopenmpt test suite driver + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "openmpt/all/BuildSettings.hpp" + +#include "mpt/base/macros.hpp" + +#if defined( LIBOPENMPT_BUILD_TEST ) + +#if defined(__MINGW32__) && !defined(__MINGW64__) +#include +#endif + +#include "../libopenmpt/libopenmpt_internal.h" + +#include "test.h" + +#include +#include + +#include +#include + +#if defined( __DJGPP__ ) +#include +#endif /* __DJGPP__ */ + +using namespace OpenMPT; + +#if defined( __DJGPP__ ) +/* Work-around */ +/* clang-format off */ +extern "C" { + int _crt0_startup_flags = 0 + | _CRT0_FLAG_NONMOVE_SBRK /* force interrupt compatible allocation */ + | _CRT0_DISABLE_SBRK_ADDRESS_WRAP /* force NT compatible allocation */ + | _CRT0_FLAG_LOCK_MEMORY /* lock all code and data at program startup */ + | 0; +} +/* clang-format on */ +#endif /* __DJGPP__ */ +#if (defined(_WIN32) || defined(WIN32)) && (defined(_UNICODE) || defined(UNICODE)) +#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) +// mingw-w64 g++ does only default to special C linkage for "main", but not for "wmain" (see ). +extern "C" int wmain( int /*argc*/ , wchar_t * /*argv*/ [] ); +extern "C" +#endif +int wmain( int /*argc*/ , wchar_t * /*argv*/ [] ) { +#else +int main( int /*argc*/ , char * /*argv*/ [] ) { +#endif +#if defined( __DJGPP__ ) + _crt0_startup_flags &= ~_CRT0_FLAG_LOCK_MEMORY; /* disable automatic locking for all further memory allocations */ +#endif /* __DJGPP__ */ + + try { + + // run test with "C" / classic() locale + Test::DoTests(); + + // try setting the C locale to the user locale + setlocale( LC_ALL, "" ); + + // run all tests again with a set C locale + Test::DoTests(); + + // try to set the C and C++ locales to the user locale + try { + std::locale old = std::locale::global( std::locale( "" ) ); + (void)old; + } catch ( ... ) { + // Setting c++ global locale does not work. + // This is no problem for libopenmpt, just continue. + } + + // and now, run all tests once again + Test::DoTests(); + + } catch ( const std::exception & e ) { + std::cerr << "TEST ERROR: exception: " << ( e.what() ? e.what() : "" ) << std::endl; + return -1; + } catch ( ... ) { + std::cerr << "TEST ERROR: unknown exception" << std::endl; + return -1; + } + return 0; +} + +#else // !LIBOPENMPT_BUILD_TEST + +unsigned char libopenmpt_test_dummy = 0; + +#endif // LIBOPENMPT_BUILD_TEST diff --git a/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.manifest b/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.manifest new file mode 100644 index 000000000..53bd216f7 --- /dev/null +++ b/Frameworks/OpenMPT/OpenMPT/test/libopenmpt_test.manifest @@ -0,0 +1,8 @@ + + + + diff --git a/Frameworks/OpenMPT/OpenMPT/test/mpt_tests_endian.cpp b/Frameworks/OpenMPT/OpenMPT/test/mpt_tests_endian.cpp index 409329aba..04c9ccdc7 100644 --- a/Frameworks/OpenMPT/OpenMPT/test/mpt_tests_endian.cpp +++ b/Frameworks/OpenMPT/OpenMPT/test/mpt_tests_endian.cpp @@ -4,6 +4,7 @@ #ifdef ENABLE_TESTS #include "mpt/endian/tests/tests_endian_floatingpoint.hpp" +#include "mpt/endian/tests/tests_endian_int24.hpp" #include "mpt/endian/tests/tests_endian_integer.hpp" #endif diff --git a/Frameworks/OpenMPT/OpenMPT/test/test.cpp b/Frameworks/OpenMPT/OpenMPT/test/test.cpp index 37b8d5286..2a80a3bb5 100644 --- a/Frameworks/OpenMPT/OpenMPT/test/test.cpp +++ b/Frameworks/OpenMPT/OpenMPT/test/test.cpp @@ -14,13 +14,27 @@ #ifdef ENABLE_TESTS +#ifdef LIBOPENMPT_BUILD +#include "mpt/arch/x86_amd64.hpp" +#endif +#include "mpt/base/check_platform.hpp" +#include "mpt/base/detect.hpp" #include "mpt/base/numbers.hpp" #include "mpt/crc/crc.hpp" #include "mpt/environment/environment.hpp" +#ifdef MODPLUG_TRACKER +#include "mpt/fs/common_directories.hpp" +#include "mpt/fs/fs.hpp" +#endif // MODPLUG_TRACKER #include "mpt/io/base.hpp" #include "mpt/io/io.hpp" #include "mpt/io/io_stdstream.hpp" #include "mpt/io_read/filecursor_stdstream.hpp" +#include "mpt/osinfo/class.hpp" +#include "mpt/osinfo/dos_version.hpp" +#include "mpt/osinfo/dos_memory.hpp" +#include "mpt/parse/parse.hpp" +#include "mpt/parse/split.hpp" #include "mpt/test/test.hpp" #include "mpt/test/test_macros.hpp" #include "mpt/uuid/uuid.hpp" @@ -55,6 +69,10 @@ #include "../mptrack/Settings.h" #include "../mptrack/HTTP.h" #endif // MODPLUG_TRACKER +#include "mpt/io_file/fileref.hpp" +#include "mpt/io_file/inputfile.hpp" +#include "mpt/io_file/outputfile.hpp" +#include "mpt/io_file_read/inputfile_filecursor.hpp" #include "../common/mptFileIO.h" #ifdef MODPLUG_TRACKER #include "mpt/crypto/hash.hpp" @@ -70,11 +88,15 @@ #include #include #ifdef LIBOPENMPT_BUILD +#include #include #endif // LIBOPENMPT_BUILD #include #include #include +#ifdef LIBOPENMPT_BUILD +#include +#endif // LIBOPENMPT_BUILD #if MPT_COMPILER_MSVC #include #endif @@ -89,10 +111,6 @@ #endif #define MPT_TEST_HAS_FILESYSTEM 1 -#if MPT_OS_DJGPP -#undef MPT_TEST_HAS_FILESYSTEM -#define MPT_TEST_HAS_FILESYSTEM 0 -#endif #include "TestTools.h" @@ -116,6 +134,8 @@ static MPT_NOINLINE void TestMisc1(); static MPT_NOINLINE void TestMisc2(); static MPT_NOINLINE void TestRandom(); static MPT_NOINLINE void TestCharsets(); +static MPT_NOINLINE void TestPathNative(); +static MPT_NOINLINE void TestPathForeign(); static MPT_NOINLINE void TestStringFormatting(); static MPT_NOINLINE void TestSettings(); static MPT_NOINLINE void TestStringIO(); @@ -154,14 +174,177 @@ void DoTests() std::cout << "libopenmpt test suite" << std::endl; - std::cout << "Version.: " << mpt::ToCharset(mpt::Charset::ASCII, Build::GetVersionString(Build::StringVersion | Build::StringRevision | Build::StringSourceInfo | Build::StringBuildFlags | Build::StringBuildFeatures)) << std::endl; + std::cout << "Version: " << mpt::ToCharset(mpt::Charset::ASCII, Build::GetVersionString(Build::StringVersion | Build::StringRevision | Build::StringSourceInfo | Build::StringBuildFlags | Build::StringBuildFeatures)) << std::endl; std::cout << "Compiler: " << mpt::ToCharset(mpt::Charset::ASCII, Build::GetBuildCompilerString()) << std::endl; + std::cout << "OS: " << mpt::osinfo::get_class_name(mpt::osinfo::get_class()) << " (" << mpt::osinfo::get_sysname() << ")" << std::endl; + #ifndef MPT_LIBC_QUIRK_NO_FENV + { + auto format_rounding = [](int rounding_mode) { + std::string result; + switch(rounding_mode) + { + case FE_DOWNWARD: + result = "FE_DOWNWARD"; + break; + case FE_TONEAREST: + result = "FE_TONEAREST"; + break; + case FE_TOWARDZERO: + result = "FE_TOWARDZERO"; + break; + case FE_UPWARD: + result = "FE_UPWARD"; + break; + default: + result = "UNKNOWN: " + mpt::afmt::hex(rounding_mode); + break; + } + return result; + }; + std::cout << "Rounding mode: " << format_rounding(std::fegetround()); + } + #endif // !MPT_LIBC_QUIRK_NO_FENV + #if MPT_ARCH_X86 || MPT_ARCH_AMD64 + { + const mpt::arch::x86::floating_point::control_state fpstate = mpt::arch::x86::floating_point::get_state(); + if(fpstate.x87_level) + { + auto format_rounding = [](uint16 fcw) { + std::string result; + switch((fcw & mpt::arch::x86::floating_point::FCW_RC) >> mpt::countr_zero(mpt::arch::x86::floating_point::FCW_RC)) + { + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::nearest): + result = "ROUND_NEAREST"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::down): + result = "ROUND_DOWN"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::up): + result = "ROUND_UP"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::zero): + result = "ROUND_ZERO"; + break; + } + return result; + }; + auto format_precision = [](uint16 fcw) { + std::string result; + switch((fcw & mpt::arch::x86::floating_point::FCW_PC) >> mpt::countr_zero(mpt::arch::x86::floating_point::FCW_PC)) + { + case mpt::to_underlying(mpt::arch::x86::floating_point::precision::single24): + result = "PRECISION_SINGLE"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::precision::double53): + result = "PRECISION_DOUBLE"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::precision::extended64): + result = "PRECISION_EXTENDED"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::precision::reserved): + result = "PRECISION_UNDEFINED"; + break; + } + return result; + }; + std::cout << "FCW: " << std::hex << std::setfill('0') << std::setw(4) << fpstate.x87fcw << std::endl; + std::cout << " " << format_rounding(fpstate.x87fcw); + std::cout << " " << format_precision(fpstate.x87fcw); + if (fpstate.x87_level <= 2) { + std::cout << " " << (fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_X) ? std::string("INFINITY-AFFINE") : std::string("INFINITY-PROJECTIVE"); + } + std::cout << std::endl; + } + if(fpstate.mxcsr_mask) + { + auto format_rounding = [](uint32 csr) { + std::string result; + switch((csr & mpt::arch::x86::floating_point::MXCSR_RC) >> mpt::countr_zero(mpt::arch::x86::floating_point::MXCSR_RC)) + { + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::nearest): + result = "ROUND_NEAREST"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::down): + result = "ROUND_DOWN"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::up): + result = "ROUND_UP"; + break; + case mpt::to_underlying(mpt::arch::x86::floating_point::rounding::zero): + result = "ROUND_ZERO"; + break; + } + return result; + }; + std::cout << "MXCSR (mask): " << std::hex << std::setfill('0') << std::setw(8) << fpstate.mxcsr << " (" << std::hex << std::setfill('0') << std::setw(8) << fpstate.mxcsr_mask << ")" << std::endl; + std::cout << " " << format_rounding(fpstate.mxcsr); + if(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_FTZ) + { + std::cout << " " << "FTZ"; + } + if(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_DAZ) + { + std::cout << " " << "DAZ"; + } + std::cout << std::endl; + } + if(fpstate.x87_level || fpstate.mxcsr_mask) + { + std::cout << "FP Exceptions: "; + if(fpstate.x87_level) + { + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_IM)) std::cout << " x87/#I"; + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_DM)) std::cout << " x87/#D"; + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_ZM)) std::cout << " x87/#Z"; + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_OM)) std::cout << " x87/#O"; + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_UM)) std::cout << " x87/#U"; + if(!(fpstate.x87fcw & mpt::arch::x86::floating_point::FCW_PM)) std::cout << " x87/#P"; + } + if(fpstate.mxcsr_mask) + { + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_IM)) std::cout << " sse/#I"; + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_DM)) std::cout << " sse/#D"; + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_ZM)) std::cout << " sse/#Z"; + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_OM)) std::cout << " sse/#O"; + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_UM)) std::cout << " sse/#U"; + if(!(fpstate.mxcsr & fpstate.mxcsr_mask & mpt::arch::x86::floating_point::MXCSR_PM)) std::cout << " sse/#P"; + } + std::cout << std::endl; + } + } + #endif // MPT_ARCH_X86 || MPT_ARCH_AMD64 + #if MPT_OS_DJGPP + mpt::osinfo::dos::Version ver = mpt::osinfo::dos::Version::Current(); + std::cout << "DOS: " << ver.GetOEM() << " " << static_cast(ver.GetSystemEmulated().Major) << "." << static_cast(ver.GetSystemEmulated().Minor) << " (true " << static_cast(ver.GetSystem().Major) << "." << static_cast(ver.GetSystem().Minor) << ")" << std::endl; + std::cout << "DPMI: " << static_cast(ver.GetDPMI().Major) << "." << static_cast(ver.GetDPMI().Minor) << std::endl; + std::cout << "DPMI Host: " << ver.GetDPMIVendor() << " " << static_cast(ver.GetDPMIHost().Major) << "." << static_cast(ver.GetDPMIHost().Minor) << std::endl; + std::cout << "Host OS: " << ver.GetHostName() << " " << ver.GetHostVersion() << "." << ver.GetHostRevision() << "." << ver.GetHostPatch() << " (" << "multitasking=" << static_cast(ver.IsHostMultitasking()) << ", " << "fixedtimer=" << static_cast(ver.HasHostFixedTimer()) << ")" << std::endl; + std::cout << "BIOS Date: " << ver.GetBIOSDate() << std::endl; + const mpt::osinfo::dos::memory_info mem = mpt::osinfo::dos::get_memory_info(); + auto print_mem = [](std::optional value) -> std::string { + if (!value) { + return "???"; + } + if (value >= (10ull * 1024 * 1024 * 1024)) { + return MPT_AFORMAT("{}{}")(*value / 1024 / 1024 / 1024, "GiB"); + } else if (value >= (10 * 1024 * 1024)) { + return MPT_AFORMAT("{}{}")(*value / 1024 / 1024, "MiB"); + } else if (value >= (10 * 1024)) { + return MPT_AFORMAT("{}{}")(*value / 1024, "kiB"); + } else { + return MPT_AFORMAT("{}{}")(*value, "B"); + } + }; + std::cout << "Memory (virtual): " << print_mem(mem.get_virtual_used()) << " used / " << print_mem(mem.get_virtual_total()) << " total (" << print_mem(mem.get_virtual_free()) << " free, " << print_mem(mem.get_virtual_external_fragmentation()) << " fragmented)" << std::endl; + std::cout << "RAM: " << print_mem(mem.get_physical_used()) << " used / " << print_mem(mem.get_physical_total()) << " total (" << print_mem(mem.get_physical_free()) << " free, " << print_mem(mem.get_physical_used_locked()) << " locked)" << std::endl; + std::cout << "Swap: " << print_mem(mem.get_swap_total()) << " total" << std::endl; + #endif // MPT_OS_DJGPP std::cout << std::flush; - + #endif - #if MPT_OS_WINDOWS + #if MPT_OS_WINDOWS && !defined(MPT_COMPILER_QUIRK_NO_WCHAR) // prefix for test suite std::wstring pathprefix = std::wstring(); @@ -186,6 +369,31 @@ void DoTests() PathPrefix = new mpt::PathString(mpt::PathString::FromWide(pathprefix)); + #elif MPT_OS_WINDOWS + + // prefix for test suite + std::string pathprefix = std::string(); + + bool libopenmpt = false; + #ifdef LIBOPENMPT_BUILD + libopenmpt = true; + #endif + +#if !MPT_OS_WINDOWS_WINRT + // set path prefix for test files (if provided) + std::vector buf(GetEnvironmentVariable("srcdir", NULL, 0) + 1); + if(GetEnvironmentVariable("srcdir", buf.data(), static_cast(buf.size())) > 0) + { + pathprefix = buf.data(); + } else +#endif + if(libopenmpt && IsDebuggerPresent()) + { + pathprefix = "../../"; + } + + PathPrefix = new mpt::PathString(mpt::PathString::FromLocale(pathprefix)); + #else // prefix for test suite @@ -201,6 +409,13 @@ void DoTests() #endif + #if MPT_OS_DJGPP + void (*TestLIBC)(void) = []() { + VERIFY_EQUAL(mpt::platform::libc().is_ok(), true); + }; + DO_TEST(TestLIBC); + #endif + void (*do_mpt_test)(void) = []() { mpt_test_reporter reporter{}; mpt::test::run_all(reporter); @@ -216,6 +431,8 @@ void DoTests() DO_TEST(TestMisc2); DO_TEST(TestRandom); DO_TEST(TestCharsets); + DO_TEST(TestPathNative); + DO_TEST(TestPathForeign); DO_TEST(TestStringFormatting); DO_TEST(TestSettings); DO_TEST(TestStringIO); @@ -384,7 +601,7 @@ static MPT_NOINLINE void TestVersion() { continue; } - std::vector line_fields = mpt::String::Split(line, std::string("=")); + std::vector line_fields = mpt::split(line, std::string("=")); VERIFY_EQUAL_NONCONT(line_fields.size(), 2u); line_fields[0] = mpt::trim(line_fields[0]); line_fields[1] = mpt::trim(line_fields[1]); @@ -485,12 +702,12 @@ static std::string StringFormat(std::string format, T x) #endif template -static void TestFloatFormat(Tfloat x, std::string format, mpt::FormatFlags f, std::size_t width = 0, int precision = -1) +static void TestFloatFormat(Tfloat x, std::string format, mpt::format_simple_flags f, std::size_t width = 0, int precision = -1) { #ifdef MODPLUG_TRACKER std::string str_sprintf = StringFormat(format, x); #endif - std::string str_iostreams = mpt::afmt::fmt(x, mpt::FormatSpec().SetFlags(f).SetWidth(width).SetPrecision(precision)); + std::string str_iostreams = mpt::afmt::fmt(x, mpt::format_simple_spec().SetFlags(f).SetWidth(width).SetPrecision(precision)); #ifdef MODPLUG_TRACKER //MPT_LOG_GLOBAL(LogDebug, "test", mpt::ToUnicode(mpt::Charset::ASCII, str_sprintf)); #endif @@ -569,7 +786,7 @@ static MPT_NOINLINE void TestStringFormatting() VERIFY_EQUAL(mpt::ufmt::HEX0<9>(0xa2345678), U_("0A2345678")); VERIFY_EQUAL(mpt::ufmt::HEX0<10>(0xa2345678), U_("00A2345678")); -#if MPT_WSTRING_FORMAT +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) VERIFY_EQUAL(mpt::wfmt::hex(0x123e), L"123e"); VERIFY_EQUAL(mpt::wfmt::hex0<6>(0x123e), L"00123e"); VERIFY_EQUAL(mpt::wfmt::hex0<2>(0x123e), L"123e"); @@ -614,32 +831,32 @@ static MPT_NOINLINE void TestStringFormatting() VERIFY_EQUAL(mpt::afmt::fix(234.2, 1), "234.2"); VERIFY_EQUAL(mpt::afmt::fix(2342.0, 1), "2342.0"); - VERIFY_EQUAL(mpt::afmt::dec(2, ';', 2345678), std::string("2;34;56;78")); - VERIFY_EQUAL(mpt::afmt::dec(2, ';', 12345678), std::string("12;34;56;78")); - VERIFY_EQUAL(mpt::afmt::hex(3, ':', 0xa2345678), std::string("a2:345:678")); + VERIFY_EQUAL(mpt::afmt::dec(2, ";", 2345678), std::string("2;34;56;78")); + VERIFY_EQUAL(mpt::afmt::dec(2, ";", 12345678), std::string("12;34;56;78")); + VERIFY_EQUAL(mpt::afmt::hex(3, ":", 0xa2345678), std::string("a2:345:678")); - VERIFY_EQUAL(mpt::ufmt::dec(2, ';', 12345678), U_("12;34;56;78")); - VERIFY_EQUAL(mpt::ufmt::hex(3, ':', 0xa2345678), U_("a2:345:678")); + VERIFY_EQUAL(mpt::ufmt::dec(2, U_(";"), 12345678), U_("12;34;56;78")); + VERIFY_EQUAL(mpt::ufmt::hex(3, U_(":"), 0xa2345678), U_("a2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', 0xa2345678), U_("A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, ':', 0xa2345678), U_("A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, ':', 0xa2345678), U_("0A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, ':', 0xa2345678), U_("0:0A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, ':', 0xa2345678), U_("00:0A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, ':', 0xa2345678), U_("000:0A2:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', -0x12345678), U_("-12:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, ':', -0x12345678), U_("-12:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, ':', -0x12345678), U_("-012:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, ':', -0x12345678), U_("-0:012:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, ':', -0x12345678), U_("-00:012:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, ':', -0x12345678), U_("-000:012:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, U_(":"), 0xa2345678), U_("A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, U_(":"), 0xa2345678), U_("A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, U_(":"), 0xa2345678), U_("0A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, U_(":"), 0xa2345678), U_("0:0A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, U_(":"), 0xa2345678), U_("00:0A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, U_(":"), 0xa2345678), U_("000:0A2:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, U_(":"), -0x12345678), U_("-12:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, U_(":"), -0x12345678), U_("-12:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, U_(":"), -0x12345678), U_("-012:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, U_(":"), -0x12345678), U_("-0:012:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, U_(":"), -0x12345678), U_("-00:012:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, U_(":"), -0x12345678), U_("-000:012:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, ':', 0x345678), U_("345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, ':', 0x345678), U_("345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', 0x345678), U_("0:345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, ':', -0x345678), U_("-345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, ':', -0x345678), U_("-345:678")); - VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', -0x345678), U_("-0:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, U_(":"), 0x345678), U_("345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, U_(":"), 0x345678), U_("345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, U_(":"), 0x345678), U_("0:345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, U_(":"), -0x345678), U_("-345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, U_(":"), -0x345678), U_("-345:678")); + VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, U_(":"), -0x345678), U_("-0:345:678")); VERIFY_EQUAL(mpt::afmt::left(3, "a"), "a "); VERIFY_EQUAL(mpt::afmt::right(3, "a"), " a"); @@ -653,44 +870,47 @@ static MPT_NOINLINE void TestStringFormatting() VERIFY_EQUAL(mpt::cfmt::center(4, CString(_T("a"))), CString(_T(" a "))); #endif // MPT_WITH_MFC - VERIFY_EQUAL(ConvertStrTo("1"), true); - VERIFY_EQUAL(ConvertStrTo("0"), false); - VERIFY_EQUAL(ConvertStrTo("2"), true); - VERIFY_EQUAL(ConvertStrTo("-0"), false); - VERIFY_EQUAL(ConvertStrTo("-1"), true); + VERIFY_EQUAL(mpt::parse_or("", -1), -1); + VERIFY_EQUAL(mpt::parse_or("0", -1), 0); - VERIFY_EQUAL(ConvertStrTo("586"), 586u); - VERIFY_EQUAL(ConvertStrTo("2147483647"), (uint32)int32_max); - VERIFY_EQUAL(ConvertStrTo("4294967295"), uint32_max); + VERIFY_EQUAL(mpt::parse("1"), true); + VERIFY_EQUAL(mpt::parse("0"), false); + VERIFY_EQUAL(mpt::parse("2"), true); + VERIFY_EQUAL(mpt::parse("-0"), false); + VERIFY_EQUAL(mpt::parse("-1"), true); - VERIFY_EQUAL(ConvertStrTo("-9223372036854775808"), int64_min); - VERIFY_EQUAL(ConvertStrTo("-159"), -159); - VERIFY_EQUAL(ConvertStrTo("9223372036854775807"), int64_max); + VERIFY_EQUAL(mpt::parse("586"), 586u); + VERIFY_EQUAL(mpt::parse("2147483647"), (uint32)int32_max); + VERIFY_EQUAL(mpt::parse("4294967295"), uint32_max); - VERIFY_EQUAL(ConvertStrTo("85059"), 85059u); - VERIFY_EQUAL(ConvertStrTo("9223372036854775807"), (uint64)int64_max); - VERIFY_EQUAL(ConvertStrTo("18446744073709551615"), uint64_max); + VERIFY_EQUAL(mpt::parse("-9223372036854775808"), int64_min); + VERIFY_EQUAL(mpt::parse("-159"), -159); + VERIFY_EQUAL(mpt::parse("9223372036854775807"), int64_max); - VERIFY_EQUAL(ConvertStrTo("-87.0"), -87.0f); + VERIFY_EQUAL(mpt::parse("85059"), 85059u); + VERIFY_EQUAL(mpt::parse("9223372036854775807"), (uint64)int64_max); + VERIFY_EQUAL(mpt::parse("18446744073709551615"), uint64_max); + + VERIFY_EQUAL(mpt::parse("-87.0"), -87.0f); #if !MPT_OS_DJGPP - VERIFY_EQUAL(ConvertStrTo("-0.5e-6"), -0.5e-6); + VERIFY_EQUAL(mpt::parse("-0.5e-6"), -0.5e-6); #endif #if !MPT_OS_DJGPP - VERIFY_EQUAL(ConvertStrTo("58.65403492763"), 58.65403492763); + VERIFY_EQUAL(mpt::parse("58.65403492763"), 58.65403492763); #else - VERIFY_EQUAL_EPS(ConvertStrTo("58.65403492763"), 58.65403492763, 0.0001); + VERIFY_EQUAL_EPS(mpt::parse("58.65403492763"), 58.65403492763, 0.0001); #endif - VERIFY_EQUAL(ConvertStrTo(mpt::afmt::val(-87.0)), -87.0f); + VERIFY_EQUAL(mpt::parse(mpt::afmt::val(-87.0)), -87.0f); #if !MPT_OS_DJGPP - VERIFY_EQUAL(ConvertStrTo(mpt::afmt::val(-0.5e-6)), -0.5e-6); + VERIFY_EQUAL(mpt::parse(mpt::afmt::val(-0.5e-6)), -0.5e-6); #endif - VERIFY_EQUAL(mpt::String::Parse::Hex("fe"), 254); -#if MPT_WSTRING_FORMAT - VERIFY_EQUAL(mpt::String::Parse::Hex(L"fe"), 254); + VERIFY_EQUAL(mpt::parse_hex("fe"), 254); +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) + VERIFY_EQUAL(mpt::parse_hex(L"fe"), 254); #endif - VERIFY_EQUAL(mpt::String::Parse::Hex(U_("ffff")), 65535); + VERIFY_EQUAL(mpt::parse_hex(U_("ffff")), 65535); TestFloatFormats(0.0f); TestFloatFormats(-0.0f); @@ -730,7 +950,7 @@ static MPT_NOINLINE void TestStringFormatting() VERIFY_EQUAL(mpt::afmt::flt(6.12345, 4), "6.123"); VERIFY_EQUAL(mpt::afmt::fix(6.12345, 4), "6.1235"); -#if MPT_WSTRING_FORMAT +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) VERIFY_EQUAL(mpt::wfmt::flt(6.12345, 3), L"6.12"); VERIFY_EQUAL(mpt::wfmt::fix(6.12345, 3), L"6.123"); VERIFY_EQUAL(mpt::wfmt::flt(6.12345, 4), L"6.123"); @@ -751,7 +971,7 @@ static MPT_NOINLINE void TestStringFormatting() //VERIFY_EQUAL(MPT_AFORMAT("{2}{1}{0}{2}{1}{0}{10}{9}{8}")(0,1,2,3,4,5,6,7,8,9,"a"), "210210a98"); -#if MPT_WSTRING_FORMAT +#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) VERIFY_EQUAL(MPT_WFORMAT("{}{}{}")(1,2,3), L"123"); #endif @@ -783,45 +1003,12 @@ static MPT_NOINLINE void TestStringFormatting() } -namespace { - -struct Gregorian { - int Y,M,D,h,m,s; - static Gregorian FromTM(tm t) { - Gregorian g; - g.Y = t.tm_year + 1900; - g.M = t.tm_mon + 1; - g.D = t.tm_mday; - g.h = t.tm_hour; - g.m = t.tm_min; - g.s = t.tm_sec; - return g; - } - static tm ToTM(Gregorian g) { - tm t; - MemsetZero(t); - t.tm_year = g.Y - 1900; - t.tm_mon = g.M - 1; - t.tm_mday = g.D; - t.tm_hour = g.h; - t.tm_min = g.m; - t.tm_sec = g.s; - return t; - } -}; - -inline bool operator ==(Gregorian a, Gregorian b) { - return a.Y == b.Y && a.M == b.M && a.D == b.D && a.h == b.h && a.m == b.m && a.s == b.s; +static int64 TestDate1(int s, int m, int h, unsigned int D, unsigned int M, int Y) { + return mpt::Date::UnixAsSeconds(mpt::Date::UnixFromUTC(mpt::Date::UTC{Y,M,D,h,m,s})); } -} - -static int64 TestDate1(int s, int m, int h, int D, int M, int Y) { - return mpt::Date::Unix::FromUTC(Gregorian::ToTM(Gregorian{Y,M,D,h,m,s})); -} - -static Gregorian TestDate2(int s, int m, int h, int D, int M, int Y) { - return Gregorian{Y,M,D,h,m,s}; +static mpt::Date::UTC TestDate2(int s, int m, int h, unsigned int D, unsigned int M, int Y) { + return mpt::Date::UTC{Y,M,D,h,m,s}; } @@ -832,25 +1019,25 @@ static MPT_NOINLINE void TestMisc1() VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PC), true); VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PCS), true); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(".mod"), MOD_TYPE_MOD); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("mod"), MOD_TYPE_MOD); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(".s3m"), MOD_TYPE_S3M); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("s3m"), MOD_TYPE_S3M); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(".xm"), MOD_TYPE_XM); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("xm"), MOD_TYPE_XM); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(".it"), MOD_TYPE_IT); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("it"), MOD_TYPE_IT); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(".itp"), MOD_TYPE_NONE); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("itp"), MOD_TYPE_NONE); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("mptm"), MOD_TYPE_MPT); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("invalidExtension"), MOD_TYPE_NONE); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("ita"), MOD_TYPE_NONE); - VERIFY_EQUAL(CModSpecifications::ExtensionToType("s2m"), MOD_TYPE_NONE); - VERIFY_EQUAL(CModSpecifications::ExtensionToType(""), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_(".mod")), MOD_TYPE_MOD); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("mod")), MOD_TYPE_MOD); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_(".s3m")), MOD_TYPE_S3M); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("s3m")), MOD_TYPE_S3M); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_(".xm")), MOD_TYPE_XM); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("xm")), MOD_TYPE_XM); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_(".it")), MOD_TYPE_IT); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("it")), MOD_TYPE_IT); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_(".itp")), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("itp")), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("mptm")), MOD_TYPE_MPT); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("invalidExtension")), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("ita")), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("s2m")), MOD_TYPE_NONE); + VERIFY_EQUAL(CModSpecifications::ExtensionToType(U_("")), MOD_TYPE_NONE); // invalid - VERIFY_EQUAL(SampleFormat::FromInt(0), SampleFormat::Invalid); - VERIFY_EQUAL(SampleFormat::FromInt(0b0'0000'11'0), SampleFormat::Invalid); + VERIFY_EQUAL(SampleFormat::FromInt(0), SampleFormat::Default); + VERIFY_EQUAL(SampleFormat::FromInt(0b0'0000'11'0), SampleFormat::Default); // correct VERIFY_EQUAL(SampleFormat::FromInt(0b0'0001'00'1), SampleFormat::Unsigned8); @@ -862,10 +1049,10 @@ static MPT_NOINLINE void TestMisc1() VERIFY_EQUAL(SampleFormat::FromInt(0b1'1000'00'0), SampleFormat::Float64); // no size - VERIFY_EQUAL(SampleFormat::FromInt(0b0'0000'00'0), SampleFormat::Invalid); + VERIFY_EQUAL(SampleFormat::FromInt(0b0'0000'00'0), SampleFormat::Default); VERIFY_EQUAL(SampleFormat::FromInt(0b0'0000'00'1), SampleFormat::Unsigned8); VERIFY_EQUAL(SampleFormat::FromInt(0b1'0000'00'0), SampleFormat::Float32); - VERIFY_EQUAL(SampleFormat::FromInt(0b1'0000'00'1), SampleFormat::Invalid); + VERIFY_EQUAL(SampleFormat::FromInt(0b1'0000'00'1), SampleFormat::Default); // invalid unsigned VERIFY_EQUAL(SampleFormat::FromInt(0b0'0010'00'1), SampleFormat::Int16); @@ -967,7 +1154,7 @@ static MPT_NOINLINE void TestMisc2() data.push_back(mpt::as_byte(2)); mpt::PathString fn = GetTempFilenameBase() + P_("lazy"); RemoveFile(fn); - mpt::LazyFileRef f(fn); + mpt::IO::FileRef f(fn); f = data; std::vector data2; data2 = f; @@ -1051,7 +1238,7 @@ static MPT_NOINLINE void TestMisc2() VERIFY_EQUAL(SamplePosition(1, 0) * 3, SamplePosition(3, 0)); VERIFY_EQUAL((SamplePosition(6, 0) / SamplePosition(2, 0)), 3); - VERIFY_EQUAL(srlztn::ID::FromInt(static_cast(0x87654321u)).AsString(), srlztn::ID("\x21\x43\x65\x87").AsString()); + VERIFY_EQUAL(srlztn::ID::FromInt(static_cast(0x87654321u)), srlztn::ID("\x21\x43\x65\x87")); #if defined(MODPLUG_TRACKER) @@ -1092,30 +1279,30 @@ static MPT_NOINLINE void TestMisc2() VERIFY_EQUAL( 1413064016, TestDate1( 56, 46, 21, 11, 10, 2014 )); VERIFY_EQUAL( 1413064100, TestDate1( 20, 48, 21, 11, 10, 2014 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 0).AsUTC()), TestDate2( 0, 0, 0, 1, 1, 1970 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 3600).AsUTC()), TestDate2( 0, 0, 1, 1, 1, 1970 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 86400).AsUTC()), TestDate2( 0, 0, 0, 2, 1, 1970 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 31536000).AsUTC()), TestDate2( 0, 0, 0, 1, 1, 1971 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 100000000).AsUTC()), TestDate2( 40, 46, 9, 3, 3, 1973 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 951782400).AsUTC()), TestDate2( 0, 0, 0, 29, 2, 2000 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1000000000).AsUTC()), TestDate2( 40, 46, 1, 9, 9, 2001 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1044057600).AsUTC()), TestDate2( 0, 0, 0, 1, 2, 2003 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1044144000).AsUTC()), TestDate2( 0, 0, 0, 2, 2, 2003 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1046476800).AsUTC()), TestDate2( 0, 0, 0, 1, 3, 2003 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1064966400).AsUTC()), TestDate2( 0, 0, 0, 1, 10, 2003 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1077926399).AsUTC()), TestDate2( 59, 59, 23, 27, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1077926400).AsUTC()), TestDate2( 0, 0, 0, 28, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1077926410).AsUTC()), TestDate2( 10, 0, 0, 28, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078012799).AsUTC()), TestDate2( 59, 59, 23, 28, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078012800).AsUTC()), TestDate2( 0, 0, 0, 29, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078012820).AsUTC()), TestDate2( 20, 0, 0, 29, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078099199).AsUTC()), TestDate2( 59, 59, 23, 29, 2, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078099200).AsUTC()), TestDate2( 0, 0, 0, 1, 3, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078099230).AsUTC()), TestDate2( 30, 0, 0, 1, 3, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1078185599).AsUTC()), TestDate2( 59, 59, 23, 1, 3, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1096588800).AsUTC()), TestDate2( 0, 0, 0, 1, 10, 2004 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1413064016).AsUTC()), TestDate2( 56, 46, 21, 11, 10, 2014 )); - VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix( 1413064100).AsUTC()), TestDate2( 20, 48, 21, 11, 10, 2014 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 0)), TestDate2( 0, 0, 0, 1, 1, 1970 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 3600)), TestDate2( 0, 0, 1, 1, 1, 1970 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 86400)), TestDate2( 0, 0, 0, 2, 1, 1970 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 31536000)), TestDate2( 0, 0, 0, 1, 1, 1971 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 100000000)), TestDate2( 40, 46, 9, 3, 3, 1973 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 951782400)), TestDate2( 0, 0, 0, 29, 2, 2000 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1000000000)), TestDate2( 40, 46, 1, 9, 9, 2001 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1044057600)), TestDate2( 0, 0, 0, 1, 2, 2003 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1044144000)), TestDate2( 0, 0, 0, 2, 2, 2003 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1046476800)), TestDate2( 0, 0, 0, 1, 3, 2003 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1064966400)), TestDate2( 0, 0, 0, 1, 10, 2003 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1077926399)), TestDate2( 59, 59, 23, 27, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1077926400)), TestDate2( 0, 0, 0, 28, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1077926410)), TestDate2( 10, 0, 0, 28, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078012799)), TestDate2( 59, 59, 23, 28, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078012800)), TestDate2( 0, 0, 0, 29, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078012820)), TestDate2( 20, 0, 0, 29, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078099199)), TestDate2( 59, 59, 23, 29, 2, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078099200)), TestDate2( 0, 0, 0, 1, 3, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078099230)), TestDate2( 30, 0, 0, 1, 3, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1078185599)), TestDate2( 59, 59, 23, 1, 3, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1096588800)), TestDate2( 0, 0, 0, 1, 10, 2004 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1413064016)), TestDate2( 56, 46, 21, 11, 10, 2014 )); + VERIFY_EQUAL(mpt::Date::UnixAsUTC(mpt::Date::UnixFromSeconds( 1413064100)), TestDate2( 20, 48, 21, 11, 10, 2014 )); #ifdef MODPLUG_TRACKER @@ -1320,7 +1507,7 @@ static MPT_NOINLINE void TestMisc2() float f = ::powf(2.0f, exp); double d = ::pow (2.0 , (double)exp); VERIFY_EQUAL_EPS(d, 6.349605, 0.00001); - VERIFY_EQUAL_EPS(f, 6.349605, 0.00001); + VERIFY_EQUAL_EPS(f, 6.349605f, 0.00001f); #endif } @@ -1379,164 +1566,227 @@ static MPT_NOINLINE void TestRandom() } -static MPT_NOINLINE void TestCharsets() +static MPT_NOINLINE void TestPathNative() { // Path splitting -#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS +#if MPT_OS_WINDOWS + VERIFY_EQUAL(P_("").GetPrefix(), P_("")); VERIFY_EQUAL(P_("").GetDrive(), P_("")); - VERIFY_EQUAL(P_("").GetDir(), P_("")); - VERIFY_EQUAL(P_("").GetPath(), P_("")); - VERIFY_EQUAL(P_("").GetFileName(), P_("")); - VERIFY_EQUAL(P_("").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("").GetDirectoryWithDrive(), P_("")); + VERIFY_EQUAL(P_("").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("").GetFilename(), P_("")); + VERIFY_EQUAL(P_("C:\\").GetPrefix(), P_("")); VERIFY_EQUAL(P_("C:\\").GetDrive(), P_("C:")); - VERIFY_EQUAL(P_("C:\\").GetDir(), P_("\\")); - VERIFY_EQUAL(P_("C:\\").GetPath(), P_("C:\\")); - VERIFY_EQUAL(P_("C:\\").GetFileName(), P_("")); - VERIFY_EQUAL(P_("C:\\").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("C:\\").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("C:\\").GetDirectory(), P_("\\")); + VERIFY_EQUAL(P_("C:\\").GetDirectoryWithDrive(), P_("C:\\")); + VERIFY_EQUAL(P_("C:\\").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("C:\\").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("C:\\").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\directory\\").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\directory\\").GetDrive(), P_("")); - VERIFY_EQUAL(P_("\\directory\\").GetDir(), P_("\\directory\\")); - VERIFY_EQUAL(P_("\\directory\\").GetPath(), P_("\\directory\\")); - VERIFY_EQUAL(P_("\\directory\\").GetFileName(), P_("")); - VERIFY_EQUAL(P_("\\directory\\").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("\\directory\\").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("\\directory\\").GetDirectory(), P_("\\directory\\")); + VERIFY_EQUAL(P_("\\directory\\").GetDirectoryWithDrive(), P_("\\directory\\")); + VERIFY_EQUAL(P_("\\directory\\").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("\\directory\\").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("\\directory\\").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\directory\\file.txt").GetDrive(), P_("")); - VERIFY_EQUAL(P_("\\directory\\file.txt").GetDir(), P_("\\directory\\")); - VERIFY_EQUAL(P_("\\directory\\file.txt").GetPath(), P_("\\directory\\")); - VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileName(), P_("file")); - VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileExt(), P_(".txt")); - VERIFY_EQUAL(P_("\\directory\\file.txt").GetFullFileName(), P_("file.txt")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetDirectory(), P_("\\directory\\")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetDirectoryWithDrive(), P_("\\directory\\")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetFilenameBase(), P_("file")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("\\directory\\file.txt").GetFilename(), P_("file.txt")); + VERIFY_EQUAL(P_(".").GetPrefix(), P_("")); VERIFY_EQUAL(P_(".").GetDrive(), P_("")); - VERIFY_EQUAL(P_(".").GetDir(), P_("")); - VERIFY_EQUAL(P_(".").GetPath(), P_("")); - VERIFY_EQUAL(P_(".").GetFileName(), P_(".")); - VERIFY_EQUAL(P_(".").GetFileExt(), P_("")); - VERIFY_EQUAL(P_(".").GetFullFileName(), P_(".")); + VERIFY_EQUAL(P_(".").GetDirectory(), P_("")); + VERIFY_EQUAL(P_(".").GetDirectoryWithDrive(), P_("")); + VERIFY_EQUAL(P_(".").GetFilenameBase(), P_(".")); + VERIFY_EQUAL(P_(".").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_(".").GetFilename(), P_(".")); + VERIFY_EQUAL(P_("..").GetPrefix(), P_("")); VERIFY_EQUAL(P_("..").GetDrive(), P_("")); - VERIFY_EQUAL(P_("..").GetDir(), P_("")); - VERIFY_EQUAL(P_("..").GetPath(), P_("")); - VERIFY_EQUAL(P_("..").GetFileName(), P_("..")); - VERIFY_EQUAL(P_("..").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("..").GetFullFileName(), P_("..")); + VERIFY_EQUAL(P_("..").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("..").GetDirectoryWithDrive(), P_("")); + VERIFY_EQUAL(P_("..").GetFilenameBase(), P_("..")); + VERIFY_EQUAL(P_("..").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("..").GetFilename(), P_("..")); + VERIFY_EQUAL(P_("dir\\.").GetPrefix(), P_("")); VERIFY_EQUAL(P_("dir\\.").GetDrive(), P_("")); - VERIFY_EQUAL(P_("dir\\.").GetDir(), P_("dir\\")); - VERIFY_EQUAL(P_("dir\\.").GetPath(), P_("dir\\")); - VERIFY_EQUAL(P_("dir\\.").GetFileName(), P_(".")); - VERIFY_EQUAL(P_("dir\\.").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("dir\\.").GetFullFileName(), P_(".")); + VERIFY_EQUAL(P_("dir\\.").GetDirectory(), P_("dir\\")); + VERIFY_EQUAL(P_("dir\\.").GetDirectoryWithDrive(), P_("dir\\")); + VERIFY_EQUAL(P_("dir\\.").GetFilenameBase(), P_(".")); + VERIFY_EQUAL(P_("dir\\.").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("dir\\.").GetFilename(), P_(".")); + VERIFY_EQUAL(P_("dir\\..").GetPrefix(), P_("")); VERIFY_EQUAL(P_("dir\\..").GetDrive(), P_("")); - VERIFY_EQUAL(P_("dir\\..").GetDir(), P_("dir\\")); - VERIFY_EQUAL(P_("dir\\..").GetPath(), P_("dir\\")); - VERIFY_EQUAL(P_("dir\\..").GetFileName(), P_("..")); - VERIFY_EQUAL(P_("dir\\..").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("dir\\..").GetFullFileName(), P_("..")); + VERIFY_EQUAL(P_("dir\\..").GetDirectory(), P_("dir\\")); + VERIFY_EQUAL(P_("dir\\..").GetDirectoryWithDrive(), P_("dir\\")); + VERIFY_EQUAL(P_("dir\\..").GetFilenameBase(), P_("..")); + VERIFY_EQUAL(P_("dir\\..").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("dir\\..").GetFilename(), P_("..")); + VERIFY_EQUAL(P_(".txt").GetPrefix(), P_("")); VERIFY_EQUAL(P_(".txt").GetDrive(), P_("")); - VERIFY_EQUAL(P_(".txt").GetDir(), P_("")); - VERIFY_EQUAL(P_(".txt").GetPath(), P_("")); - VERIFY_EQUAL(P_(".txt").GetFileName(), P_(".txt")); - VERIFY_EQUAL(P_(".txt").GetFileExt(), P_("")); - VERIFY_EQUAL(P_(".txt").GetFullFileName(), P_(".txt")); + VERIFY_EQUAL(P_(".txt").GetDirectory(), P_("")); + VERIFY_EQUAL(P_(".txt").GetDirectoryWithDrive(), P_("")); + VERIFY_EQUAL(P_(".txt").GetFilenameBase(), P_(".txt")); + VERIFY_EQUAL(P_(".txt").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_(".txt").GetFilename(), P_(".txt")); + VERIFY_EQUAL(P_("C:tmp.txt").GetPrefix(), P_("")); VERIFY_EQUAL(P_("C:tmp.txt").GetDrive(), P_("C:")); - VERIFY_EQUAL(P_("C:tmp.txt").GetDir(), P_("")); - VERIFY_EQUAL(P_("C:tmp.txt").GetPath(), P_("C:")); - VERIFY_EQUAL(P_("C:tmp.txt").GetFileName(), P_("tmp")); - VERIFY_EQUAL(P_("C:tmp.txt").GetFileExt(), P_(".txt")); - VERIFY_EQUAL(P_("C:tmp.txt").GetFullFileName(), P_("tmp.txt")); + VERIFY_EQUAL(P_("C:tmp.txt").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("C:tmp.txt").GetDirectoryWithDrive(), P_("C:")); + VERIFY_EQUAL(P_("C:tmp.txt").GetFilenameBase(), P_("tmp")); + VERIFY_EQUAL(P_("C:tmp.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("C:tmp.txt").GetFilename(), P_("tmp.txt")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetPrefix(), P_("")); VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDrive(), P_("C:")); - VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDir(), P_("tempdir\\")); - VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetPath(), P_("C:tempdir\\")); - VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFileName(), P_("tmp")); - VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFileExt(), P_(".txt")); - VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFullFileName(), P_("tmp.txt")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDirectory(), P_("tempdir\\")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDirectoryWithDrive(), P_("C:tempdir\\")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFilenameBase(), P_("tmp")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFilename(), P_("tmp.txt")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetPrefix(), P_("")); VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDrive(), P_("C:")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDir(), P_("\\tempdir\\")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetPath(), P_("C:\\tempdir\\")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFileName(), P_("tmp")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFileExt(), P_(".txt")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFullFileName(), P_("tmp.txt")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDirectory(), P_("\\tempdir\\")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDirectoryWithDrive(), P_("C:\\tempdir\\")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFilenameBase(), P_("tmp")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFilename(), P_("tmp.txt")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFileName(), P_("tmp.foo")); - VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFileExt(), P_(".txt")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFilenameBase(), P_("tmp.foo")); + VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("\\\\server").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\\\server").GetDrive(), P_("\\\\server")); - VERIFY_EQUAL(P_("\\\\server").GetDir(), P_("")); - VERIFY_EQUAL(P_("\\\\server").GetPath(), P_("\\\\server")); - VERIFY_EQUAL(P_("\\\\server").GetFileName(), P_("")); - VERIFY_EQUAL(P_("\\\\server").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("\\\\server").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("\\\\server").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("\\\\server").GetDirectoryWithDrive(), P_("\\\\server")); + VERIFY_EQUAL(P_("\\\\server").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("\\\\server").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("\\\\server").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\\\server\\").GetDrive(), P_("\\\\server\\")); - VERIFY_EQUAL(P_("\\\\server\\").GetDir(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\").GetPath(), P_("\\\\server\\")); - VERIFY_EQUAL(P_("\\\\server\\").GetFileName(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\").GetDirectoryWithDrive(), P_("\\\\server\\")); + VERIFY_EQUAL(P_("\\\\server\\").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\\\server\\share").GetDrive(), P_("\\\\server\\share")); - VERIFY_EQUAL(P_("\\\\server\\share").GetDir(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\share").GetPath(), P_("\\\\server\\share")); - VERIFY_EQUAL(P_("\\\\server\\share").GetFileName(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\share").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\share").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share").GetDirectoryWithDrive(), P_("\\\\server\\share")); + VERIFY_EQUAL(P_("\\\\server\\share").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\\\server\\share\\").GetDrive(), P_("\\\\server\\share")); - VERIFY_EQUAL(P_("\\\\server\\share\\").GetDir(), P_("\\")); - VERIFY_EQUAL(P_("\\\\server\\share\\").GetPath(), P_("\\\\server\\share\\")); - VERIFY_EQUAL(P_("\\\\server\\share\\").GetFileName(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\share\\").GetFileExt(), P_("")); - VERIFY_EQUAL(P_("\\\\server\\share\\").GetFullFileName(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetDirectory(), P_("\\")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetDirectoryWithDrive(), P_("\\\\server\\share\\")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share\\").GetFilename(), P_("")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetPrefix(), P_("")); VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P_("\\\\server\\share")); - VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDir(), P_("\\dir1\\dir2\\")); - VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetPath(), P_("\\\\server\\share\\dir1\\dir2\\")); - VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileName(), P_("name.foo")); - VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileExt(), P_(".ext")); - VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFullFileName(), P_("name.foo.ext")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectory(), P_("\\dir1\\dir2\\")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectoryWithDrive(), P_("\\\\server\\share\\dir1\\dir2\\")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameBase(), P_("name.foo")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameExtension(), P_(".ext")); + VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilename(), P_("name.foo.ext")); +#if MPT_OS_WINDOWS_WINNT + + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetPrefix(), P_("\\\\?\\")); VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDrive(), P_("C:")); - VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDir(), P_("\\tempdir\\dir.2\\")); - VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetPath(), P_("C:\\tempdir\\dir.2\\")); - VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFileName(), P_("tmp.foo")); - VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFileExt(), P_(".txt")); - VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFullFileName(), P_("tmp.foo.txt")); + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDirectory(), P_("\\tempdir\\dir.2\\")); + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDirectoryWithDrive(), P_("C:\\tempdir\\dir.2\\")); + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilenameBase(), P_("tmp.foo")); + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilename(), P_("tmp.foo.txt")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetPrefix(), P_("\\\\?\\UNC")); VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P_("\\\\server\\share")); - VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDir(), P_("\\dir1\\dir2\\")); - VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetPath(), P_("\\\\server\\share\\dir1\\dir2\\")); - VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileName(), P_("name.foo")); - VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileExt(), P_(".ext")); - VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFullFileName(), P_("name.foo.ext")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectory(), P_("\\dir1\\dir2\\")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectoryWithDrive(), P_("\\\\server\\share\\dir1\\dir2\\")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameBase(), P_("name.foo")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameExtension(), P_(".ext")); + VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilename(), P_("name.foo.ext")); + #endif +#elif !MPT_OS_DJGPP + VERIFY_EQUAL(P_("").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("").GetFilename(), P_("")); - // Path conversions -#ifdef MODPLUG_TRACKER - const mpt::PathString exePath = P_("C:\\OpenMPT\\"); - VERIFY_EQUAL(P_("C:\\OpenMPT\\").AbsolutePathToRelative(exePath), P_(".\\")); - VERIFY_EQUAL(P_("c:\\OpenMPT\\foo").AbsolutePathToRelative(exePath), P_(".\\foo")); - VERIFY_EQUAL(P_("C:\\foo").AbsolutePathToRelative(exePath), P_("\\foo")); - VERIFY_EQUAL(P_(".\\").RelativePathToAbsolute(exePath), P_("C:\\OpenMPT\\")); - VERIFY_EQUAL(P_(".\\foo").RelativePathToAbsolute(exePath), P_("C:\\OpenMPT\\foo")); - VERIFY_EQUAL(P_("\\foo").RelativePathToAbsolute(exePath), P_("C:\\foo")); - VERIFY_EQUAL(P_("\\\\server\\path\\file").AbsolutePathToRelative(exePath), P_("\\\\server\\path\\file")); - VERIFY_EQUAL(P_("\\\\server\\path\\file").RelativePathToAbsolute(exePath), P_("\\\\server\\path\\file")); + VERIFY_EQUAL(P_("/").GetDirectory(), P_("/")); + VERIFY_EQUAL(P_("/").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("/").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("/").GetFilename(), P_("")); + VERIFY_EQUAL(P_("/directory/").GetDirectory(), P_("/directory/")); + VERIFY_EQUAL(P_("/directory/").GetFilenameBase(), P_("")); + VERIFY_EQUAL(P_("/directory/").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("/directory/").GetFilename(), P_("")); + + VERIFY_EQUAL(P_("/directory/file.txt").GetDirectory(), P_("/directory/")); + VERIFY_EQUAL(P_("/directory/file.txt").GetFilenameBase(), P_("file")); + VERIFY_EQUAL(P_("/directory/file.txt").GetFilenameExtension(), P_(".txt")); + VERIFY_EQUAL(P_("/directory/file.txt").GetFilename(), P_("file.txt")); + + VERIFY_EQUAL(P_(".").GetDirectory(), P_("")); + VERIFY_EQUAL(P_(".").GetFilenameBase(), P_(".")); + VERIFY_EQUAL(P_(".").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_(".").GetFilename(), P_(".")); + + VERIFY_EQUAL(P_("..").GetDirectory(), P_("")); + VERIFY_EQUAL(P_("..").GetFilenameBase(), P_("..")); + VERIFY_EQUAL(P_("..").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("..").GetFilename(), P_("..")); + + VERIFY_EQUAL(P_("dir/.").GetDirectory(), P_("dir/")); + VERIFY_EQUAL(P_("dir/.").GetFilenameBase(), P_(".")); + VERIFY_EQUAL(P_("dir/.").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("dir/.").GetFilename(), P_(".")); + + VERIFY_EQUAL(P_("dir/..").GetDirectory(), P_("dir/")); + VERIFY_EQUAL(P_("dir/..").GetFilenameBase(), P_("..")); + VERIFY_EQUAL(P_("dir/..").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("dir/..").GetFilename(), P_("..")); + + VERIFY_EQUAL(P_(".txt").GetDirectory(), P_("")); + VERIFY_EQUAL(P_(".txt").GetFilenameBase(), P_(".txt")); + VERIFY_EQUAL(P_(".txt").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_(".txt").GetFilename(), P_(".txt")); + + VERIFY_EQUAL(P_("//server").GetDirectory(), P_("//")); + VERIFY_EQUAL(P_("//server").GetFilenameBase(), P_("server")); + VERIFY_EQUAL(P_("//server").GetFilenameExtension(), P_("")); + VERIFY_EQUAL(P_("//server").GetFilename(), P_("server")); + +#endif // MPT_OS + +#if MPT_OS_WINDOWS VERIFY_EQUAL(P_("").Simplify(), P_("")); VERIFY_EQUAL(P_(" ").Simplify(), P_(" ")); VERIFY_EQUAL(P_("foo\\bar").Simplify(), P_("foo\\bar")); @@ -1552,10 +1802,608 @@ static MPT_NOINLINE void TestCharsets() VERIFY_EQUAL(P_("C:\\.").Simplify(), P_("C:\\")); VERIFY_EQUAL(P_("\\\\foo\\..\\.bar").Simplify(), P_("\\\\.bar")); VERIFY_EQUAL(P_("\\\\foo\\..\\..\\bar").Simplify(), P_("\\\\bar")); +#elif !MPT_OS_DJGPP + VERIFY_EQUAL(P_("/").Simplify(), P_("/")); + VERIFY_EQUAL(P_("").Simplify(), P_("")); + VERIFY_EQUAL(P_(" ").Simplify(), P_(" ")); + VERIFY_EQUAL(P_("foo/bar").Simplify(), P_("foo/bar")); + VERIFY_EQUAL(P_("./foo/bar").Simplify(), P_("./foo/bar")); + VERIFY_EQUAL(P_(".//foo/bar").Simplify(), P_("./foo/bar")); + VERIFY_EQUAL(P_(".//foo/bar").Simplify(), P_("./foo/bar")); + VERIFY_EQUAL(P_("/foo/bar").Simplify(), P_("/foo/bar")); + VERIFY_EQUAL(P_("//foo/../.bar").Simplify(), P_("/.bar")); + VERIFY_EQUAL(P_("//foo/../../bar").Simplify(), P_("/bar")); +#endif // MPT_OS + +} + + + + +#if MPT_OS_EMSCRIPTEN +#define MPT_EMSCRIPTEN_TEST_PATH_CRASH +#endif // MPT_OS_EMSCRIPTEN + + +#if !defined(MPT_EMSCRIPTEN_TEST_PATH_CRASH) + +static MPT_NOINLINE void TestPathForeignWindowsNT() +{ + { + using P = mpt::BasicPathString>>; + + VERIFY_EQUAL(P::FromNative("").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("C:\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectory(), P::FromNative("\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectoryWithDrive(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameBase(), P::FromNative("file")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilename(), P::FromNative("file.txt")); + + VERIFY_EQUAL(P::FromNative(".").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative("dir\\.").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("dir\\..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative(".txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameBase(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilename(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectory(), P::FromNative("tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectory(), P::FromNative("\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameBase(), P::FromNative("tmp.foo")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameExtension(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("\\\\server").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDrive(), P::FromNative("\\\\server")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDirectoryWithDrive(), P::FromNative("\\\\server")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDrive(), P::FromNative("\\\\server\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDirectoryWithDrive(), P::FromNative("\\\\server\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDirectory(), P::FromNative("\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectory(), P::FromNative("\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameBase(), P::FromNative("name.foo")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameExtension(), P::FromNative(".ext")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilename(), P::FromNative("name.foo.ext")); + + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetPrefix(), P::FromNative("\\\\?\\")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDirectory(), P::FromNative("\\tempdir\\dir.2\\")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDirectoryWithDrive(), P::FromNative("C:\\tempdir\\dir.2\\")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilenameBase(), P::FromNative("tmp.foo")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFilename(), P::FromNative("tmp.foo.txt")); + + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetPrefix(), P::FromNative("\\\\?\\UNC")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectory(), P::FromNative("\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameBase(), P::FromNative("name.foo")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameExtension(), P::FromNative(".ext")); + VERIFY_EQUAL(P::FromNative("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilename(), P::FromNative("name.foo.ext")); + + } +} + +static MPT_NOINLINE void TestPathForeignWindows9x() +{ + { + using P = mpt::BasicPathString>>; + + VERIFY_EQUAL(P::FromNative("").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("C:\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectory(), P::FromNative("\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectoryWithDrive(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameBase(), P::FromNative("file")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilename(), P::FromNative("file.txt")); + + VERIFY_EQUAL(P::FromNative(".").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative("dir\\.").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("dir\\..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative(".txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameBase(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilename(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectory(), P::FromNative("tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectory(), P::FromNative("\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameBase(), P::FromNative("tmp.foo")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameExtension(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("\\\\server").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDrive(), P::FromNative("\\\\server")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetDirectoryWithDrive(), P::FromNative("\\\\server")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDrive(), P::FromNative("\\\\server\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetDirectoryWithDrive(), P::FromNative("\\\\server\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDirectory(), P::FromNative("\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P::FromNative("\\\\server\\share")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectory(), P::FromNative("\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDirectoryWithDrive(), P::FromNative("\\\\server\\share\\dir1\\dir2\\")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameBase(), P::FromNative("name.foo")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilenameExtension(), P::FromNative(".ext")); + VERIFY_EQUAL(P::FromNative("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFilename(), P::FromNative("name.foo.ext")); + + } +} + +static MPT_NOINLINE void TestPathForeignDOSDJGPP() +{ + { + using P = mpt::BasicPathString>>; + + VERIFY_EQUAL(P::FromNative("").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("C:\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectory(), P::FromNative("\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetDirectoryWithDrive(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectory(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetDirectoryWithDrive(), P::FromNative("\\directory\\")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameBase(), P::FromNative("file")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("\\directory\\file.txt").GetFilename(), P::FromNative("file.txt")); + + VERIFY_EQUAL(P::FromNative(".").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative("dir\\.").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\.").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("dir\\..").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectory(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetDirectoryWithDrive(), P::FromNative("dir\\")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir\\..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative(".txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetDirectoryWithDrive(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameBase(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilename(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectory(), P::FromNative("tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetPrefix(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDrive(), P::FromNative("C:")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectory(), P::FromNative("\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetDirectoryWithDrive(), P::FromNative("C:\\tempdir\\")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameBase(), P::FromNative("tmp")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.txt").GetFilename(), P::FromNative("tmp.txt")); + + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameBase(), P::FromNative("tmp.foo")); + VERIFY_EQUAL(P::FromNative("C:\\tempdir\\tmp.foo.txt").GetFilenameExtension(), P::FromNative(".txt")); + + } +} + +static MPT_NOINLINE void TestPathForeignPOSIX() +{ + { + using P = mpt::BasicPathString>>; + + VERIFY_EQUAL(P::FromNative("").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("/").GetDirectory(), P::FromNative("/")); + VERIFY_EQUAL(P::FromNative("/").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("/").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("/").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("/directory/").GetDirectory(), P::FromNative("/directory/")); + VERIFY_EQUAL(P::FromNative("/directory/").GetFilenameBase(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("/directory/").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("/directory/").GetFilename(), P::FromNative("")); + + VERIFY_EQUAL(P::FromNative("/directory/file.txt").GetDirectory(), P::FromNative("/directory/")); + VERIFY_EQUAL(P::FromNative("/directory/file.txt").GetFilenameBase(), P::FromNative("file")); + VERIFY_EQUAL(P::FromNative("/directory/file.txt").GetFilenameExtension(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative("/directory/file.txt").GetFilename(), P::FromNative("file.txt")); + + VERIFY_EQUAL(P::FromNative(".").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative(".").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("..").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative("dir/.").GetDirectory(), P::FromNative("dir/")); + VERIFY_EQUAL(P::FromNative("dir/.").GetFilenameBase(), P::FromNative(".")); + VERIFY_EQUAL(P::FromNative("dir/.").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir/.").GetFilename(), P::FromNative(".")); + + VERIFY_EQUAL(P::FromNative("dir/..").GetDirectory(), P::FromNative("dir/")); + VERIFY_EQUAL(P::FromNative("dir/..").GetFilenameBase(), P::FromNative("..")); + VERIFY_EQUAL(P::FromNative("dir/..").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("dir/..").GetFilename(), P::FromNative("..")); + + VERIFY_EQUAL(P::FromNative(".txt").GetDirectory(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameBase(), P::FromNative(".txt")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(".txt").GetFilename(), P::FromNative(".txt")); + + VERIFY_EQUAL(P::FromNative("//server").GetDirectory(), P::FromNative("//")); + VERIFY_EQUAL(P::FromNative("//server").GetFilenameBase(), P::FromNative("server")); + VERIFY_EQUAL(P::FromNative("//server").GetFilenameExtension(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative("//server").GetFilename(), P::FromNative("server")); + + } +} + +#endif // !MPT_EMSCRIPTEN_TEST_PATH_CRASH + + +static MPT_NOINLINE void TestPathForeign() +{ + +#if !defined(MPT_EMSCRIPTEN_TEST_PATH_CRASH) + TestPathForeignWindowsNT(); + TestPathForeignWindows9x(); + TestPathForeignDOSDJGPP(); + TestPathForeignPOSIX(); +#endif // !MPT_EMSCRIPTEN_TEST_PATH_CRASH + + { + using P = mpt::BasicPathString>>; + VERIFY_EQUAL(P::FromNative("").Simplify(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(" ").Simplify(), P::FromNative(" ")); + VERIFY_EQUAL(P::FromNative("foo\\bar").Simplify(), P::FromNative("foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("./\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("\\foo\\bar").Simplify(), P::FromNative("\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\..\\name_3\\").Simplify(), P::FromNative("A:\\name_1\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\..\\name_2\\./name_3").Simplify(), P::FromNative("A:\\name_2\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..").Simplify(), P::FromNative("A:\\name_1\\name_2")); + VERIFY_EQUAL(P::FromNative("A:foo\\\\bar").Simplify(), P::FromNative("A:\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("C:\\..").Simplify(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\.").Simplify(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("\\\\foo\\..\\.bar").Simplify(), P::FromNative("\\\\.bar")); + VERIFY_EQUAL(P::FromNative("\\\\foo\\..\\..\\bar").Simplify(), P::FromNative("\\\\bar")); + } + { + using P = mpt::BasicPathString>>; + VERIFY_EQUAL(P::FromNative("").Simplify(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(" ").Simplify(), P::FromNative(" ")); + VERIFY_EQUAL(P::FromNative("foo\\bar").Simplify(), P::FromNative("foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("./\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("\\foo\\bar").Simplify(), P::FromNative("\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\..\\name_3\\").Simplify(), P::FromNative("A:\\name_1\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\..\\name_2\\./name_3").Simplify(), P::FromNative("A:\\name_2\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..").Simplify(), P::FromNative("A:\\name_1\\name_2")); + VERIFY_EQUAL(P::FromNative("A:foo\\\\bar").Simplify(), P::FromNative("A:\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("C:\\..").Simplify(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\.").Simplify(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("\\\\foo\\..\\.bar").Simplify(), P::FromNative("\\\\.bar")); + VERIFY_EQUAL(P::FromNative("\\\\foo\\..\\..\\bar").Simplify(), P::FromNative("\\\\bar")); + } + { + using P = mpt::BasicPathString>>; + VERIFY_EQUAL(P::FromNative("").Simplify(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(" ").Simplify(), P::FromNative(" ")); + VERIFY_EQUAL(P::FromNative("foo\\bar").Simplify(), P::FromNative("foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative(".\\\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("./\\foo\\bar").Simplify(), P::FromNative(".\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("\\foo\\bar").Simplify(), P::FromNative("\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\..\\name_3\\").Simplify(), P::FromNative("A:\\name_1\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\..\\name_2\\./name_3").Simplify(), P::FromNative("A:\\name_2\\name_3")); + VERIFY_EQUAL(P::FromNative("A:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..").Simplify(), P::FromNative("A:\\name_1\\name_2")); + VERIFY_EQUAL(P::FromNative("A:foo\\\\bar").Simplify(), P::FromNative("A:\\foo\\bar")); + VERIFY_EQUAL(P::FromNative("C:\\..").Simplify(), P::FromNative("C:\\")); + VERIFY_EQUAL(P::FromNative("C:\\.").Simplify(), P::FromNative("C:\\")); + } + { + using P = mpt::BasicPathString < mpt::PathTraits>>; + VERIFY_EQUAL(P::FromNative("/").Simplify(), P::FromNative("/")); + VERIFY_EQUAL(P::FromNative("").Simplify(), P::FromNative("")); + VERIFY_EQUAL(P::FromNative(" ").Simplify(), P::FromNative(" ")); + VERIFY_EQUAL(P::FromNative("foo/bar").Simplify(), P::FromNative("foo/bar")); + VERIFY_EQUAL(P::FromNative("./foo/bar").Simplify(), P::FromNative("./foo/bar")); + VERIFY_EQUAL(P::FromNative(".//foo/bar").Simplify(), P::FromNative("./foo/bar")); + VERIFY_EQUAL(P::FromNative(".//foo/bar").Simplify(), P::FromNative("./foo/bar")); + VERIFY_EQUAL(P::FromNative("/foo/bar").Simplify(), P::FromNative("/foo/bar")); + VERIFY_EQUAL(P::FromNative("//foo/../.bar").Simplify(), P::FromNative("/.bar")); + VERIFY_EQUAL(P::FromNative("//foo/../../bar").Simplify(), P::FromNative("/bar")); + } + +} + + + +static MPT_NOINLINE void TestCharsets() +{ + + // Path conversions +#ifdef MODPLUG_TRACKER + const mpt::PathString exePath = P_("C:\\OpenMPT\\"); + VERIFY_EQUAL(mpt::AbsolutePathToRelative(P_("C:\\OpenMPT\\"), exePath), P_(".\\")); + VERIFY_EQUAL(mpt::AbsolutePathToRelative(P_("c:\\OpenMPT\\foo"), exePath), P_(".\\foo")); + VERIFY_EQUAL(mpt::AbsolutePathToRelative(P_("C:\\foo"), exePath), P_("\\foo")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_(".\\"), exePath), P_("C:\\OpenMPT\\")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_(".\\foo"), exePath), P_("C:\\OpenMPT\\foo")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_("..\\foo"), exePath).Simplify(), P_("C:\\foo")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_("..\\..\\foo"), exePath).Simplify(), P_("C:\\foo")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_("file"), exePath), P_("C:\\OpenMPT\\file")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_("\\foo"), exePath), P_("C:\\foo")); + VERIFY_EQUAL(mpt::AbsolutePathToRelative(P_("\\\\server\\path\\file"), exePath), P_("\\\\server\\path\\file")); + VERIFY_EQUAL(mpt::RelativePathToAbsolute(P_("\\\\server\\path\\file"), exePath), P_("\\\\server\\path\\file")); #endif - - #ifdef MODPLUG_TRACKER #if MPT_COMPILER_MSVC @@ -1697,7 +2545,7 @@ inline Test::CustomSettingsTestType FromSettingValue(const SettingValue &val) std::size_t pos = xy.find(U_("|")); mpt::ustring x = xy.substr(0, pos); mpt::ustring y = xy.substr(pos + 1); - return Test::CustomSettingsTestType(ConvertStrTo(x), ConvertStrTo(y)); + return Test::CustomSettingsTestType(mpt::parse(x), mpt::parse(y)); } template <> @@ -2072,12 +2920,37 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile) // Edit history VERIFY_EQUAL_NONCONT(sndFile.GetFileHistory().size() > 15, true); const FileHistory &fh = sndFile.GetFileHistory().front(); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_year, 111); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_mon, 5); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_mday, 14); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_hour, 21); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_min, 8); - VERIFY_EQUAL_NONCONT(fh.loadDate.tm_sec, 32); +#ifdef MODPLUG_TRACKER + if(sndFile.GetTimezoneInternal() == mpt::Date::LogicalTimezone::UTC) + { + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).year, 2011); + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).month, 6); + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).day, 14); +#if MPT_CXX_AT_LEAST(20) && !defined(MPT_LIBCXX_QUIRK_NO_CHRONO_DATE) + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).hours, 21); +#else +#if defined(MPT_FALLBACK_TIMEZONE_WINDOWS_HISTORIC) + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).hours, 21); +#elif defined(MPT_FALLBACK_TIMEZONE_WINDOWS_CURRENT) + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).hours, 21); +#elif defined(MPT_FALLBACK_TIMEZONE_C) + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).hours, 22); +#else + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).hours, 22); +#endif +#endif + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).minutes, 8); + VERIFY_EQUAL_NONCONT(mpt::Date::forget_timezone(mpt::Date::UnixAsLocal(mpt::Date::UnixFromUTC(mpt::Date::interpret_as_timezone(fh.loadDate)))).seconds, 32); + } else +#endif // MODPLUG_TRACKER + { + VERIFY_EQUAL_NONCONT(fh.loadDate.year, 2011); + VERIFY_EQUAL_NONCONT(fh.loadDate.month, 6); + VERIFY_EQUAL_NONCONT(fh.loadDate.day, 14); + VERIFY_EQUAL_NONCONT(fh.loadDate.hours, 21); + VERIFY_EQUAL_NONCONT(fh.loadDate.minutes, 8); + VERIFY_EQUAL_NONCONT(fh.loadDate.seconds, 32); + } VERIFY_EQUAL_NONCONT((uint32)((double)fh.openTime / HISTORY_TIMER_PRECISION), 31); // Macros @@ -2214,8 +3087,8 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile) { const ModInstrument *pIns = sndFile.Instruments[ins]; VERIFY_EQUAL_NONCONT(pIns->nGlobalVol, 32); - VERIFY_EQUAL_NONCONT(pIns->nFadeOut, 1024); - VERIFY_EQUAL_NONCONT(pIns->nPan, 64); + VERIFY_EQUAL_NONCONT(pIns->nFadeOut, (ins == 1) ? 1023u : 8992u); + VERIFY_EQUAL_NONCONT(pIns->nPan, 63); VERIFY_EQUAL_NONCONT(pIns->dwFlags, INS_SETPANNING); VERIFY_EQUAL_NONCONT(pIns->nPPS, 8); @@ -2243,7 +3116,7 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile) VERIFY_EQUAL_NONCONT(pIns->nMidiChannel, 16); VERIFY_EQUAL_NONCONT(pIns->nMidiProgram, 64); VERIFY_EQUAL_NONCONT(pIns->wMidiBank, 2); - VERIFY_EQUAL_NONCONT(pIns->midiPWD, ins); + VERIFY_EQUAL_NONCONT(pIns->midiPWD, -1); VERIFY_EQUAL_NONCONT(pIns->pTuning, sndFile.GetDefaultTuning()); @@ -2382,9 +3255,9 @@ static void TestLoadMPTMFile(const CSoundFile &sndFile) VERIFY_EQUAL_NONCONT(chns[69].color, ModChannelSettings::INVALID_COLOR); #endif - VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(0)), 0); - VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(80)), 80); - VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(127)), 127); + VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(static_cast(sndFile.CutOffToFrequency(0))), 0); + VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(static_cast(sndFile.CutOffToFrequency(80))), 80); + VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(static_cast(sndFile.CutOffToFrequency(127))), 127); } @@ -2606,9 +3479,9 @@ static void TestLoadMODFile(CSoundFile &sndFile) static bool ShouldRunTests() { mpt::PathString theFile = theApp.GetInstallPath(); - if(theFile.IsDirectory() && (theFile + P_("test")).IsDirectory()) + if(mpt::native_fs{}.is_directory(theFile) && mpt::native_fs{}.is_directory(theFile + P_("test"))) { - if((theFile + P_("test\\test.mptm")).IsFile()) + if(mpt::native_fs{}.is_file(theFile + P_("test\\test.mptm"))) { return true; } @@ -2628,7 +3501,7 @@ static mpt::PathString GetTempFilenameBase() return GetTestFilenameBase(); } -typedef CModDoc *TSoundFileContainer; +using TSoundFileContainer = CModDoc *; static CSoundFile &GetSoundFile(TSoundFileContainer &sndFile) { @@ -2672,15 +3545,23 @@ static bool ShouldRunTests() static mpt::PathString GetTestFilenameBase() { +#if MPT_OS_DJGPP + return Test::GetPathPrefix() + P_("test\\test."); +#else return Test::GetPathPrefix() + P_("./test/test."); +#endif } static mpt::PathString GetTempFilenameBase() { +#if MPT_OS_DJGPP + return P_("test."); +#else return P_("./test."); +#endif } -typedef std::shared_ptr TSoundFileContainer; +using TSoundFileContainer = std::shared_ptr; static CSoundFile &GetSoundFile(TSoundFileContainer &sndFile) { @@ -2751,14 +3632,22 @@ static MPT_NOINLINE void TestLoadSaveFile() // Test MPTM file loading { +#if MPT_OS_DJGPP + TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("mpt")); +#else TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("mptm")); +#endif TestLoadMPTMFile(GetSoundFile(sndFileContainer)); #ifndef MODPLUG_NO_FILESAVE // Test file saving GetSoundFile(sndFileContainer).m_dwLastSavedWithVersion = Version::Current(); +#if MPT_OS_DJGPP + SaveIT(sndFileContainer, filenameBase + P_("spt")); +#else SaveIT(sndFileContainer, filenameBase + P_("saved.mptm")); +#endif #endif DestroySoundFileContainer(sndFileContainer); @@ -2767,13 +3656,21 @@ static MPT_NOINLINE void TestLoadSaveFile() // Reload the saved file and test if everything is still working correctly. #ifndef MODPLUG_NO_FILESAVE { +#if MPT_OS_DJGPP + TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("spt")); +#else TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.mptm")); +#endif TestLoadMPTMFile(GetSoundFile(sndFileContainer)); DestroySoundFileContainer(sndFileContainer); +#if MPT_OS_DJGPP + RemoveFile(filenameBase + P_("spt")); +#else RemoveFile(filenameBase + P_("saved.mptm")); +#endif } #endif @@ -2794,7 +3691,11 @@ static MPT_NOINLINE void TestLoadSaveFile() #ifndef MODPLUG_NO_FILESAVE // Test file saving GetSoundFile(sndFileContainer).m_dwLastSavedWithVersion = Version::Current(); +#if MPT_OS_DJGPP + SaveXM(sndFileContainer, filenameBase + P_("sxm")); +#else SaveXM(sndFileContainer, filenameBase + P_("saved.xm")); +#endif #endif DestroySoundFileContainer(sndFileContainer); @@ -2803,13 +3704,21 @@ static MPT_NOINLINE void TestLoadSaveFile() // Reload the saved file and test if everything is still working correctly. #ifndef MODPLUG_NO_FILESAVE { +#if MPT_OS_DJGPP + TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("sxm")); +#else TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.xm")); +#endif TestLoadXMFile(GetSoundFile(sndFileContainer)); DestroySoundFileContainer(sndFileContainer); +#if MPT_OS_DJGPP + RemoveFile(filenameBase + P_("sxm")); +#else RemoveFile(filenameBase + P_("saved.xm")); +#endif } #endif @@ -2839,7 +3748,11 @@ static MPT_NOINLINE void TestLoadSaveFile() // Test file saving sndFile.ChnSettings[1].dwFlags.set(CHN_MUTE); sndFile.m_dwLastSavedWithVersion = Version::Current(); +#if MPT_OS_DJGPP + SaveS3M(sndFileContainer, filenameBase + P_("ss3")); +#else SaveS3M(sndFileContainer, filenameBase + P_("saved.s3m")); +#endif #endif DestroySoundFileContainer(sndFileContainer); @@ -2848,13 +3761,21 @@ static MPT_NOINLINE void TestLoadSaveFile() // Reload the saved file and test if everything is still working correctly. #ifndef MODPLUG_NO_FILESAVE { +#if MPT_OS_DJGPP + TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("ss3")); +#else TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.s3m")); +#endif TestLoadS3MFile(GetSoundFile(sndFileContainer), true); DestroySoundFileContainer(sndFileContainer); +#if MPT_OS_DJGPP + RemoveFile(filenameBase + P_("ss3")); +#else RemoveFile(filenameBase + P_("saved.s3m")); +#endif } #endif @@ -2867,7 +3788,11 @@ static MPT_NOINLINE void TestLoadSaveFile() #ifndef MODPLUG_NO_FILESAVE // Test file saving +#if MPT_OS_DJGPP + SaveMOD(sndFileContainer, filenameBase + P_("smo")); +#else SaveMOD(sndFileContainer, filenameBase + P_("saved.mod")); +#endif #endif DestroySoundFileContainer(sndFileContainer); @@ -2876,10 +3801,18 @@ static MPT_NOINLINE void TestLoadSaveFile() // Reload the saved file and test if everything is still working correctly. #ifndef MODPLUG_NO_FILESAVE { +#if MPT_OS_DJGPP + TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("smo")); +#else TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.mod")); +#endif TestLoadMODFile(GetSoundFile(sndFileContainer)); DestroySoundFileContainer(sndFileContainer); +#if MPT_OS_DJGPP + RemoveFile(filenameBase + P_("smo")); +#else RemoveFile(filenameBase + P_("saved.mod")); +#endif } #endif @@ -3177,8 +4110,15 @@ static inline std::size_t strnlen(const char *str, std::size_t n) // Test String I/O functionality -static MPT_NOINLINE void TestStringIO() + +static MPT_NOINLINE void TestStringIO1() { + +#if MPT_COMPILER_MSVC +#pragma warning(push) +#pragma warning(disable:6054) // String '' might not be zero-terminated. +#endif // MPT_COMPILER_MSVC + char src0[4] = { '\0', 'X', ' ', 'X' }; // Weird empty buffer char src1[4] = { 'X', ' ', '\0', 'X' }; // Weird buffer (hello Impulse Tracker) char src2[4] = { 'X', 'Y', 'Z', ' ' }; // Full buffer, last character space @@ -3316,6 +4256,10 @@ static MPT_NOINLINE void TestStringIO() #undef ReadTest #undef WriteTest +#if MPT_COMPILER_MSVC +#pragma warning(push) +#endif // MPT_COMPILER_MSVC + { std::string dststring; @@ -3423,7 +4367,10 @@ static MPT_NOINLINE void TestStringIO() #undef WriteTest } +} +static MPT_NOINLINE void TestStringIO2() +{ { char s0[4] = {'\0', 'X', ' ', 'X' }; @@ -3534,9 +4481,13 @@ static MPT_NOINLINE void TestStringIO() #undef CopyTest } - } +static MPT_NOINLINE void TestStringIO() +{ + TestStringIO1(); + TestStringIO2(); +} static MPT_NOINLINE void TestSampleConversion() { diff --git a/Frameworks/OpenMPT/libOpenMPT.xcodeproj/project.pbxproj b/Frameworks/OpenMPT/libOpenMPT.xcodeproj/project.pbxproj index e38610aaa..ea487342e 100644 --- a/Frameworks/OpenMPT/libOpenMPT.xcodeproj/project.pbxproj +++ b/Frameworks/OpenMPT/libOpenMPT.xcodeproj/project.pbxproj @@ -180,6 +180,43 @@ 831132EA21F9565F001F678F /* OPL.h in Headers */ = {isa = PBXBuildFile; fileRef = 831132E521F9565F001F678F /* OPL.h */; }; 831132EB21F9565F001F678F /* Load_c67.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831132E621F9565F001F678F /* Load_c67.cpp */; }; 831132EC21F9565F001F678F /* OPL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 831132E721F9565F001F678F /* OPL.cpp */; }; + 83649B972A0340FF00CD0580 /* mptFileTemporary.h in Headers */ = {isa = PBXBuildFile; fileRef = 83649B922A0340FF00CD0580 /* mptFileTemporary.h */; }; + 83649B982A0340FF00CD0580 /* mptFileTemporary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83649B932A0340FF00CD0580 /* mptFileTemporary.cpp */; }; + 83649B992A0340FF00CD0580 /* mptCPU.h in Headers */ = {isa = PBXBuildFile; fileRef = 83649B942A0340FF00CD0580 /* mptCPU.h */; }; + 83649B9A2A0340FF00CD0580 /* mptFileType.h in Headers */ = {isa = PBXBuildFile; fileRef = 83649B952A0340FF00CD0580 /* mptFileType.h */; }; + 83649B9B2A0340FF00CD0580 /* mptFileType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83649B962A0340FF00CD0580 /* mptFileType.cpp */; }; + 83649B9D2A03414400CD0580 /* libopenmpt_stream_callbacks_file_posix_lfs64.h in Headers */ = {isa = PBXBuildFile; fileRef = 83649B9C2A03414400CD0580 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */; }; + 83649BA12A03416B00CD0580 /* Load_gt2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83649B9E2A03416B00CD0580 /* Load_gt2.cpp */; }; + 83649BA22A03416B00CD0580 /* Load_xmf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83649B9F2A03416B00CD0580 /* Load_xmf.cpp */; }; + 83649BA32A03416B00CD0580 /* Load_667.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83649BA02A03416B00CD0580 /* Load_667.cpp */; }; + 83649BA82A03418600CD0580 /* feature_flags.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BA52A03418500CD0580 /* feature_flags.hpp */; }; + 83649BA92A03418600CD0580 /* arch.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BA62A03418500CD0580 /* arch.hpp */; }; + 83649BAA2A03418600CD0580 /* x86_amd64.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BA72A03418500CD0580 /* x86_amd64.hpp */; }; + 83649BAC2A03419D00CD0580 /* detect_arch.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BAB2A03419D00CD0580 /* detect_arch.hpp */; }; + 83649BAE2A0341B300CD0580 /* compiler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BAD2A0341B300CD0580 /* compiler.hpp */; }; + 83649BB02A0341CF00CD0580 /* tests_endian_int24.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BAF2A0341CF00CD0580 /* tests_endian_int24.hpp */; }; + 83649BB22A0341DC00CD0580 /* type_traits.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BB12A0341DC00CD0580 /* type_traits.hpp */; }; + 83649BB82A03420100CD0580 /* logic_error.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BB42A03420100CD0580 /* logic_error.hpp */; }; + 83649BB92A03420100CD0580 /* exception_text.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BB52A03420100CD0580 /* exception_text.hpp */; }; + 83649BBA2A03420100CD0580 /* runtime_error.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BB62A03420100CD0580 /* runtime_error.hpp */; }; + 83649BBB2A03420100CD0580 /* exception.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BB72A03420100CD0580 /* exception.hpp */; }; + 83649BBD2A03422400CD0580 /* concat.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BBC2A03422400CD0580 /* concat.hpp */; }; + 83649BC82A03424E00CD0580 /* unique_tempfilename.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BBF2A03424E00CD0580 /* unique_tempfilename.hpp */; }; + 83649BC92A03424E00CD0580 /* unique_basename.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC02A03424E00CD0580 /* unique_basename.hpp */; }; + 83649BCA2A03424E00CD0580 /* outputfile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC22A03424E00CD0580 /* outputfile.hpp */; }; + 83649BCB2A03424E00CD0580 /* inputfile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC32A03424E00CD0580 /* inputfile.hpp */; }; + 83649BCC2A03424E00CD0580 /* fileref.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC42A03424E00CD0580 /* fileref.hpp */; }; + 83649BCD2A03424E00CD0580 /* fstream.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC52A03424E00CD0580 /* fstream.hpp */; }; + 83649BCE2A03424E00CD0580 /* fileadapter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BC72A03424E00CD0580 /* fileadapter.hpp */; }; + 83649BD12A03427500CD0580 /* inputfile_filecursor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BD02A03427500CD0580 /* inputfile_filecursor.hpp */; }; + 83649BD52A03429300CD0580 /* dos_version.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BD22A03429300CD0580 /* dos_version.hpp */; }; + 83649BD62A03429300CD0580 /* windows_wine_version.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BD32A03429300CD0580 /* windows_wine_version.hpp */; }; + 83649BD72A03429300CD0580 /* dos_memory.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BD42A03429300CD0580 /* dos_memory.hpp */; }; + 83649BDE2A0342AB00CD0580 /* native_path.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BD92A0342AB00CD0580 /* native_path.hpp */; }; + 83649BDF2A0342AB00CD0580 /* path.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BDA2A0342AB00CD0580 /* path.hpp */; }; + 83649BE02A0342AB00CD0580 /* basic_path.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BDB2A0342AB00CD0580 /* basic_path.hpp */; }; + 83649BE12A0342AB00CD0580 /* os_path_long.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BDC2A0342AB00CD0580 /* os_path_long.hpp */; }; + 83649BE22A0342AB00CD0580 /* os_path.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 83649BDD2A0342AB00CD0580 /* os_path.hpp */; }; 83AA7D322519B694004C5298 /* TinyFFT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7D2E2519B694004C5298 /* TinyFFT.cpp */; }; 83AA7D332519B694004C5298 /* SampleFormatSFZ.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7D2F2519B694004C5298 /* SampleFormatSFZ.cpp */; }; 83AA7D342519B694004C5298 /* SampleFormatBRR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83AA7D302519B694004C5298 /* SampleFormatBRR.cpp */; }; @@ -629,6 +666,43 @@ 831132E521F9565F001F678F /* OPL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPL.h; sourceTree = ""; }; 831132E621F9565F001F678F /* Load_c67.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Load_c67.cpp; sourceTree = ""; }; 831132E721F9565F001F678F /* OPL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OPL.cpp; sourceTree = ""; }; + 83649B922A0340FF00CD0580 /* mptFileTemporary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mptFileTemporary.h; sourceTree = ""; }; + 83649B932A0340FF00CD0580 /* mptFileTemporary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mptFileTemporary.cpp; sourceTree = ""; }; + 83649B942A0340FF00CD0580 /* mptCPU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mptCPU.h; sourceTree = ""; }; + 83649B952A0340FF00CD0580 /* mptFileType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mptFileType.h; sourceTree = ""; }; + 83649B962A0340FF00CD0580 /* mptFileType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mptFileType.cpp; sourceTree = ""; }; + 83649B9C2A03414400CD0580 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libopenmpt_stream_callbacks_file_posix_lfs64.h; sourceTree = ""; }; + 83649B9E2A03416B00CD0580 /* Load_gt2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Load_gt2.cpp; sourceTree = ""; }; + 83649B9F2A03416B00CD0580 /* Load_xmf.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Load_xmf.cpp; sourceTree = ""; }; + 83649BA02A03416B00CD0580 /* Load_667.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Load_667.cpp; sourceTree = ""; }; + 83649BA52A03418500CD0580 /* feature_flags.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = feature_flags.hpp; sourceTree = ""; }; + 83649BA62A03418500CD0580 /* arch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = arch.hpp; sourceTree = ""; }; + 83649BA72A03418500CD0580 /* x86_amd64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = x86_amd64.hpp; sourceTree = ""; }; + 83649BAB2A03419D00CD0580 /* detect_arch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = detect_arch.hpp; sourceTree = ""; }; + 83649BAD2A0341B300CD0580 /* compiler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = compiler.hpp; sourceTree = ""; }; + 83649BAF2A0341CF00CD0580 /* tests_endian_int24.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tests_endian_int24.hpp; sourceTree = ""; }; + 83649BB12A0341DC00CD0580 /* type_traits.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = type_traits.hpp; sourceTree = ""; }; + 83649BB42A03420100CD0580 /* logic_error.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = logic_error.hpp; sourceTree = ""; }; + 83649BB52A03420100CD0580 /* exception_text.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = exception_text.hpp; sourceTree = ""; }; + 83649BB62A03420100CD0580 /* runtime_error.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = runtime_error.hpp; sourceTree = ""; }; + 83649BB72A03420100CD0580 /* exception.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = exception.hpp; sourceTree = ""; }; + 83649BBC2A03422400CD0580 /* concat.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = concat.hpp; sourceTree = ""; }; + 83649BBF2A03424E00CD0580 /* unique_tempfilename.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unique_tempfilename.hpp; sourceTree = ""; }; + 83649BC02A03424E00CD0580 /* unique_basename.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unique_basename.hpp; sourceTree = ""; }; + 83649BC22A03424E00CD0580 /* outputfile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = outputfile.hpp; sourceTree = ""; }; + 83649BC32A03424E00CD0580 /* inputfile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = inputfile.hpp; sourceTree = ""; }; + 83649BC42A03424E00CD0580 /* fileref.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = fileref.hpp; sourceTree = ""; }; + 83649BC52A03424E00CD0580 /* fstream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = fstream.hpp; sourceTree = ""; }; + 83649BC72A03424E00CD0580 /* fileadapter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = fileadapter.hpp; sourceTree = ""; }; + 83649BD02A03427500CD0580 /* inputfile_filecursor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = inputfile_filecursor.hpp; sourceTree = ""; }; + 83649BD22A03429300CD0580 /* dos_version.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = dos_version.hpp; sourceTree = ""; }; + 83649BD32A03429300CD0580 /* windows_wine_version.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = windows_wine_version.hpp; sourceTree = ""; }; + 83649BD42A03429300CD0580 /* dos_memory.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = dos_memory.hpp; sourceTree = ""; }; + 83649BD92A0342AB00CD0580 /* native_path.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = native_path.hpp; sourceTree = ""; }; + 83649BDA2A0342AB00CD0580 /* path.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = path.hpp; sourceTree = ""; }; + 83649BDB2A0342AB00CD0580 /* basic_path.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = basic_path.hpp; sourceTree = ""; }; + 83649BDC2A0342AB00CD0580 /* os_path_long.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = os_path_long.hpp; sourceTree = ""; }; + 83649BDD2A0342AB00CD0580 /* os_path.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = os_path.hpp; sourceTree = ""; }; 83747BC02862D5820021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83AA7D2E2519B694004C5298 /* TinyFFT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TinyFFT.cpp; sourceTree = ""; }; 83AA7D2F2519B694004C5298 /* SampleFormatSFZ.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SampleFormatSFZ.cpp; sourceTree = ""; }; @@ -934,6 +1008,7 @@ isa = PBXGroup; children = ( 8309960F27787E9A00857684 /* .clang-format */, + 83649BA42A03418500CD0580 /* arch */, 8309960A27787E9A00857684 /* audio */, 8309964727787E9A00857684 /* base */, 8309962327787E9A00857684 /* binary */, @@ -942,9 +1017,14 @@ 830995CB27787E9A00857684 /* detect */, 830995D027787E9A00857684 /* endian */, 8309962027787E9A00857684 /* environment */, + 83649BB32A03420100CD0580 /* exception */, 8309964527787E9A00857684 /* exception_text */, 8309961027787E9A00857684 /* format */, 8309960027787E9A00857684 /* io */, + 83649BC12A03424E00CD0580 /* io_file */, + 83649BC62A03424E00CD0580 /* io_file_adapter */, + 83649BCF2A03427500CD0580 /* io_file_read */, + 83649BBE2A03424E00CD0580 /* io_file_unique */, 830995DF27787E9A00857684 /* io_read */, 8309960D27787E9A00857684 /* io_write */, 8309962227787E9A00857684 /* LICENSE.BSD-3-Clause.txt */, @@ -953,6 +1033,7 @@ 830995D727787E9A00857684 /* osinfo */, 830995F227787E9A00857684 /* out_of_memory */, 830995F727787E9A00857684 /* parse */, + 83649BD82A0342AB00CD0580 /* path */, 8309963227787E9A00857684 /* random */, 8309962927787E9A00857684 /* string */, 830995DA27787E9A00857684 /* string_transcode */, @@ -977,10 +1058,11 @@ 830995D027787E9A00857684 /* endian */ = { isa = PBXGroup; children = ( - 830995D127787E9A00857684 /* integer.hpp */, - 830995D227787E9A00857684 /* int24.hpp */, 830995D327787E9A00857684 /* floatingpoint.hpp */, + 830995D227787E9A00857684 /* int24.hpp */, + 830995D127787E9A00857684 /* integer.hpp */, 830995D427787E9A00857684 /* tests */, + 83649BB12A0341DC00CD0580 /* type_traits.hpp */, ); path = endian; sourceTree = ""; @@ -988,8 +1070,9 @@ 830995D427787E9A00857684 /* tests */ = { isa = PBXGroup; children = ( - 830995D527787E9A00857684 /* tests_endian_integer.hpp */, 830995D627787E9A00857684 /* tests_endian_floatingpoint.hpp */, + 83649BAF2A0341CF00CD0580 /* tests_endian_int24.hpp */, + 830995D527787E9A00857684 /* tests_endian_integer.hpp */, ); path = tests; sourceTree = ""; @@ -998,7 +1081,10 @@ isa = PBXGroup; children = ( 830995D827787E9A00857684 /* class.hpp */, + 83649BD42A03429300CD0580 /* dos_memory.hpp */, + 83649BD22A03429300CD0580 /* dos_version.hpp */, 830995D927787E9A00857684 /* windows_version.hpp */, + 83649BD32A03429300CD0580 /* windows_wine_version.hpp */, ); path = osinfo; sourceTree = ""; @@ -1146,19 +1232,20 @@ 8309961027787E9A00857684 /* format */ = { isa = PBXGroup; children = ( - 8309961127787E9A00857684 /* join.hpp */, - 8309961227787E9A00857684 /* default_formatter.hpp */, - 8309961327787E9A00857684 /* simple_integer.hpp */, - 8309961427787E9A00857684 /* simple_floatingpoint.hpp */, - 8309961527787E9A00857684 /* default_string.hpp */, - 8309961627787E9A00857684 /* default_integer.hpp */, - 8309961727787E9A00857684 /* tests */, - 8309961A27787E9A00857684 /* message_macros.hpp */, - 8309961B27787E9A00857684 /* simple.hpp */, + 83649BBC2A03422400CD0580 /* concat.hpp */, 8309961C27787E9A00857684 /* default_floatingpoint.hpp */, + 8309961227787E9A00857684 /* default_formatter.hpp */, + 8309961627787E9A00857684 /* default_integer.hpp */, + 8309961527787E9A00857684 /* default_string.hpp */, 8309961D27787E9A00857684 /* helpers.hpp */, - 8309961E27787E9A00857684 /* simple_spec.hpp */, + 8309961127787E9A00857684 /* join.hpp */, + 8309961A27787E9A00857684 /* message_macros.hpp */, 8309961F27787E9A00857684 /* message.hpp */, + 8309961427787E9A00857684 /* simple_floatingpoint.hpp */, + 8309961327787E9A00857684 /* simple_integer.hpp */, + 8309961E27787E9A00857684 /* simple_spec.hpp */, + 8309961B27787E9A00857684 /* simple.hpp */, + 8309961727787E9A00857684 /* tests */, ); path = format; sourceTree = ""; @@ -1271,6 +1358,7 @@ 8309964127787E9A00857684 /* check */ = { isa = PBXGroup; children = ( + 83649BAD2A0341B300CD0580 /* compiler.hpp */, 8309964227787E9A00857684 /* mfc.hpp */, 8309964327787E9A00857684 /* windows.hpp */, 8309964427787E9A00857684 /* libc.hpp */, @@ -1298,6 +1386,7 @@ 8309965527787E9A00857684 /* check_platform.hpp */, 8309966827787E9A00857684 /* compiletime_warning.hpp */, 8309966D27787E9A00857684 /* constexpr_throw.hpp */, + 83649BAB2A03419D00CD0580 /* detect_arch.hpp */, 8309966C27787E9A00857684 /* detect_compiler.hpp */, 8309964B27787E9A00857684 /* detect_libc.hpp */, 8309966327787E9A00857684 /* detect_libcxx.hpp */, @@ -1410,6 +1499,75 @@ path = base; sourceTree = ""; }; + 83649BA42A03418500CD0580 /* arch */ = { + isa = PBXGroup; + children = ( + 83649BA52A03418500CD0580 /* feature_flags.hpp */, + 83649BA62A03418500CD0580 /* arch.hpp */, + 83649BA72A03418500CD0580 /* x86_amd64.hpp */, + ); + path = arch; + sourceTree = ""; + }; + 83649BB32A03420100CD0580 /* exception */ = { + isa = PBXGroup; + children = ( + 83649BB42A03420100CD0580 /* logic_error.hpp */, + 83649BB52A03420100CD0580 /* exception_text.hpp */, + 83649BB62A03420100CD0580 /* runtime_error.hpp */, + 83649BB72A03420100CD0580 /* exception.hpp */, + ); + path = exception; + sourceTree = ""; + }; + 83649BBE2A03424E00CD0580 /* io_file_unique */ = { + isa = PBXGroup; + children = ( + 83649BBF2A03424E00CD0580 /* unique_tempfilename.hpp */, + 83649BC02A03424E00CD0580 /* unique_basename.hpp */, + ); + path = io_file_unique; + sourceTree = ""; + }; + 83649BC12A03424E00CD0580 /* io_file */ = { + isa = PBXGroup; + children = ( + 83649BC22A03424E00CD0580 /* outputfile.hpp */, + 83649BC32A03424E00CD0580 /* inputfile.hpp */, + 83649BC42A03424E00CD0580 /* fileref.hpp */, + 83649BC52A03424E00CD0580 /* fstream.hpp */, + ); + path = io_file; + sourceTree = ""; + }; + 83649BC62A03424E00CD0580 /* io_file_adapter */ = { + isa = PBXGroup; + children = ( + 83649BC72A03424E00CD0580 /* fileadapter.hpp */, + ); + path = io_file_adapter; + sourceTree = ""; + }; + 83649BCF2A03427500CD0580 /* io_file_read */ = { + isa = PBXGroup; + children = ( + 83649BD02A03427500CD0580 /* inputfile_filecursor.hpp */, + ); + path = io_file_read; + sourceTree = ""; + }; + 83649BD82A0342AB00CD0580 /* path */ = { + isa = PBXGroup; + children = ( + 83649BD92A0342AB00CD0580 /* native_path.hpp */, + 83649BDA2A0342AB00CD0580 /* path.hpp */, + 83649BDB2A0342AB00CD0580 /* basic_path.hpp */, + 83649BDC2A0342AB00CD0580 /* os_path_long.hpp */, + 83649BDD2A0342AB00CD0580 /* os_path.hpp */, + ); + path = path; + sourceTree = ""; + }; 83747BBF2862D5820021245F /* Xcode-config */ = { isa = PBXGroup; children = ( @@ -1478,8 +1636,13 @@ 831132CB21F955B0001F678F /* mptBaseMacros.h */, 831132CE21F955B1001F678F /* mptBaseTypes.h */, 831132D121F955B1001F678F /* mptBaseUtils.h */, + 83649B942A0340FF00CD0580 /* mptCPU.h */, 83E5FC521FFEFA0D00659F0F /* mptFileIO.cpp */, 83E5FC471FFEFA0D00659F0F /* mptFileIO.h */, + 83649B932A0340FF00CD0580 /* mptFileTemporary.cpp */, + 83649B922A0340FF00CD0580 /* mptFileTemporary.h */, + 83649B962A0340FF00CD0580 /* mptFileType.cpp */, + 83649B952A0340FF00CD0580 /* mptFileType.h */, 83E5FC4D1FFEFA0D00659F0F /* mptPathString.cpp */, 83E5FC591FFEFA0D00659F0F /* mptPathString.h */, 83E5FC5B1FFEFA0D00659F0F /* mptRandom.cpp */, @@ -1522,6 +1685,7 @@ 83E5FCA01FFEFA1A00659F0F /* libopenmpt_plugin_settings.hpp */, 83E5FCCA1FFEFA1A00659F0F /* libopenmpt_stream_callbacks_buffer.h */, 83E5FC9D1FFEFA1A00659F0F /* libopenmpt_stream_callbacks_fd.h */, + 83649B9C2A03414400CD0580 /* libopenmpt_stream_callbacks_file_posix_lfs64.h */, 83E5FCAC1FFEFA1A00659F0F /* libopenmpt_stream_callbacks_file.h */, 83E5FCC51FFEFA1A00659F0F /* libopenmpt_version.h */, 83E5FC9F1FFEFA1A00659F0F /* libopenmpt.h */, @@ -1567,6 +1731,7 @@ 83E5FD221FFEFA8400659F0F /* ITCompression.h */, 83E5FD101FFEFA8400659F0F /* ITTools.cpp */, 83E5FD301FFEFA8400659F0F /* ITTools.h */, + 83649BA02A03416B00CD0580 /* Load_667.cpp */, 83E5FD631FFEFA8400659F0F /* Load_669.cpp */, 83E5FD621FFEFA8400659F0F /* Load_amf.cpp */, 83E5FD561FFEFA8400659F0F /* Load_ams.cpp */, @@ -1580,6 +1745,7 @@ 83E5FD261FFEFA8400659F0F /* Load_far.cpp */, 830995B527787BEE00857684 /* Load_fmt.cpp */, 83E5FD171FFEFA8400659F0F /* Load_gdm.cpp */, + 83649B9E2A03416B00CD0580 /* Load_gt2.cpp */, 83E5FD8A1FFEFA8400659F0F /* Load_imf.cpp */, 83E5FDA41FFEFA8400659F0F /* Load_it.cpp */, 83E5FD7F1FFEFA8400659F0F /* Load_itp.cpp */, @@ -1605,6 +1771,7 @@ 83E5FDA91FFEFA8400659F0F /* Load_ult.cpp */, 83E5FDA21FFEFA8400659F0F /* Load_wav.cpp */, 83E5FD921FFEFA8400659F0F /* Load_xm.cpp */, + 83649B9F2A03416B00CD0580 /* Load_xmf.cpp */, 83E5FDAF1FFEFA8400659F0F /* Loaders.h */, 83E5FD2F1FFEFA8400659F0F /* Message.cpp */, 83E5FD671FFEFA8400659F0F /* Message.h */, @@ -1850,6 +2017,7 @@ 83E5FE2C1FFEFA8500659F0F /* Sndfile.h in Headers */, 8309970527787E9A00857684 /* version.hpp in Headers */, 83E5FE191FFEFA8500659F0F /* MixFuncTable.h in Headers */, + 83649BE12A0342AB00CD0580 /* os_path_long.hpp in Headers */, 83E5FE531FFEFA8500659F0F /* OggStream.h in Headers */, 8309972127787E9A00857684 /* SampleClip.hpp in Headers */, 83E5FC8D1FFEFA0D00659F0F /* mptStringParse.h in Headers */, @@ -1867,6 +2035,7 @@ 83E5FE371FFEFA8500659F0F /* Dlsbank.h in Headers */, 83E5FCD51FFEFA1A00659F0F /* libopenmpt_ext_impl.hpp in Headers */, 83E5FDDC1FFEFA8500659F0F /* PluginMixBuffer.h in Headers */, + 83649BCA2A03424E00CD0580 /* outputfile.hpp in Headers */, 83E5FDF71FFEFA8500659F0F /* Chorus.h in Headers */, 83E5FE0A1FFEFA8500659F0F /* UMXTools.h in Headers */, 83E5FDF31FFEFA8500659F0F /* Gargle.h in Headers */, @@ -1884,6 +2053,7 @@ 83E5FC681FFEFA0D00659F0F /* stdafx.h in Headers */, 830996F427787E9A00857684 /* bit.hpp in Headers */, 83E5FDD21FFEFA8500659F0F /* MPEGFrame.h in Headers */, + 83649BD72A03429300CD0580 /* dos_memory.hpp in Headers */, 83E5FDCA1FFEFA8500659F0F /* ITCompression.h in Headers */, 8309970D27787E9A00857684 /* constexpr_throw.hpp in Headers */, 8309969627787E9A00857684 /* class.hpp in Headers */, @@ -1894,9 +2064,11 @@ 83E5FC661FFEFA0D00659F0F /* version.h in Headers */, 830996E627787E9A00857684 /* windows.hpp in Headers */, 83E5FC831FFEFA0D00659F0F /* serialization_utils.h in Headers */, + 83649BCB2A03424E00CD0580 /* inputfile.hpp in Headers */, 830996FD27787E9A00857684 /* tests_base_bit.hpp in Headers */, 83E5FE1A1FFEFA8500659F0F /* pattern.h in Headers */, 83F30ABF286EBBEA0005EF06 /* init_layer12.h in Headers */, + 83649BC92A03424E00CD0580 /* unique_basename.hpp in Headers */, 830996E927787E9A00857684 /* wrapping_divide.hpp in Headers */, 831132E021F955B2001F678F /* mptAssert.h in Headers */, 83E5FE211FFEFA8500659F0F /* Tagging.h in Headers */, @@ -1904,12 +2076,14 @@ 83E5FE101FFEFA8500659F0F /* modcommand.h in Headers */, 83E5FE331FFEFA8500659F0F /* ModInstrument.h in Headers */, 83E5FC781FFEFA0D00659F0F /* FileReaderFwd.h in Headers */, + 83649BCD2A03424E00CD0580 /* fstream.hpp in Headers */, 83E5FDF41FFEFA8500659F0F /* DMOPlugin.h in Headers */, 83F30ABB286EBBEA0005EF06 /* getbits.h in Headers */, 830996EA27787E9A00857684 /* integer.hpp in Headers */, 83E5FE2B1FFEFA8500659F0F /* WindowedFIR.h in Headers */, 830996D127787E9A00857684 /* base64url.hpp in Headers */, 830996EC27787E9A00857684 /* detect_libc.hpp in Headers */, + 83649BA82A03418600CD0580 /* feature_flags.hpp in Headers */, 8309971227787E9A00857684 /* ModPlug.hpp in Headers */, 830996F127787E9A00857684 /* array.hpp in Headers */, 83E5FE001FFEFA8500659F0F /* SampleIO.h in Headers */, @@ -1928,6 +2102,7 @@ 83F30AB6286EBBEA0005EF06 /* reader.h in Headers */, 830996EE27787E9A00857684 /* span.hpp in Headers */, 830996F627787E9A00857684 /* check_platform.hpp in Headers */, + 83649BE02A0342AB00CD0580 /* basic_path.hpp in Headers */, 8309972027787E9A00857684 /* SampleClipFixedPoint.hpp in Headers */, 830996DC27787E9A00857684 /* tests_random.hpp in Headers */, 830996C627787E9A00857684 /* tests_format_simple.hpp in Headers */, @@ -1946,6 +2121,8 @@ 83F30AD2286EBBEA0005EF06 /* mpeghead.h in Headers */, 83E5FDD41FFEFA8500659F0F /* WAVTools.h in Headers */, 830996DF27787E9A00857684 /* device.hpp in Headers */, + 83649BC82A03424E00CD0580 /* unique_tempfilename.hpp in Headers */, + 83649B972A0340FF00CD0580 /* mptFileTemporary.h in Headers */, 830996CD27787E9A00857684 /* message.hpp in Headers */, 83F30AC1286EBBEA0005EF06 /* parse.h in Headers */, 830996B027787E9A00857684 /* tests_parse.hpp in Headers */, @@ -1970,18 +2147,25 @@ 830996A627787E9A00857684 /* callbackstream.hpp in Headers */, 831132E821F9565F001F678F /* BitReader.h in Headers */, 83E5FC741FFEFA0D00659F0F /* BuildSettings.h in Headers */, + 83649B9D2A03414400CD0580 /* libopenmpt_stream_callbacks_file_posix_lfs64.h in Headers */, 8309970B27787E9A00857684 /* memory.hpp in Headers */, 83E5FDC01FFEFA8500659F0F /* SoundFilePlayConfig.h in Headers */, + 83649BAC2A03419D00CD0580 /* detect_arch.hpp in Headers */, 8309970827787E9A00857684 /* compiletime_warning.hpp in Headers */, + 83649BBB2A03420100CD0580 /* exception.hpp in Headers */, 830996C027787E9A00857684 /* join.hpp in Headers */, 8309969227787E9A00857684 /* int24.hpp in Headers */, 83E5FCCF1FFEFA1A00659F0F /* libopenmpt_plugin_settings.hpp in Headers */, 830996C127787E9A00857684 /* default_formatter.hpp in Headers */, + 83649BAA2A03418600CD0580 /* x86_amd64.hpp in Headers */, 8309968F27787E9A00857684 /* ltdl.hpp in Headers */, 830996E027787E9A00857684 /* crand.hpp in Headers */, 830996B927787E9A00857684 /* io_virtual_wrapper.hpp in Headers */, + 83649BB02A0341CF00CD0580 /* tests_endian_int24.hpp in Headers */, + 83649BE22A0342AB00CD0580 /* os_path.hpp in Headers */, 8309970F27787E9A00857684 /* detect_os.hpp in Headers */, 830996A127787E9A00857684 /* filereader.hpp in Headers */, + 83649BCC2A03424E00CD0580 /* fileref.hpp in Headers */, 8309971327787E9A00857684 /* SampleFormat.hpp in Headers */, 8309969027787E9A00857684 /* dl.hpp in Headers */, 83E5FE4B1FFEFA8500659F0F /* tuning.h in Headers */, @@ -1989,6 +2173,7 @@ 830996F727787E9A00857684 /* saturate_cast.hpp in Headers */, 830996D227787E9A00857684 /* hex.hpp in Headers */, 83F30AB2286EBBEA0005EF06 /* l12tabs.h in Headers */, + 83649BA92A03418600CD0580 /* arch.hpp in Headers */, 8309972627787E9A00857684 /* Types.hpp in Headers */, 83F30ACB286EBBEA0005EF06 /* gapless.h in Headers */, 83E5FDFA1FFEFA8500659F0F /* Flanger.h in Headers */, @@ -2017,9 +2202,13 @@ 830996F027787E9A00857684 /* secure.hpp in Headers */, 83F30AB9286EBBEA0005EF06 /* dither.h in Headers */, 8309969327787E9A00857684 /* floatingpoint.hpp in Headers */, + 83649BD12A03427500CD0580 /* inputfile_filecursor.hpp in Headers */, 830996A427787E9A00857684 /* filedata.hpp in Headers */, + 83649BB92A03420100CD0580 /* exception_text.hpp in Headers */, 830996B727787E9A00857684 /* io.hpp in Headers */, + 83649BDE2A0342AB00CD0580 /* native_path.hpp in Headers */, 83E5FC791FFEFA0D00659F0F /* Logging.h in Headers */, + 83649BBA2A03420100CD0580 /* runtime_error.hpp in Headers */, 83F30ACD286EBBEA0005EF06 /* l2tables.h in Headers */, 83F30ADD286EBC080005EF06 /* vorbisfile.h in Headers */, 83F30AC9286EBBEA0005EF06 /* newhuffman.h in Headers */, @@ -2027,6 +2216,7 @@ 830995C627787C1C00857684 /* DMOUtils.h in Headers */, 83E5FDE01FFEFA8500659F0F /* DigiBoosterEcho.h in Headers */, 83E5FD0A1FFEFA7D00659F0F /* EQ.h in Headers */, + 83649BD62A03429300CD0580 /* windows_wine_version.hpp in Headers */, 83E5FD0D1FFEFA7D00659F0F /* AGC.h in Headers */, 8309969D27787E9A00857684 /* filecursor_filename_traits.hpp in Headers */, 830996DB27787E9A00857684 /* default_engines.hpp in Headers */, @@ -2042,7 +2232,9 @@ 83F30AC8286EBBEA0005EF06 /* fmt123.h in Headers */, 8309971A27787E9A00857684 /* MixSampleConvert.hpp in Headers */, 83E5FE261FFEFA8500659F0F /* AudioCriticalSection.h in Headers */, + 83649BBD2A03422400CD0580 /* concat.hpp in Headers */, 8309969C27787E9A00857684 /* filecursor.hpp in Headers */, + 83649BCE2A03424E00CD0580 /* fileadapter.hpp in Headers */, 83F30AB7286EBBEA0005EF06 /* debug.h in Headers */, 83F30AC7286EBBEA0005EF06 /* icy.h in Headers */, 83AA7D352519B694004C5298 /* TinyFFT.h in Headers */, @@ -2060,13 +2252,16 @@ 830996A727787E9A00857684 /* filedata_callbackstream.hpp in Headers */, 830996F927787E9A00857684 /* floatingpoint.hpp in Headers */, 830996DA27787E9A00857684 /* engine.hpp in Headers */, + 83649B992A0340FF00CD0580 /* mptCPU.h in Headers */, 8309970127787E9A00857684 /* numbers.hpp in Headers */, 83E5FE501FFEFA8500659F0F /* MIDIMacros.h in Headers */, 83E5FC911FFEFA0D00659F0F /* FileReader.h in Headers */, + 83649BAE2A0341B300CD0580 /* compiler.hpp in Headers */, 83F30ADE286EBC080005EF06 /* codec.h in Headers */, 83E5FE291FFEFA8500659F0F /* tuningbase.h in Headers */, 83E5FDEB1FFEFA8500659F0F /* Echo.h in Headers */, 8309969B27787E9A00857684 /* filecursor_traits_memory.hpp in Headers */, + 83649BB22A0341DC00CD0580 /* type_traits.hpp in Headers */, 830996C927787E9A00857684 /* simple.hpp in Headers */, 83E5FC691FFEFA0D00659F0F /* ComponentManager.h in Headers */, 83E5FCED1FFEFA1A00659F0F /* libopenmpt_ext.hpp in Headers */, @@ -2110,12 +2305,15 @@ 83F30ABC286EBBEA0005EF06 /* synth.h in Headers */, 830996FA27787E9A00857684 /* tests_base_math.hpp in Headers */, 83F30AC2286EBBEA0005EF06 /* synth_sse3d.h in Headers */, + 83649BB82A03420100CD0580 /* logic_error.hpp in Headers */, 830996A527787E9A00857684 /* filecursor_callbackstream.hpp in Headers */, 83E5FDF01FFEFA8500659F0F /* WavesReverb.h in Headers */, 8309971D27787E9A00857684 /* Copy.hpp in Headers */, 8309969727787E9A00857684 /* windows_version.hpp in Headers */, + 83649BDF2A0342AB00CD0580 /* path.hpp in Headers */, 830996AF27787E9A00857684 /* test.hpp in Headers */, 83E5FDED1FFEFA8500659F0F /* I3DL2Reverb.h in Headers */, + 83649BD52A03429300CD0580 /* dos_version.hpp in Headers */, 830996CE27787E9A00857684 /* environment.hpp in Headers */, 830996E427787E9A00857684 /* tests_uuid.hpp in Headers */, 8309972327787E9A00857684 /* Int24.hpp in Headers */, @@ -2140,6 +2338,7 @@ 8309970A27787E9A00857684 /* numeric.hpp in Headers */, 830996FB27787E9A00857684 /* tests_base_wrapping_divide.hpp in Headers */, 830995B227787BB800857684 /* Dither.h in Headers */, + 83649B9A2A0340FF00CD0580 /* mptFileType.h in Headers */, 830996BB27787E9A00857684 /* system_error.hpp in Headers */, 8309971927787E9A00857684 /* DitherSimple.hpp in Headers */, 83F30ACF286EBBEA0005EF06 /* icy2utf8.h in Headers */, @@ -2222,6 +2421,7 @@ 83E5FE061FFEFA8500659F0F /* Sndfile.cpp in Sources */, 83E5FE2E1FFEFA8500659F0F /* ContainerPP20.cpp in Sources */, 830995C527787C1C00857684 /* DMOUtils.cpp in Sources */, + 83649BA22A03416B00CD0580 /* Load_xmf.cpp in Sources */, 83E5FE511FFEFA8500659F0F /* MixFuncTable.cpp in Sources */, 83E5FE4C1FFEFA8500659F0F /* UMXTools.cpp in Sources */, 83E5FE381FFEFA8500659F0F /* Load_xm.cpp in Sources */, @@ -2230,6 +2430,7 @@ 83E5FE471FFEFA8500659F0F /* SampleFormats.cpp in Sources */, 83E5FDD71FFEFA8500659F0F /* Message.cpp in Sources */, 83E5FDBC1FFEFA8500659F0F /* MixerLoops.cpp in Sources */, + 83649BA32A03416B00CD0580 /* Load_667.cpp in Sources */, 830995BB27787BEE00857684 /* Load_fmt.cpp in Sources */, 83E5FDE11FFEFA8500659F0F /* PlugInterface.cpp in Sources */, 830995BE27787BEE00857684 /* Load_dsym.cpp in Sources */, @@ -2274,6 +2475,7 @@ 83E5FE0E1FFEFA8500659F0F /* OggStream.cpp in Sources */, 83E5FE451FFEFA8500659F0F /* Load_mdl.cpp in Sources */, 831132EC21F9565F001F678F /* OPL.cpp in Sources */, + 83649B982A0340FF00CD0580 /* mptFileTemporary.cpp in Sources */, 83E5FDBB1FFEFA8500659F0F /* Load_stm.cpp in Sources */, 83E5FE1D1FFEFA8500659F0F /* ModInstrument.cpp in Sources */, 83E5FE461FFEFA8500659F0F /* WindowedFIR.cpp in Sources */, @@ -2284,6 +2486,7 @@ 83AA7D332519B694004C5298 /* SampleFormatSFZ.cpp in Sources */, 831132D821F955B2001F678F /* mptStringBuffer.cpp in Sources */, 83E5FDD61FFEFA8500659F0F /* modcommand.cpp in Sources */, + 83649BA12A03416B00CD0580 /* Load_gt2.cpp in Sources */, 83E5FD091FFEFA7D00659F0F /* DSP.cpp in Sources */, 83E5FE081FFEFA8500659F0F /* Load_amf.cpp in Sources */, 83E5FD081FFEFA7D00659F0F /* EQ.cpp in Sources */, @@ -2337,6 +2540,7 @@ 83E5FE521FFEFA8500659F0F /* SampleFormatOpus.cpp in Sources */, 83E5FC7F1FFEFA0D00659F0F /* serialization_utils.cpp in Sources */, 83E5FDEA1FFEFA8500659F0F /* ParamEq.cpp in Sources */, + 83649B9B2A0340FF00CD0580 /* mptFileType.cpp in Sources */, 830995BC27787BEE00857684 /* Load_symmod.cpp in Sources */, 83E5FE071FFEFA8500659F0F /* ContainerMMCMP.cpp in Sources */, 83E5FDEC1FFEFA8500659F0F /* Gargle.cpp in Sources */, diff --git a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj index e469f18db..9c5e611a7 100644 --- a/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/libvgmstream.xcodeproj/project.pbxproj @@ -3416,14 +3416,20 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/vgmstream/ext_libs", + ../../ThirdParty/vorbis/include, + ../../ThirdParty/ogg/include, + ../../ThirdParty/speex/include, + ../../ThirdParty/mpg123/include, ../../ThirdParty/ffmpeg/include, + vgmstream/ext_includes, ); INSTALL_PATH = "@loader_path/../Frameworks"; LIBRARY_SEARCH_PATHS = ( ../../ThirdParty/ffmpeg/lib, ../../ThirdParty/speex, "../../ThirdParty/fdk-aac/lib", + ../../ThirdParty/vorbis/lib, + ../../ThirdParty/mpg123/lib, ); MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; @@ -3495,14 +3501,20 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/vgmstream/ext_libs", + ../../ThirdParty/vorbis/include, + ../../ThirdParty/ogg/include, + ../../ThirdParty/speex/include, + ../../ThirdParty/mpg123/include, ../../ThirdParty/ffmpeg/include, + vgmstream/ext_includes, ); INSTALL_PATH = "@loader_path/../Frameworks"; LIBRARY_SEARCH_PATHS = ( ../../ThirdParty/ffmpeg/lib, ../../ThirdParty/speex, "../../ThirdParty/fdk-aac/lib", + ../../ThirdParty/vorbis/lib, + ../../ThirdParty/mpg123/lib, ); MACOSX_DEPLOYMENT_TARGET = 10.13; OTHER_CFLAGS = "-Wframe-larger-than=4000"; @@ -3524,22 +3536,7 @@ ../mpg123, ); FRAMEWORK_VERSION = A; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../../ThirdParty/vorbis/include, - ../../ThirdParty/ogg/include, - ../../ThirdParty/speex/include, - ../../ThirdParty/mpg123/include, - ); INFOPLIST_FILE = "vgmstream/libvgmstream-Info.plist"; - LIBRARY_SEARCH_PATHS = ( - ../../ThirdParty/ffmpeg/lib, - ../../ThirdParty/speex, - "../../ThirdParty/fdk-aac/lib", - ../../ThirdParty/vorbis/lib, - ../../ThirdParty/mpg123/lib, - ); PRODUCT_BUNDLE_IDENTIFIER = "NoWork-Inc.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; @@ -3559,22 +3556,7 @@ ../mpg123, ); FRAMEWORK_VERSION = A; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../../ThirdParty/vorbis/include, - ../../ThirdParty/ogg/include, - ../../ThirdParty/speex/include, - ../../ThirdParty/mpg123/include, - ); INFOPLIST_FILE = "vgmstream/libvgmstream-Info.plist"; - LIBRARY_SEARCH_PATHS = ( - ../../ThirdParty/ffmpeg/lib, - ../../ThirdParty/speex, - "../../ThirdParty/fdk-aac/lib", - ../../ThirdParty/vorbis/lib, - ../../ThirdParty/mpg123/lib, - ); PRODUCT_BUNDLE_IDENTIFIER = "NoWork-Inc.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; diff --git a/Info.plist.template b/Info.plist.template index fdb760618..8d5e0b8c0 100644 --- a/Info.plist.template +++ b/Info.plist.template @@ -1498,6 +1498,7 @@ s3m xm it + 667 669 amf ams @@ -1534,8 +1535,11 @@ stx stp symmod + gtk + gt2 ult wow + xmf gdm mo3 oxm