This commit is contained in:
louist103 2025-04-26 23:24:06 +00:00 committed by GitHub
commit 21947b34bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 12242 additions and 563 deletions

View file

@ -1 +1 @@
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build
libusb-dev libusb-1.0-0-dev libsdl2-dev libsdl2-net-dev libpng-dev libglew-dev nlohmann-json3-dev libtinyxml2-dev libspdlog-dev ninja-build libogg-dev libopus-dev opus-tools libopusfile-dev libvorbis-dev

View file

@ -62,16 +62,16 @@ jobs:
cmake ..
make
sudo make install
- name: Generate soh.otr
- name: Generate soh.o2r
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build-cmake --config Release --target GenerateSohOtr -j3
- name: Upload soh.otr
- name: Upload soh.o2r
uses: actions/upload-artifact@v4
with:
name: soh.otr
path: soh.otr
name: soh.o2r
path: soh.o2r
retention-days: 3
build-macos:
@ -122,10 +122,10 @@ jobs:
brew uninstall --ignore-dependencies libpng
sudo port install $(cat .github/workflows/macports-deps.txt)
brew install ninja
- name: Download soh.otr
- name: Download soh.o2r
uses: actions/download-artifact@v4
with:
name: soh.otr
name: soh.o2r
path: build-cmake/soh
- name: Build SoH
run: |
@ -233,10 +233,10 @@ jobs:
make
sudo make install
sudo cp -av /usr/local/lib/libzip* /lib/x86_64-linux-gnu/
- name: Download soh.otr
- name: Download soh.o2r
uses: actions/download-artifact@v4
with:
name: soh.otr
name: soh.o2r
path: build-cmake/soh
- name: Build SoH
run: |
@ -298,10 +298,10 @@ jobs:
path: vcpkg
- name: Configure Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Download soh.otr
- name: Download soh.o2r
uses: actions/download-artifact@v4
with:
name: soh.otr
name: soh.o2r
path: build-windows/soh
- name: Build SoH
env:

View file

@ -1 +1 @@
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal libzip +universal nlohmann-json +universal tinyxml2 +universal
libsdl2 +universal libsdl2_net +universal libpng +universal glew +universal libzip +universal nlohmann-json +universal tinyxml2 +universal libogg +universal libopus +universal opusfile +universal libvorbis +universal

View file

@ -48,7 +48,7 @@ jobs:
});
return allArtifacts.data.artifacts.reduce((acc, item) => {
if (item.name === "soh.otr") return acc;
if (item.name === "soh.o2r") return acc;
acc += `
- [${item.name}.zip](https://nightly.link/${context.repo.owner}/${context.repo.repo}/actions/artifacts/${item.id}.zip)`;
return acc;

1
.gitignore vendored
View file

@ -412,6 +412,7 @@ ReleaseObj/*
.tags
tags
*.otr
*.o2r
*.sav
shipofharkinian.ini
shipofharkinian.json

61
CMake/FindOgg.cmake Normal file
View file

@ -0,0 +1,61 @@
# - Find ogg
# Find the native ogg includes and libraries
#
# OGG_INCLUDE_DIRS - where to find ogg.h, etc.
# OGG_LIBRARIES - List of libraries when using ogg.
# OGG_FOUND - True if ogg found.
if (OGG_INCLUDE_DIR)
# Already in cache, be silent
set(OGG_FIND_QUIETLY TRUE)
endif ()
find_package (PkgConfig QUIET)
pkg_check_modules (PC_OGG QUIET ogg>=1.3.0)
set (OGG_VERSION ${PC_OGG_VERSION})
find_path (OGG_INCLUDE_DIR ogg/ogg.h
HINTS
${PC_OGG_INCLUDEDIR}
${PC_OGG_INCLUDE_DIRS}
${OGG_ROOT}
)
# MSVC built ogg may be named ogg_static.
# The provided project files name the library with the lib prefix.
find_library (OGG_LIBRARY
NAMES
ogg
ogg_static
libogg
libogg_static
HINTS
${PC_OGG_LIBDIR}
${PC_OGG_LIBRARY_DIRS}
${OGG_ROOT}
)
# Handle the QUIETLY and REQUIRED arguments and set OGG_FOUND
# to TRUE if all listed variables are TRUE.
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (Ogg
REQUIRED_VARS
OGG_LIBRARY
OGG_INCLUDE_DIR
VERSION_VAR
OGG_VERSION
)
if (OGG_FOUND)
set (OGG_LIBRARIES ${OGG_LIBRARY})
set (OGG_INCLUDE_DIRS ${OGG_INCLUDE_DIR})
if(NOT TARGET Ogg::ogg)
add_library(Ogg::ogg UNKNOWN IMPORTED)
set_target_properties(Ogg::ogg PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OGG_INCLUDE_DIRS}"
IMPORTED_LOCATION "${OGG_LIBRARIES}"
)
endif ()
endif ()
mark_as_advanced (OGG_INCLUDE_DIR OGG_LIBRARY)

44
CMake/FindOpus.cmake Normal file
View file

@ -0,0 +1,44 @@
# - FindOpus.cmake
# Find the native opus includes and libraries
#
# OPUS_INCLUDE_DIRS - where to find opus/opus.h, etc.
# OPUS_LIBRARIES - List of libraries when using libopus(file).
# OPUS_FOUND - True if libopus found.
if(OPUS_INCLUDE_DIR AND OPUS_LIBRARY AND OPUSFILE_LIBRARY)
# Already in cache, be silent
set(OPUS_FIND_QUIETLY TRUE)
endif(OPUS_INCLUDE_DIR AND OPUS_LIBRARY AND OPUSFILE_LIBRARY)
find_path(OPUS_INCLUDE_DIR
NAMES opusfile.h
PATH_SUFFIXES opus
)
# MSVC built opus may be named opus_static
# The provided project files name the library with the lib prefix.
find_library(OPUS_LIBRARY
NAMES opus opus_static libopus libopus_static
)
#find_library(OPUSFILE_LIBRARY
# NAMES opusfile opusfile_static libopusfile libopusfile_static
#)
# Handle the QUIETLY and REQUIRED arguments and set OPUS_FOUND
# to TRUE if all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Opus DEFAULT_MSG
OPUS_LIBRARY OPUS_INCLUDE_DIR
)
if(OPUS_FOUND)
set(OPUS_LIBRARIES ${OPUS_LIBRARY})
set(OPUS_INCLUDE_DIRS ${OPUS_INCLUDE_DIR})
if(NOT TARGET Opus::opus)
add_library(Opus::opus UNKNOWN IMPORTED)
set_target_properties(Opus::opus PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OPUS_INCLUDE_DIRS}"
IMPORTED_LOCATION "${OPUS_LIBRARIES}"
)
endif()
endif(OPUS_FOUND)

55
CMake/FindOpusFile.cmake Normal file
View file

@ -0,0 +1,55 @@
# FindOpusFile.cmake
# Locate the libopusfile library and its dependencies (libopus and libogg).
# Defines the following variables on success:
# OPUSFILE_FOUND - Indicates if opusfile was found
# OPUSFILE_INCLUDE_DIR - Directory containing opusfile.h
# OPUSFILE_LIBRARY - Path to the opusfile library
# OPUSFILE_LIBRARIES - Full list of libraries to link (opusfile, opus, ogg)
# Search for the OpusFile header
find_path(OPUSFILE_INCLUDE_DIR
NAMES opusfile.h
PATHS /usr/include/opus /usr/local/include/opus /opt/local/include/opus /opt/homebrew/include/opus
DOC "Directory where opusfile.h is located"
)
# Search for the OpusFile library
find_library(OPUSFILE_LIBRARY
NAMES opusfile
DOC "Path to the libopusfile library"
)
# Search for the Opus library (dependency of OpusFile)
find_library(OPUS_LIBRARY
NAMES opus
DOC "Path to the libopus library (dependency of libopusfile)"
)
# Search for the Ogg library (dependency of OpusFile)
find_library(OGG_LIBRARY
NAMES ogg
DOC "Path to the libogg library (dependency of libopusfile)"
)
# Check if all required components are found
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OpusFile
REQUIRED_VARS OPUSFILE_LIBRARY OPUSFILE_INCLUDE_DIR OPUS_LIBRARY OGG_LIBRARY
VERSION_VAR OPUSFILE_VERSION
)
# Define an imported target if everything is found
if (OPUSFILE_FOUND)
add_library(Opusfile::Opusfile INTERFACE IMPORTED)
set_target_properties(Opusfile::Opusfile PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OPUSFILE_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${OPUSFILE_LIBRARY};${OPUS_LIBRARY};${OGG_LIBRARY}"
)
# Optionally expose the include and libraries separately
set(OPUSFILE_LIBRARIES ${OPUSFILE_LIBRARY} ${OPUS_LIBRARY} ${OGG_LIBRARY})
set(OPUSFILE_INCLUDE_DIRS ${OPUSFILE_INCLUDE_DIR})
else()
set(OPUSFILE_FOUND FALSE)
endif()

210
CMake/FindVorbis.cmake Normal file
View file

@ -0,0 +1,210 @@
#[=======================================================================[.rst:
FindVorbis
----------
Finds the native vorbis, vorbisenc amd vorbisfile includes and libraries.
Imported Targets
^^^^^^^^^^^^^^^^
This module provides the following imported targets, if found:
``Vorbis::vorbis``
The Vorbis library
``Vorbis::vorbisenc``
The VorbisEnc library
``Vorbis::vorbisfile``
The VorbisFile library
Result Variables
^^^^^^^^^^^^^^^^
This will define the following variables:
``Vorbis_Vorbis_INCLUDE_DIRS``
List of include directories when using vorbis.
``Vorbis_Enc_INCLUDE_DIRS``
List of include directories when using vorbisenc.
``Vorbis_File_INCLUDE_DIRS``
List of include directories when using vorbisfile.
``Vorbis_Vorbis_LIBRARIES``
List of libraries when using vorbis.
``Vorbis_Enc_LIBRARIES``
List of libraries when using vorbisenc.
``Vorbis_File_LIBRARIES``
List of libraries when using vorbisfile.
``Vorbis_FOUND``
True if vorbis and requested components found.
``Vorbis_Vorbis_FOUND``
True if vorbis found.
``Vorbis_Enc_FOUND``
True if vorbisenc found.
``Vorbis_Enc_FOUND``
True if vorbisfile found.
Cache variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``Vorbis_Vorbis_INCLUDE_DIR``
The directory containing ``vorbis/vorbis.h``.
``Vorbis_Enc_INCLUDE_DIR``
The directory containing ``vorbis/vorbisenc.h``.
``Vorbis_File_INCLUDE_DIR``
The directory containing ``vorbis/vorbisenc.h``.
``Vorbis_Vorbis_LIBRARY``
The path to the vorbis library.
``Vorbis_Enc_LIBRARY``
The path to the vorbisenc library.
``Vorbis_File_LIBRARY``
The path to the vorbisfile library.
Hints
^^^^^
A user may set ``Vorbis_ROOT`` to a vorbis installation root to tell this module where to look.
#]=======================================================================]
if (Vorbis_Vorbis_INCLUDE_DIR)
# Already in cache, be silent
set (Vorbis_FIND_QUIETLY TRUE)
endif ()
set (Vorbis_Vorbis_FIND_QUIETLY TRUE)
set (Vorbis_Enc_FIND_QUIETLY TRUE)
set (Vorbis_File_FIND_QUIETLY TRUE)
find_package (Ogg QUIET)
find_package (PkgConfig QUIET)
pkg_check_modules (PC_Vorbis_Vorbis QUIET vorbis)
pkg_check_modules (PC_Vorbis_Enc QUIET vorbisenc)
pkg_check_modules (PC_Vorbis_File QUIET vorbisfile)
set (Vorbis_VERSION ${PC_Vorbis_Vorbis_VERSION})
find_path (Vorbis_Vorbis_INCLUDE_DIR vorbis/codec.h
HINTS
${PC_Vorbis_Vorbis_INCLUDEDIR}
${PC_Vorbis_Vorbis_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_path (Vorbis_Enc_INCLUDE_DIR vorbis/vorbisenc.h
HINTS
${PC_Vorbis_Enc_INCLUDEDIR}
${PC_Vorbis_Enc_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_path (Vorbis_File_INCLUDE_DIR vorbis/vorbisfile.h
HINTS
${PC_Vorbis_File_INCLUDEDIR}
${PC_Vorbis_File_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_Vorbis_LIBRARY
NAMES
vorbis
vorbis_static
libvorbis
libvorbis_static
HINTS
${PC_Vorbis_Vorbis_LIBDIR}
${PC_Vorbis_Vorbis_LIBRARY_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_Enc_LIBRARY
NAMES
vorbisenc
vorbisenc_static
libvorbisenc
libvorbisenc_static
HINTS
${PC_Vorbis_Enc_LIBDIR}
${PC_Vorbis_Enc_LIBRARY_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_File_LIBRARY
NAMES
vorbisfile
vorbisfile_static
libvorbisfile
libvorbisfile_static
HINTS
${PC_Vorbis_File_LIBDIR}
${PC_Vorbis_File_LIBRARY_DIRS}
${Vorbis_ROOT}
)
include (FindPackageHandleStandardArgs)
if (Vorbis_Vorbis_LIBRARY AND Vorbis_Vorbis_INCLUDE_DIR AND Ogg_FOUND)
set (Vorbis_Vorbis_FOUND TRUE)
endif ()
if (Vorbis_Enc_LIBRARY AND Vorbis_Enc_INCLUDE_DIR AND Vorbis_Vorbis_FOUND)
set (Vorbis_Enc_FOUND TRUE)
endif ()
if (Vorbis_Vorbis_FOUND AND Vorbis_File_LIBRARY AND Vorbis_File_INCLUDE_DIR)
set (Vorbis_File_FOUND TRUE)
endif ()
find_package_handle_standard_args (Vorbis
REQUIRED_VARS
Vorbis_Vorbis_LIBRARY
Vorbis_Vorbis_INCLUDE_DIR
Ogg_FOUND
HANDLE_COMPONENTS
VERSION_VAR Vorbis_VERSION)
if (Vorbis_Vorbis_FOUND)
set (Vorbis_Vorbis_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR})
set (Vorbis_Vorbis_LIBRARIES ${VORBIS_LIBRARY} ${OGG_LIBRARIES})
if (NOT TARGET Vorbis::vorbis)
add_library (Vorbis::vorbis UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbis PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Vorbis_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_Vorbis_LIBRARY}"
INTERFACE_LINK_LIBRARIES Ogg::ogg
)
endif ()
if (Vorbis_Enc_FOUND)
set (Vorbis_Enc_INCLUDE_DIRS ${Vorbis_Enc_INCLUDE_DIR})
set (Vorbis_Enc_LIBRARIES ${Vorbis_Enc_LIBRARY} ${Vorbis_Enc_LIBRARIES})
if (NOT TARGET Vorbis::vorbisenc)
add_library (Vorbis::vorbisenc UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbisenc PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Enc_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_Enc_LIBRARY}"
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
)
endif ()
endif ()
if (Vorbis_File_FOUND)
set (Vorbis_File_INCLUDE_DIRS ${Vorbis_File_INCLUDE_DIR})
set (Vorbis_File_LIBRARIES ${Vorbis_File_LIBRARY} ${Vorbis_File_LIBRARIES})
if (NOT TARGET Vorbis::vorbisfile)
add_library (Vorbis::vorbisfile UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbisfile PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_File_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_File_LIBRARY}"
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
)
endif ()
endif ()
endif ()
mark_as_advanced (Vorbis_Vorbis_INCLUDE_DIR Vorbis_Vorbis_LIBRARY)
mark_as_advanced (Vorbis_Enc_INCLUDE_DIR Vorbis_Enc_LIBRARY)
mark_as_advanced (Vorbis_File_INCLUDE_DIR Vorbis_File_LIBRARY)

View file

@ -82,8 +82,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(VCPKG_TARGET_TRIPLET x64-windows-static)
vcpkg_bootstrap()
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog)
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile)
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
endif()
@ -153,6 +152,7 @@ set(GFX_DEBUG_DISASSEMBLER ON)
# Tell LUS we're using F3DEX_GBI_2 (in a way that doesn't break libgfxd)
set(GBI_UCODE F3DEX_GBI_2)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
################################################################################
# Set CONTROLLERBUTTONS_T
@ -174,23 +174,15 @@ set_property(TARGET soh PROPERTY APPIMAGE_ICON_FILE "${CMAKE_BINARY_DIR}/sohIcon
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
install(PROGRAMS "${CMAKE_BINARY_DIR}/linux/soh.sh" DESTINATION . COMPONENT appimage)
install(FILES "${CMAKE_BINARY_DIR}/soh/soh.otr" DESTINATION . COMPONENT ship)
install(FILES "${CMAKE_BINARY_DIR}/soh/soh.o2r" DESTINATION . COMPONENT ship)
install(TARGETS ZAPD DESTINATION ./assets/extractor COMPONENT extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT extractor)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets COMPONENT extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/xml COMPONENT extractor)
endif()
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor COMPONENT ship)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls COMPONENT ship)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists COMPONENT ship)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT ship)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT ship)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols COMPONENT ship)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/ COMPONENT ship)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/xml COMPONENT ship)
endif()
find_package(Python3 COMPONENTS Interpreter)
@ -198,42 +190,42 @@ find_package(Python3 COMPONENTS Interpreter)
# Target to generate OTRs
add_custom_target(
ExtractAssets
COMMAND ${CMAKE_COMMAND} -E rm -f oot.otr oot-mq.otr soh.otr
COMMAND ${CMAKE_COMMAND} -E rm -f oot.o2r oot-mq.o2r soh.o2r
# copy LUS default shaders into assets/custom
COMMAND ${CMAKE_COMMAND} -E rm -r -f ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom/shaders/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/libultraship/src/graphic/Fast3D/shaders/ ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom/shaders/
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --non-interactive --xml-root ../soh/assets/xml --custom-otr-file soh.otr "--custom-assets-path" ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom --port-ver "${CMAKE_PROJECT_VERSION}"
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --non-interactive --xml-root assets/xml --custom-otr-file soh.o2r "--custom-assets-path" ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom --port-ver "${CMAKE_PROJECT_VERSION}"
COMMAND ${CMAKE_COMMAND} -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DTARGET_DIR="$<TARGET_FILE_DIR:ZAPD>" -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBINARY_DIR=${CMAKE_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/copy-existing-otrs.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/soh
COMMENT "Running asset extraction..."
DEPENDS ZAPD
BYPRODUCTS oot.otr ${CMAKE_SOURCE_DIR}/oot.otr oot-mq.otr ${CMAKE_SOURCE_DIR}/oot-mq.otr ${CMAKE_SOURCE_DIR}/soh.otr
BYPRODUCTS oot.o2r ${CMAKE_SOURCE_DIR}/oot.o2r oot-mq.o2r ${CMAKE_SOURCE_DIR}/oot-mq.o2r ${CMAKE_SOURCE_DIR}/soh.o2r
)
# Target to generate headers
add_custom_target(
ExtractAssetHeaders
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --non-interactive --xml-root ../soh/assets/xml --gen-headers
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --non-interactive --xml-root assets/xml --gen-headers
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/soh
COMMENT "Generating asset headers..."
DEPENDS ZAPD
)
# Target to generate only soh.otr
# Target to generate only soh.o2r
add_custom_target(
GenerateSohOtr
COMMAND ${CMAKE_COMMAND} -E rm -f soh.otr
COMMAND ${CMAKE_COMMAND} -E rm -f soh.o2r
# copy LUS default shaders into assets/custom
COMMAND ${CMAKE_COMMAND} -E rm -r -f ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom/shaders/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/libultraship/src/graphic/Fast3D/shaders/ ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom/shaders/
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --norom --custom-otr-file soh.otr "--custom-assets-path" ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom --port-ver "${CMAKE_PROJECT_VERSION}"
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --norom --custom-otr-file soh.o2r "--custom-assets-path" ${CMAKE_CURRENT_SOURCE_DIR}/soh/assets/custom --port-ver "${CMAKE_PROJECT_VERSION}"
COMMAND ${CMAKE_COMMAND} -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DTARGET_DIR="$<TARGET_FILE_DIR:ZAPD>" -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBINARY_DIR=${CMAKE_BINARY_DIR} -DONLYSOHOTR=On -P ${CMAKE_CURRENT_SOURCE_DIR}/copy-existing-otrs.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
COMMENT "Generating soh.otr..."
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/soh
COMMENT "Generating soh.o2r..."
DEPENDS ZAPD
)
@ -266,16 +258,12 @@ add_custom_target(CreateOSXIcons
)
add_dependencies(soh CreateOSXIcons)
install(TARGETS ZAPD DESTINATION ${CMAKE_BINARY_DIR}/assets/extractor)
install(TARGETS ZAPD DESTINATION ${CMAKE_BINARY_DIR}/assets)
set(PROGRAM_PERMISSIONS_EXECUTE OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/extractor)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/extractor/xmls)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION ./assets/extractor/filelists)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols)
install(FILES "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt" DESTINATION ./assets/extractor/symbols)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/extractor/" DESTINATION ./assets/)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/soh/assets/xml/" DESTINATION ./assets/xml)
install(DIRECTORY ${CMAKE_BINARY_DIR}/assets
DESTINATION .

@ -1 +1 @@
Subproject commit 41052efcdf8df8e67517cc93da8975fcd4e14af9
Subproject commit 461ab19a36cde807591543397e136cae19aa6e7c

2
ZAPDTR

@ -1 +1 @@
Subproject commit 2aeababbfb81b00d34673406453e8e8e2deaa27b
Subproject commit 684f21a475dcfeee89938ae1f4afc42768a3e7ef

View file

@ -1,37 +1,37 @@
message(STATUS "Copying otr files...")
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/OTRExporter/oot.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${BINARY_DIR}/soh/)
message(STATUS "Copied oot.otr")
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/soh/oot.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.o2r ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.o2r ${BINARY_DIR}/soh/)
message(STATUS "Copied oot.o2r")
endif()
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/OTRExporter/oot-mq.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.otr ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.otr ${BINARY_DIR}/soh/)
message(STATUS "Copied oot-mq.otr")
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/soh/oot-mq.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.o2r ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.o2r ${BINARY_DIR}/soh/)
message(STATUS "Copied oot-mq.o2r")
endif()
if(EXISTS ${SOURCE_DIR}/OTRExporter/soh.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.otr ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.otr ${BINARY_DIR}/soh/)
message(STATUS "Copied soh.otr")
if(EXISTS ${SOURCE_DIR}/soh/soh.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.o2r ${SOURCE_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.o2r ${BINARY_DIR}/soh/)
message(STATUS "Copied soh.o2r")
endif()
# Additionally for Windows, copy the otrs to the target dir, side by side with soh.exe
if(SYSTEM_NAME MATCHES "Windows")
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/OTRExporter/oot.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.otr ${TARGET_DIR})
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/soh/oot.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot.o2r ${TARGET_DIR})
endif()
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/OTRExporter/oot-mq.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.otr ${TARGET_DIR})
if(NOT ONLYSOHOTR AND EXISTS ${SOURCE_DIR}/soh/oot-mq.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy oot-mq.o2r ${TARGET_DIR})
endif()
if(EXISTS ${SOURCE_DIR}/OTRExporter/soh.otr)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.otr ${TARGET_DIR})
if(EXISTS ${SOURCE_DIR}/soh/soh.o2r)
execute_process(COMMAND ${CMAKE_COMMAND} -E copy soh.o2r ${TARGET_DIR})
endif()
endif()
if(NOT ONLYSOHOTR AND (NOT EXISTS ${SOURCE_DIR}/oot.otr AND NOT EXISTS ${SOURCE_DIR}/oot-mq.otr))
if(NOT ONLYSOHOTR AND (NOT EXISTS ${SOURCE_DIR}/oot.o2r AND NOT EXISTS ${SOURCE_DIR}/oot-mq.o2r))
message(FATAL_ERROR "Failed to copy. No OTR files found.")
endif()
if(NOT EXISTS ${SOURCE_DIR}/soh.otr)
if(NOT EXISTS ${SOURCE_DIR}/soh.o2r)
message(FATAL_ERROR "Failed to copy. No soh OTR found.")
endif()

View file

@ -278,6 +278,14 @@ endif()
# Find/download Boost
################################################################################
include(FetchContent)
FetchContent_Declare(
dr_libs
GIT_REPOSITORY https://github.com/mackron/dr_libs.git
GIT_TAG da35f9d6c7374a95353fd1df1d394d44ab66cf01
)
FetchContent_MakeAvailable(dr_libs)
FetchContent_Declare(
Boost
URL https://archives.boost.io/release/1.81.0/source/boost_1_81_0.tar.gz
@ -350,6 +358,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE assets
${SDL2-NET-INCLUDE}
${BOOST-INCLUDE}
${CMAKE_CURRENT_SOURCE_DIR}/assets/
${dr_libs_SOURCE_DIR}
.
)
@ -589,6 +598,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
-Wno-missing-braces
-Wno-int-conversion
-Wno-implicit-int
# -fsanitize=address
$<$<COMPILE_LANGUAGE:C>:
-Werror-implicit-function-declaration
-Wno-incompatible-pointer-types
@ -601,6 +611,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_link_options(${PROJECT_NAME} PRIVATE
-pthread
#-fsanitize=address
-Wl,-export-dynamic
)
endif()
@ -618,11 +629,7 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
COMMENT "Copying asset xmls..."
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_SOURCE_DIR}/soh/assets/extractor $<TARGET_FILE_DIR:soh>/assets/extractor
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_SOURCE_DIR}/soh/assets/xml $<TARGET_FILE_DIR:soh>/assets/extractor/xmls
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists $<TARGET_FILE_DIR:soh>/assets/extractor/filelists
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:soh>/assets/extractor/symbols
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_OoTMqDbg.txt $<TARGET_FILE_DIR:soh>/assets/extractor/symbols
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_OoTMqDbg.txt $<TARGET_FILE_DIR:soh>/assets/extractor/symbols
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_OoTMqDbg.txt $<TARGET_FILE_DIR:soh>/assets/extractor/symbols
COMMAND ${VS_COPY_ASSETS_CMD}
)
endif()
@ -640,6 +647,15 @@ endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
find_package(glfw3 REQUIRED)
find_package(Ogg CONFIG REQUIRED)
link_libraries(Ogg::ogg)
find_package(Vorbis CONFIG REQUIRED)
link_libraries(Vorbis::vorbisfile)
find_package(Opus CONFIG REQUIRED)
link_libraries(Opus::opus)
find_package(OpusFile CONFIG REQUIRED)
link_libraries(OpusFile::opusfile CONFIG REQUIRED)
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
@ -653,6 +669,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
"imm32;"
"version;"
"setupapi"
"Ogg::ogg"
"Opus::opus"
"Vorbis::vorbis"
"Vorbis::vorbisenc"
"Vorbis::vorbisfile"
"OpusFile::opusfile"
)
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
@ -693,10 +715,21 @@ else()
find_package(SDL2)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(Threads REQUIRED)
find_package(Ogg REQUIRED)
find_package(Vorbis REQUIRED)
find_package(Opus REQUIRED)
find_package(OpusFile REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
"ZAPDLib;"
SDL2::SDL2
"Ogg::ogg"
"Vorbis::vorbis"
"Vorbis::vorbisenc"
"Vorbis::vorbisfile"
"Opus::opus"
"Opusfile::Opusfile"
"$<$<BOOL:${BUILD_REMOTE_CONTROL}>:SDL2_net::SDL2_net>"
${CMAKE_DL_LIBS}
Threads::Threads
@ -709,7 +742,7 @@ endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
INSTALL(FILES $<TARGET_PDB_FILE:soh> DESTINATION ./debug COMPONENT ship)
INSTALL(FILES ${CMAKE_BINARY_DIR}/soh/soh.otr DESTINATION . COMPONENT ship)
INSTALL(FILES ${CMAKE_BINARY_DIR}/soh/soh.o2r DESTINATION . COMPONENT ship)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@ -723,7 +756,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/macosx/Info.plist.in ${CMAKE_BINARY_DIR}/macosx/Info.plist @ONLY)
INSTALL(TARGETS soh DESTINATION ../MacOS COMPONENT ship)
INSTALL(FILES ${CMAKE_BINARY_DIR}/gamecontrollerdb.txt DESTINATION ../MacOS COMPONENT ship)
INSTALL(FILES ${CMAKE_BINARY_DIR}/soh/soh.otr DESTINATION ../Resources COMPONENT ship)
INSTALL(FILES ${CMAKE_BINARY_DIR}/soh/soh.o2r DESTINATION ../Resources COMPONENT ship)
elseif(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "NintendoSwitch|CafeOS")
INSTALL(FILES ${CMAKE_BINARY_DIR}/gamecontrollerdb.txt DESTINATION . COMPONENT ship)
endif()

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_MQ_D/"/>
<ExternalXMLFolder Path="assets/xml/GC_MQ_D/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_MQ_NTSC_J/"/>
<ExternalXMLFolder Path="assets/xml/GC_MQ_NTSC_J/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_MQ_NTSC_U/"/>
<ExternalXMLFolder Path="assets/xml/GC_MQ_NTSC_U/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_MQ_PAL_F/"/>
<ExternalXMLFolder Path="assets/xml/GC_MQ_PAL_F/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_D/"/>
<ExternalXMLFolder Path="assets/xml/GC_NMQ_D/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_NTSC_J/"/>
<ExternalXMLFolder Path="assets/xml/GC_NMQ_NTSC_J/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_NTSC_J_CE/"/>
<ExternalXMLFolder Path="assets/xml/GC_NMQ_NTSC_J_CE/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_NTSC_U/"/>
<ExternalXMLFolder Path="assets/xml/GC_NMQ_NTSC_U/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_PAL_F/"/>
<ExternalXMLFolder Path="assets/xml/GC_NMQ_PAL_F/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/N64_NTSC_10/"/>
<ExternalXMLFolder Path="assets/xml/N64_NTSC_10/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/N64_NTSC_11/"/>
<ExternalXMLFolder Path="assets/xml/N64_NTSC_11/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/N64_NTSC_12/"/>
<ExternalXMLFolder Path="assets/xml/N64_NTSC_12/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/N64_PAL_10/"/>
<ExternalXMLFolder Path="assets/xml/N64_PAL_10/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/N64_PAL_11/"/>
<ExternalXMLFolder Path="assets/xml/N64_PAL_11/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,472 @@
ACTOR_PLAYER
ACTOR_UNSET_1
ACTOR_EN_TEST
ACTOR_UNSET_3
ACTOR_EN_GIRLA
ACTOR_UNSET_5
ACTOR_UNSET_6
ACTOR_EN_PART
ACTOR_EN_LIGHT
ACTOR_EN_DOOR
ACTOR_EN_BOX
ACTOR_BG_DY_YOSEIZO
ACTOR_BG_HIDAN_FIREWALL
ACTOR_EN_POH
ACTOR_EN_OKUTA
ACTOR_BG_YDAN_SP
ACTOR_EN_BOM
ACTOR_EN_WALLMAS
ACTOR_EN_DODONGO
ACTOR_EN_FIREFLY
ACTOR_EN_HORSE
ACTOR_EN_ITEM00
ACTOR_EN_ARROW
ACTOR_UNSET_17
ACTOR_EN_ELF
ACTOR_EN_NIW
ACTOR_UNSET_1A
ACTOR_EN_TITE
ACTOR_EN_REEBA
ACTOR_EN_PEEHAT
ACTOR_EN_BUTTE
ACTOR_UNSET_1F
ACTOR_EN_INSECT
ACTOR_EN_FISH
ACTOR_UNSET_22
ACTOR_EN_HOLL
ACTOR_EN_SCENE_CHANGE
ACTOR_EN_ZF
ACTOR_EN_HATA
ACTOR_BOSS_DODONGO
ACTOR_BOSS_GOMA
ACTOR_EN_ZL1
ACTOR_EN_VIEWER
ACTOR_EN_GOMA
ACTOR_BG_PUSHBOX
ACTOR_EN_BUBBLE
ACTOR_DOOR_SHUTTER
ACTOR_EN_DODOJR
ACTOR_EN_BDFIRE
ACTOR_UNSET_31
ACTOR_EN_BOOM
ACTOR_EN_TORCH2
ACTOR_EN_BILI
ACTOR_EN_TP
ACTOR_UNSET_36
ACTOR_EN_ST
ACTOR_EN_BW
ACTOR_EN_A_OBJ
ACTOR_EN_EIYER
ACTOR_EN_RIVER_SOUND
ACTOR_EN_HORSE_NORMAL
ACTOR_EN_OSSAN
ACTOR_BG_TREEMOUTH
ACTOR_BG_DODOAGO
ACTOR_BG_HIDAN_DALM
ACTOR_BG_HIDAN_HROCK
ACTOR_EN_HORSE_GANON
ACTOR_BG_HIDAN_ROCK
ACTOR_BG_HIDAN_RSEKIZOU
ACTOR_BG_HIDAN_SEKIZOU
ACTOR_BG_HIDAN_SIMA
ACTOR_BG_HIDAN_SYOKU
ACTOR_EN_XC
ACTOR_BG_HIDAN_CURTAIN
ACTOR_BG_SPOT00_HANEBASI
ACTOR_EN_MB
ACTOR_EN_BOMBF
ACTOR_EN_ZL2
ACTOR_BG_HIDAN_FSLIFT
ACTOR_EN_OE2
ACTOR_BG_YDAN_HASI
ACTOR_BG_YDAN_MARUTA
ACTOR_BOSS_GANONDROF
ACTOR_UNSET_53
ACTOR_EN_AM
ACTOR_EN_DEKUBABA
ACTOR_EN_M_FIRE1
ACTOR_EN_M_THUNDER
ACTOR_BG_DDAN_JD
ACTOR_BG_BREAKWALL
ACTOR_EN_JJ
ACTOR_EN_HORSE_ZELDA
ACTOR_BG_DDAN_KD
ACTOR_DOOR_WARP1
ACTOR_OBJ_SYOKUDAI
ACTOR_ITEM_B_HEART
ACTOR_EN_DEKUNUTS
ACTOR_BG_MENKURI_KAITEN
ACTOR_BG_MENKURI_EYE
ACTOR_EN_VALI
ACTOR_BG_MIZU_MOVEBG
ACTOR_BG_MIZU_WATER
ACTOR_ARMS_HOOK
ACTOR_EN_FHG
ACTOR_BG_MORI_HINERI
ACTOR_EN_BB
ACTOR_BG_TOKI_HIKARI
ACTOR_EN_YUKABYUN
ACTOR_BG_TOKI_SWD
ACTOR_EN_FHG_FIRE
ACTOR_BG_MJIN
ACTOR_BG_HIDAN_KOUSI
ACTOR_DOOR_TOKI
ACTOR_BG_HIDAN_HAMSTEP
ACTOR_EN_BIRD
ACTOR_UNSET_73
ACTOR_UNSET_74
ACTOR_UNSET_75
ACTOR_UNSET_76
ACTOR_EN_WOOD02
ACTOR_UNSET_78
ACTOR_UNSET_79
ACTOR_UNSET_7A
ACTOR_UNSET_7B
ACTOR_EN_LIGHTBOX
ACTOR_EN_PU_BOX
ACTOR_UNSET_7E
ACTOR_UNSET_7F
ACTOR_EN_TRAP
ACTOR_EN_AROW_TRAP
ACTOR_EN_VASE
ACTOR_UNSET_83
ACTOR_EN_TA
ACTOR_EN_TK
ACTOR_BG_MORI_BIGST
ACTOR_BG_MORI_ELEVATOR
ACTOR_BG_MORI_KAITENKABE
ACTOR_BG_MORI_RAKKATENJO
ACTOR_EN_VM
ACTOR_DEMO_EFFECT
ACTOR_DEMO_KANKYO
ACTOR_BG_HIDAN_FWBIG
ACTOR_EN_FLOORMAS
ACTOR_EN_HEISHI1
ACTOR_EN_RD
ACTOR_EN_PO_SISTERS
ACTOR_BG_HEAVY_BLOCK
ACTOR_BG_PO_EVENT
ACTOR_OBJ_MURE
ACTOR_EN_SW
ACTOR_BOSS_FD
ACTOR_OBJECT_KANKYO
ACTOR_EN_DU
ACTOR_EN_FD
ACTOR_EN_HORSE_LINK_CHILD
ACTOR_DOOR_ANA
ACTOR_BG_SPOT02_OBJECTS
ACTOR_BG_HAKA
ACTOR_MAGIC_WIND
ACTOR_MAGIC_FIRE
ACTOR_UNSET_A0
ACTOR_EN_RU1
ACTOR_BOSS_FD2
ACTOR_EN_FD_FIRE
ACTOR_EN_DH
ACTOR_EN_DHA
ACTOR_EN_RL
ACTOR_EN_ENCOUNT1
ACTOR_DEMO_DU
ACTOR_DEMO_IM
ACTOR_DEMO_TRE_LGT
ACTOR_EN_FW
ACTOR_BG_VB_SIMA
ACTOR_EN_VB_BALL
ACTOR_BG_HAKA_MEGANE
ACTOR_BG_HAKA_MEGANEBG
ACTOR_BG_HAKA_SHIP
ACTOR_BG_HAKA_SGAMI
ACTOR_UNSET_B2
ACTOR_EN_HEISHI2
ACTOR_EN_ENCOUNT2
ACTOR_EN_FIRE_ROCK
ACTOR_EN_BROB
ACTOR_MIR_RAY
ACTOR_BG_SPOT09_OBJ
ACTOR_BG_SPOT18_OBJ
ACTOR_BOSS_VA
ACTOR_BG_HAKA_TUBO
ACTOR_BG_HAKA_TRAP
ACTOR_BG_HAKA_HUTA
ACTOR_BG_HAKA_ZOU
ACTOR_BG_SPOT17_FUNEN
ACTOR_EN_SYATEKI_ITM
ACTOR_EN_SYATEKI_MAN
ACTOR_EN_TANA
ACTOR_EN_NB
ACTOR_BOSS_MO
ACTOR_EN_SB
ACTOR_EN_BIGOKUTA
ACTOR_EN_KAREBABA
ACTOR_BG_BDAN_OBJECTS
ACTOR_DEMO_SA
ACTOR_DEMO_GO
ACTOR_EN_IN
ACTOR_EN_TR
ACTOR_BG_SPOT16_BOMBSTONE
ACTOR_UNSET_CE
ACTOR_BG_HIDAN_KOWARERUKABE
ACTOR_BG_BOMBWALL
ACTOR_BG_SPOT08_ICEBLOCK
ACTOR_EN_RU2
ACTOR_OBJ_DEKUJR
ACTOR_BG_MIZU_UZU
ACTOR_BG_SPOT06_OBJECTS
ACTOR_BG_ICE_OBJECTS
ACTOR_BG_HAKA_WATER
ACTOR_UNSET_D8
ACTOR_EN_MA2
ACTOR_EN_BOM_CHU
ACTOR_EN_HORSE_GAME_CHECK
ACTOR_BOSS_TW
ACTOR_EN_RR
ACTOR_EN_BA
ACTOR_EN_BX
ACTOR_EN_ANUBICE
ACTOR_EN_ANUBICE_FIRE
ACTOR_BG_MORI_HASHIGO
ACTOR_BG_MORI_HASHIRA4
ACTOR_BG_MORI_IDOMIZU
ACTOR_BG_SPOT16_DOUGHNUT
ACTOR_BG_BDAN_SWITCH
ACTOR_EN_MA1
ACTOR_BOSS_GANON
ACTOR_BOSS_SST
ACTOR_UNSET_EA
ACTOR_UNSET_EB
ACTOR_EN_NY
ACTOR_EN_FR
ACTOR_ITEM_SHIELD
ACTOR_BG_ICE_SHELTER
ACTOR_EN_ICE_HONO
ACTOR_ITEM_OCARINA
ACTOR_UNSET_F2
ACTOR_UNSET_F3
ACTOR_MAGIC_DARK
ACTOR_DEMO_6K
ACTOR_EN_ANUBICE_TAG
ACTOR_BG_HAKA_GATE
ACTOR_BG_SPOT15_SAKU
ACTOR_BG_JYA_GOROIWA
ACTOR_BG_JYA_ZURERUKABE
ACTOR_UNSET_FB
ACTOR_BG_JYA_COBRA
ACTOR_BG_JYA_KANAAMI
ACTOR_FISHING
ACTOR_OBJ_OSHIHIKI
ACTOR_BG_GATE_SHUTTER
ACTOR_EFF_DUST
ACTOR_BG_SPOT01_FUSYA
ACTOR_BG_SPOT01_IDOHASHIRA
ACTOR_BG_SPOT01_IDOMIZU
ACTOR_BG_PO_SYOKUDAI
ACTOR_BG_GANON_OTYUKA
ACTOR_BG_SPOT15_RRBOX
ACTOR_BG_UMAJUMP
ACTOR_UNSET_109
ACTOR_ARROW_FIRE
ACTOR_ARROW_ICE
ACTOR_ARROW_LIGHT
ACTOR_UNSET_10D
ACTOR_UNSET_10E
ACTOR_ITEM_ETCETERA
ACTOR_OBJ_KIBAKO
ACTOR_OBJ_TSUBO
ACTOR_EN_WONDER_ITEM
ACTOR_EN_IK
ACTOR_DEMO_IK
ACTOR_EN_SKJ
ACTOR_EN_SKJNEEDLE
ACTOR_EN_G_SWITCH
ACTOR_DEMO_EXT
ACTOR_DEMO_SHD
ACTOR_EN_DNS
ACTOR_ELF_MSG
ACTOR_EN_HONOTRAP
ACTOR_EN_TUBO_TRAP
ACTOR_OBJ_ICE_POLY
ACTOR_BG_SPOT03_TAKI
ACTOR_BG_SPOT07_TAKI
ACTOR_EN_FZ
ACTOR_EN_PO_RELAY
ACTOR_BG_RELAY_OBJECTS
ACTOR_EN_DIVING_GAME
ACTOR_EN_KUSA
ACTOR_OBJ_BEAN
ACTOR_OBJ_BOMBIWA
ACTOR_UNSET_128
ACTOR_UNSET_129
ACTOR_OBJ_SWITCH
ACTOR_OBJ_ELEVATOR
ACTOR_OBJ_LIFT
ACTOR_OBJ_HSBLOCK
ACTOR_EN_OKARINA_TAG
ACTOR_EN_YABUSAME_MARK
ACTOR_EN_GOROIWA
ACTOR_EN_EX_RUPPY
ACTOR_EN_TORYO
ACTOR_EN_DAIKU
ACTOR_UNSET_134
ACTOR_EN_NWC
ACTOR_EN_BLKOBJ
ACTOR_ITEM_INBOX
ACTOR_EN_GE1
ACTOR_OBJ_BLOCKSTOP
ACTOR_EN_SDA
ACTOR_EN_CLEAR_TAG
ACTOR_EN_NIW_LADY
ACTOR_EN_GM
ACTOR_EN_MS
ACTOR_EN_HS
ACTOR_BG_INGATE
ACTOR_EN_KANBAN
ACTOR_EN_HEISHI3
ACTOR_EN_SYATEKI_NIW
ACTOR_EN_ATTACK_NIW
ACTOR_BG_SPOT01_IDOSOKO
ACTOR_EN_SA
ACTOR_EN_WONDER_TALK
ACTOR_BG_GJYO_BRIDGE
ACTOR_EN_DS
ACTOR_EN_MK
ACTOR_EN_BOM_BOWL_MAN
ACTOR_EN_BOM_BOWL_PIT
ACTOR_EN_OWL
ACTOR_EN_ISHI
ACTOR_OBJ_HANA
ACTOR_OBJ_LIGHTSWITCH
ACTOR_OBJ_MURE2
ACTOR_EN_GO
ACTOR_EN_FU
ACTOR_UNSET_154
ACTOR_EN_CHANGER
ACTOR_BG_JYA_MEGAMI
ACTOR_BG_JYA_LIFT
ACTOR_BG_JYA_BIGMIRROR
ACTOR_BG_JYA_BOMBCHUIWA
ACTOR_BG_JYA_AMISHUTTER
ACTOR_BG_JYA_BOMBIWA
ACTOR_BG_SPOT18_BASKET
ACTOR_UNSET_15D
ACTOR_EN_GANON_ORGAN
ACTOR_EN_SIOFUKI
ACTOR_EN_STREAM
ACTOR_UNSET_161
ACTOR_EN_MM
ACTOR_EN_KO
ACTOR_EN_KZ
ACTOR_EN_WEATHER_TAG
ACTOR_BG_SST_FLOOR
ACTOR_EN_ANI
ACTOR_EN_EX_ITEM
ACTOR_BG_JYA_IRONOBJ
ACTOR_EN_JS
ACTOR_EN_JSJUTAN
ACTOR_EN_CS
ACTOR_EN_MD
ACTOR_EN_HY
ACTOR_EN_GANON_MANT
ACTOR_EN_OKARINA_EFFECT
ACTOR_EN_MAG
ACTOR_DOOR_GERUDO
ACTOR_ELF_MSG2
ACTOR_DEMO_GT
ACTOR_EN_PO_FIELD
ACTOR_EFC_ERUPC
ACTOR_BG_ZG
ACTOR_EN_HEISHI4
ACTOR_EN_ZL3
ACTOR_BOSS_GANON2
ACTOR_EN_KAKASI
ACTOR_EN_TAKARA_MAN
ACTOR_OBJ_MAKEOSHIHIKI
ACTOR_OCEFF_SPOT
ACTOR_END_TITLE
ACTOR_UNSET_180
ACTOR_EN_TORCH
ACTOR_DEMO_EC
ACTOR_SHOT_SUN
ACTOR_EN_DY_EXTRA
ACTOR_EN_WONDER_TALK2
ACTOR_EN_GE2
ACTOR_OBJ_ROOMTIMER
ACTOR_EN_SSH
ACTOR_EN_STH
ACTOR_OCEFF_WIPE
ACTOR_OCEFF_STORM
ACTOR_EN_WEIYER
ACTOR_BG_SPOT05_SOKO
ACTOR_BG_JYA_1FLIFT
ACTOR_BG_JYA_HAHENIRON
ACTOR_BG_SPOT12_GATE
ACTOR_BG_SPOT12_SAKU
ACTOR_EN_HINTNUTS
ACTOR_EN_NUTSBALL
ACTOR_BG_SPOT00_BREAK
ACTOR_EN_SHOPNUTS
ACTOR_EN_IT
ACTOR_EN_GELDB
ACTOR_OCEFF_WIPE2
ACTOR_OCEFF_WIPE3
ACTOR_EN_NIW_GIRL
ACTOR_EN_DOG
ACTOR_EN_SI
ACTOR_BG_SPOT01_OBJECTS2
ACTOR_OBJ_COMB
ACTOR_BG_SPOT11_BAKUDANKABE
ACTOR_OBJ_KIBAKO2
ACTOR_EN_DNT_DEMO
ACTOR_EN_DNT_JIJI
ACTOR_EN_DNT_NOMAL
ACTOR_EN_GUEST
ACTOR_BG_BOM_GUARD
ACTOR_EN_HS2
ACTOR_DEMO_KEKKAI
ACTOR_BG_SPOT08_BAKUDANKABE
ACTOR_BG_SPOT17_BAKUDANKABE
ACTOR_UNSET_1AA
ACTOR_OBJ_MURE3
ACTOR_EN_TG
ACTOR_EN_MU
ACTOR_EN_GO2
ACTOR_EN_WF
ACTOR_EN_SKB
ACTOR_DEMO_GJ
ACTOR_DEMO_GEFF
ACTOR_BG_GND_FIREMEIRO
ACTOR_BG_GND_DARKMEIRO
ACTOR_BG_GND_SOULMEIRO
ACTOR_BG_GND_NISEKABE
ACTOR_BG_GND_ICEBLOCK
ACTOR_EN_GB
ACTOR_EN_GS
ACTOR_BG_MIZU_BWALL
ACTOR_BG_MIZU_SHUTTER
ACTOR_EN_DAIKU_KAKARIKO
ACTOR_BG_BOWL_WALL
ACTOR_EN_WALL_TUBO
ACTOR_EN_PO_DESERT
ACTOR_EN_CROW
ACTOR_DOOR_KILLER
ACTOR_BG_SPOT11_OASIS
ACTOR_BG_SPOT18_FUTA
ACTOR_BG_SPOT18_SHUTTER
ACTOR_EN_MA3
ACTOR_EN_COW
ACTOR_BG_ICE_TURARA
ACTOR_BG_ICE_SHUTTER
ACTOR_EN_KAKASI2
ACTOR_EN_KAKASI3
ACTOR_OCEFF_WIPE4
ACTOR_EN_EG
ACTOR_BG_MENKURI_NISEKABE
ACTOR_EN_ZO
ACTOR_OBJ_MAKEKINSUTA
ACTOR_EN_GE3
ACTOR_OBJ_TIMEBLOCK
ACTOR_OBJ_HAMISHI
ACTOR_EN_ZL4
ACTOR_EN_MM2
ACTOR_BG_JYA_BLOCK
ACTOR_OBJ_WARP2BLOCK
ACTOR_ID_MAX

View file

@ -0,0 +1,402 @@
OBJECT_INVALID
OBJECT_GAMEPLAY_KEEP
OBJECT_GAMEPLAY_FIELD_KEEP
OBJECT_GAMEPLAY_DANGEON_KEEP
OBJECT_UNSET_4
OBJECT_UNSET_5
OBJECT_HUMAN
OBJECT_OKUTA
OBJECT_CROW
OBJECT_POH
OBJECT_DY_OBJ
OBJECT_WALLMASTER
OBJECT_DODONGO
OBJECT_FIREFLY
OBJECT_BOX
OBJECT_FIRE
OBJECT_UNSET_10
OBJECT_UNSET_11
OBJECT_BUBBLE
OBJECT_NIW
OBJECT_LINK_BOY
OBJECT_LINK_CHILD
OBJECT_TITE
OBJECT_REEBA
OBJECT_PEEHAT
OBJECT_KINGDODONGO
OBJECT_HORSE
OBJECT_ZF
OBJECT_GOMA
OBJECT_ZL1
OBJECT_GOL
OBJECT_DODOJR
OBJECT_TORCH2
OBJECT_BL
OBJECT_TP
OBJECT_OA1
OBJECT_ST
OBJECT_BW
OBJECT_EI
OBJECT_HORSE_NORMAL
OBJECT_OB1
OBJECT_O_ANIME
OBJECT_SPOT04_OBJECTS
OBJECT_DDAN_OBJECTS
OBJECT_HIDAN_OBJECTS
OBJECT_HORSE_GANON
OBJECT_OA2
OBJECT_SPOT00_OBJECTS
OBJECT_MB
OBJECT_BOMBF
OBJECT_SK2
OBJECT_OE1
OBJECT_OE_ANIME
OBJECT_OE2
OBJECT_YDAN_OBJECTS
OBJECT_GND
OBJECT_AM
OBJECT_DEKUBABA
OBJECT_UNSET_3A
OBJECT_OA3
OBJECT_OA4
OBJECT_OA5
OBJECT_OA6
OBJECT_OA7
OBJECT_JJ
OBJECT_OA8
OBJECT_OA9
OBJECT_OB2
OBJECT_OB3
OBJECT_OB4
OBJECT_HORSE_ZELDA
OBJECT_OPENING_DEMO1
OBJECT_WARP1
OBJECT_B_HEART
OBJECT_DEKUNUTS
OBJECT_OE3
OBJECT_OE4
OBJECT_MENKURI_OBJECTS
OBJECT_OE5
OBJECT_OE6
OBJECT_OE7
OBJECT_OE8
OBJECT_OE9
OBJECT_OE10
OBJECT_OE11
OBJECT_OE12
OBJECT_VALI
OBJECT_OA10
OBJECT_OA11
OBJECT_MIZU_OBJECTS
OBJECT_FHG
OBJECT_OSSAN
OBJECT_MORI_HINERI1
OBJECT_BB
OBJECT_TOKI_OBJECTS
OBJECT_YUKABYUN
OBJECT_ZL2
OBJECT_MJIN
OBJECT_MJIN_FLASH
OBJECT_MJIN_DARK
OBJECT_MJIN_FLAME
OBJECT_MJIN_ICE
OBJECT_MJIN_SOUL
OBJECT_MJIN_WIND
OBJECT_MJIN_OKA
OBJECT_HAKA_OBJECTS
OBJECT_SPOT06_OBJECTS
OBJECT_ICE_OBJECTS
OBJECT_RELAY_OBJECTS
OBJECT_PO_FIELD
OBJECT_PO_COMPOSER
OBJECT_MORI_HINERI1A
OBJECT_MORI_HINERI2
OBJECT_MORI_HINERI2A
OBJECT_MORI_OBJECTS
OBJECT_MORI_TEX
OBJECT_SPOT08_OBJ
OBJECT_WARP2
OBJECT_HATA
OBJECT_BIRD
OBJECT_UNSET_78
OBJECT_UNSET_79
OBJECT_UNSET_7A
OBJECT_UNSET_7B
OBJECT_WOOD02
OBJECT_UNSET_7D
OBJECT_UNSET_7E
OBJECT_UNSET_7F
OBJECT_UNSET_80
OBJECT_LIGHTBOX
OBJECT_PU_BOX
OBJECT_UNSET_83
OBJECT_UNSET_84
OBJECT_TRAP
OBJECT_VASE
OBJECT_IM
OBJECT_TA
OBJECT_TK
OBJECT_XC
OBJECT_VM
OBJECT_BV
OBJECT_HAKACH_OBJECTS
OBJECT_EFC_CRYSTAL_LIGHT
OBJECT_EFC_FIRE_BALL
OBJECT_EFC_FLASH
OBJECT_EFC_LGT_SHOWER
OBJECT_EFC_STAR_FIELD
OBJECT_GOD_LGT
OBJECT_LIGHT_RING
OBJECT_TRIFORCE_SPOT
OBJECT_BDAN_OBJECTS
OBJECT_SD
OBJECT_RD
OBJECT_PO_SISTERS
OBJECT_HEAVY_OBJECT
OBJECT_GNDD
OBJECT_FD
OBJECT_DU
OBJECT_FW
OBJECT_MEDAL
OBJECT_HORSE_LINK_CHILD
OBJECT_SPOT02_OBJECTS
OBJECT_HAKA
OBJECT_RU1
OBJECT_SYOKUDAI
OBJECT_FD2
OBJECT_DH
OBJECT_RL
OBJECT_EFC_TW
OBJECT_DEMO_TRE_LGT
OBJECT_GI_KEY
OBJECT_MIR_RAY
OBJECT_BROB
OBJECT_GI_JEWEL
OBJECT_SPOT09_OBJ
OBJECT_SPOT18_OBJ
OBJECT_BDOOR
OBJECT_SPOT17_OBJ
OBJECT_SHOP_DUNGEN
OBJECT_NB
OBJECT_MO
OBJECT_SB
OBJECT_GI_MELODY
OBJECT_GI_HEART
OBJECT_GI_COMPASS
OBJECT_GI_BOSSKEY
OBJECT_GI_MEDAL
OBJECT_GI_NUTS
OBJECT_SA
OBJECT_GI_HEARTS
OBJECT_GI_ARROWCASE
OBJECT_GI_BOMBPOUCH
OBJECT_IN
OBJECT_TR
OBJECT_SPOT16_OBJ
OBJECT_OE1S
OBJECT_OE4S
OBJECT_OS_ANIME
OBJECT_GI_BOTTLE
OBJECT_GI_STICK
OBJECT_GI_MAP
OBJECT_OF1D_MAP
OBJECT_RU2
OBJECT_GI_SHIELD_1
OBJECT_DEKUJR
OBJECT_GI_MAGICPOT
OBJECT_GI_BOMB_1
OBJECT_OF1S
OBJECT_MA2
OBJECT_GI_PURSE
OBJECT_HNI
OBJECT_TW
OBJECT_RR
OBJECT_BXA
OBJECT_ANUBICE
OBJECT_GI_GERUDO
OBJECT_GI_ARROW
OBJECT_GI_BOMB_2
OBJECT_GI_EGG
OBJECT_GI_SCALE
OBJECT_GI_SHIELD_2
OBJECT_GI_HOOKSHOT
OBJECT_GI_OCARINA
OBJECT_GI_MILK
OBJECT_MA1
OBJECT_GANON
OBJECT_SST
OBJECT_NY_UNUSED
OBJECT_UNSET_E4
OBJECT_NY
OBJECT_FR
OBJECT_GI_PACHINKO
OBJECT_GI_BOOMERANG
OBJECT_GI_BOW
OBJECT_GI_GLASSES
OBJECT_GI_LIQUID
OBJECT_ANI
OBJECT_DEMO_6K
OBJECT_GI_SHIELD_3
OBJECT_GI_LETTER
OBJECT_SPOT15_OBJ
OBJECT_JYA_OBJ
OBJECT_GI_CLOTHES
OBJECT_GI_BEAN
OBJECT_GI_FISH
OBJECT_GI_SAW
OBJECT_GI_HAMMER
OBJECT_GI_GRASS
OBJECT_GI_LONGSWORD
OBJECT_SPOT01_OBJECTS
OBJECT_MD_UNUSED
OBJECT_MD
OBJECT_KM1
OBJECT_KW1
OBJECT_ZO
OBJECT_KZ
OBJECT_UMAJUMP
OBJECT_MASTERKOKIRI
OBJECT_MASTERKOKIRIHEAD
OBJECT_MASTERGOLON
OBJECT_MASTERZOORA
OBJECT_AOB
OBJECT_IK
OBJECT_AHG
OBJECT_CNE
OBJECT_GI_NIWATORI
OBJECT_SKJ
OBJECT_GI_BOTTLE_LETTER
OBJECT_BJI
OBJECT_BBA
OBJECT_GI_OCARINA_0
OBJECT_DS
OBJECT_ANE
OBJECT_BOJ
OBJECT_SPOT03_OBJECT
OBJECT_SPOT07_OBJECT
OBJECT_FZ
OBJECT_BOB
OBJECT_GE1
OBJECT_YABUSAME_POINT
OBJECT_GI_BOOTS_2
OBJECT_GI_SEED
OBJECT_GND_MAGIC
OBJECT_D_ELEVATOR
OBJECT_D_HSBLOCK
OBJECT_D_LIFT
OBJECT_MAMENOKI
OBJECT_GOROIWA
OBJECT_UNSET_120
OBJECT_TORYO
OBJECT_DAIKU
OBJECT_UNSET_123
OBJECT_NWC
OBJECT_BLKOBJ
OBJECT_GM
OBJECT_MS
OBJECT_HS
OBJECT_INGATE
OBJECT_LIGHTSWITCH
OBJECT_KUSA
OBJECT_TSUBO
OBJECT_GI_GLOVES
OBJECT_GI_COIN
OBJECT_KANBAN
OBJECT_GJYO_OBJECTS
OBJECT_OWL
OBJECT_MK
OBJECT_FU
OBJECT_GI_KI_TAN_MASK
OBJECT_GI_REDEAD_MASK
OBJECT_GI_SKJ_MASK
OBJECT_GI_RABIT_MASK
OBJECT_GI_TRUTH_MASK
OBJECT_GANON_OBJECTS
OBJECT_SIOFUKI
OBJECT_STREAM
OBJECT_MM
OBJECT_FA
OBJECT_OS
OBJECT_GI_EYE_LOTION
OBJECT_GI_POWDER
OBJECT_GI_MUSHROOM
OBJECT_GI_TICKETSTONE
OBJECT_GI_BROKENSWORD
OBJECT_JS
OBJECT_CS
OBJECT_GI_PRESCRIPTION
OBJECT_GI_BRACELET
OBJECT_GI_SOLDOUT
OBJECT_GI_FROG
OBJECT_MAG
OBJECT_DOOR_GERUDO
OBJECT_GT
OBJECT_EFC_ERUPC
OBJECT_ZL2_ANIME1
OBJECT_ZL2_ANIME2
OBJECT_GI_GOLONMASK
OBJECT_GI_ZORAMASK
OBJECT_GI_GERUDOMASK
OBJECT_GANON2
OBJECT_KA
OBJECT_TS
OBJECT_ZG
OBJECT_GI_HOVERBOOTS
OBJECT_GI_M_ARROW
OBJECT_DS2
OBJECT_EC
OBJECT_FISH
OBJECT_GI_SUTARU
OBJECT_GI_GODDESS
OBJECT_SSH
OBJECT_BIGOKUTA
OBJECT_BG
OBJECT_SPOT05_OBJECTS
OBJECT_SPOT12_OBJ
OBJECT_BOMBIWA
OBJECT_HINTNUTS
OBJECT_RS
OBJECT_SPOT00_BREAK
OBJECT_GLA
OBJECT_SHOPNUTS
OBJECT_GELDB
OBJECT_GR
OBJECT_DOG
OBJECT_JYA_IRON
OBJECT_JYA_DOOR
OBJECT_UNSET_16E
OBJECT_SPOT11_OBJ
OBJECT_KIBAKO2
OBJECT_DNS
OBJECT_DNK
OBJECT_GI_FIRE
OBJECT_GI_INSECT
OBJECT_GI_BUTTERFLY
OBJECT_GI_GHOST
OBJECT_GI_SOUL
OBJECT_BOWL
OBJECT_DEMO_KEKKAI
OBJECT_EFC_DOUGHNUT
OBJECT_GI_DEKUPOUCH
OBJECT_GANON_ANIME1
OBJECT_GANON_ANIME2
OBJECT_GANON_ANIME3
OBJECT_GI_RUPY
OBJECT_SPOT01_MATOYA
OBJECT_SPOT01_MATOYAB
OBJECT_MU
OBJECT_WF
OBJECT_SKB
OBJECT_GJ
OBJECT_GEFF
OBJECT_HAKA_DOOR
OBJECT_GS
OBJECT_PS
OBJECT_BWALL
OBJECT_COW
OBJECT_COB
OBJECT_GI_SWORD_1
OBJECT_DOOR_KILLER
OBJECT_OUKE_HAKA
OBJECT_TIMEBLOCK
OBJECT_ZL4

View file

@ -0,0 +1 @@
8012DB20 gMtxClear

View file

@ -15,7 +15,7 @@ extern "C"
#include <soh/Enhancements/randomizer/randomizer_inf.h>
#if defined(INCLUDE_GAME_PRINTF) && defined(_DEBUG)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, ##__VA_ARGS__)
#else
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
#endif

View file

@ -1,6 +1,10 @@
#ifndef Z64_AUDIO_H
#define Z64_AUDIO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <endianness.h>
#define MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0))
@ -24,8 +28,8 @@
//#define MAX_SEQUENCES 0x800
extern size_t sequenceMapSize;
extern char* fontMap[256];
extern size_t fontMapSize;
extern char** fontMap;
#define MAX_AUTHENTIC_SEQID 110
@ -54,7 +58,8 @@ typedef enum {
/* 2 */ CODEC_S16_INMEMORY,
/* 3 */ CODEC_SMALL_ADPCM,
/* 4 */ CODEC_REVERB,
/* 5 */ CODEC_S16
/* 5 */ CODEC_S16,
/* 6 */ CODEC_OPUS,
} SampleCodec;
typedef enum {
@ -117,12 +122,13 @@ typedef struct {
/* 0x2 */ s16 arg;
} AdsrEnvelope; // size = 0x4
typedef struct {
/* 0x00 */ uintptr_t start;
/* 0x04 */ uintptr_t end;
/* 0x08 */ u32 count;
/* 0x0C */ char unk_0C[0x4];
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
typedef struct AdpcmLoop {
/* 0x00 */ u32 start;
/* 0x04 */ u32 loopEnd; // numSamples position into the sample where the loop ends
/* 0x08 */ u32 count; // The number of times the loop is played before the sound completes. Setting count to -1
// indicates that the loop should play indefinitely.
/* 0x0C */ u32 sampleEnd; // total number of s16-samples in the sample audio clip
/* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned
} AdpcmLoop; // size = 0x30 (or 0x10)
typedef struct {
@ -131,24 +137,23 @@ typedef struct {
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
} AdpcmBook; // size >= 0x8
typedef struct
{
typedef struct SoundFontSample {
union {
struct {
/* 0x00 */ u32 codec : 4;
/* 0x00 */ u32 medium : 2;
/* 0x00 */ u32 unk_bit26 : 1;
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
/* 0x01 */ u32 size : 24;
///* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
};
u32 asU32;
};
/* 0x04 */ u8* sampleAddr;
/* 0x08 */ AdpcmLoop* loop;
/* 0x0C */ AdpcmBook* book;
u32 sampleRateMagicValue; // For wav samples only...
s32 sampleRate; // For wav samples only...
/* 0x1 */ u32 size; // Size of the sample
u32 fileSize;
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either rom or ram
/* 0x8 */ AdpcmLoop* loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram
/* 0xC */ AdpcmBook* book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram
} SoundFontSample; // size = 0x10
typedef struct {
@ -465,6 +470,8 @@ typedef struct {
/* 0x00F0 */ s16 dummyResampleState[0x10];
} NoteSynthesisBuffers; // size = 0x110
struct OggOpusFile;
typedef struct {
/* 0x00 */ u8 restart;
/* 0x01 */ u8 sampleDmaIndex;
@ -483,6 +490,7 @@ typedef struct {
/* 0x1A */ u8 unk_1A;
/* 0x1C */ u16 unk_1C;
/* 0x1E */ u16 unk_1E;
struct OggOpusFile* opusFile; // Only for streamed opus audio
} NoteSynthesisState; // size = 0x20
typedef struct {
@ -917,7 +925,7 @@ typedef struct {
/* 0x3420 */ AudioPoolSplit3 persistentCommonPoolSplit;
/* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit;
/* 0x3438 */ u8 sampleFontLoadStatus[0x30];
/* 0x3468 */ u8 fontLoadStatus[0x30];
/* 0x3468 */ u8* fontLoadStatus;
/* 0x3498 */ u8* seqLoadStatus;
/* 0x3518 */ volatile u8 resetStatus;
/* 0x3519 */ u8 audioResetSpecIdToLoad;
@ -1119,10 +1127,6 @@ typedef struct {
uint8_t fonts[16];
} SequenceData;
#ifdef __cplusplus
extern "C" {
#endif
void Audio_SetGameVolume(int player_id, f32 volume);
float Audio_GetGameVolume(int player_id);

View file

@ -609,13 +609,13 @@ std::string Extractor::Mkdtemp() {
extern "C" int zapd_main(int argc, char** argv);
bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
constexpr int argc = 18;
constexpr int argc = 22;
char xmlPath[1024];
char confPath[1024];
char portVersion[18]; // 5 digits for int16_max (x3) + separators + terminator
std::array<const char*, argc> argv;
const char* version = GetZapdVerStr();
const char* otrFile = IsMasterQuest() ? "oot-mq.otr" : "oot.otr";
const char* otrFile = IsMasterQuest() ? "oot-mq.o2r" : "oot.o2r";
std::string romPath = std::filesystem::absolute(mCurrentRomPath).string();
installPath = std::filesystem::absolute(installPath).string();
@ -632,8 +632,8 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
std::filesystem::current_path(tempdir);
snprintf(xmlPath, 1024, "assets/extractor/xmls/%s", version);
snprintf(confPath, 1024, "assets/extractor/Config_%s.xml", version);
snprintf(xmlPath, 1024, "assets/xml/%s", version);
snprintf(confPath, 1024, "assets/Config_%s.xml", version);
snprintf(portVersion, 18, "%d.%d.%d", gBuildVersionMajor, gBuildVersionMinor, gBuildVersionPatch);
argv[0] = "ZAPD";
@ -643,9 +643,9 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
argv[4] = "-b";
argv[5] = romPath.c_str();
argv[6] = "-fl";
argv[7] = "assets/extractor/filelists";
argv[7] = "assets/filelists";
argv[8] = "-gsf";
argv[9] = "1";
argv[9] = "0";
argv[10] = "-rconf";
argv[11] = confPath;
argv[12] = "-se";
@ -654,6 +654,10 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
argv[15] = otrFile;
argv[16] = "--portVer";
argv[17] = portVersion;
argv[18] = "-o";
argv[19] = "placeholder";
argv[20] = "-osf";
argv[21] = "placeholder";
#ifdef _WIN32
// Grab a handle to the command window.

View file

@ -263,15 +263,15 @@ const char* constCameraStrings[] = {
OTRGlobals::OTRGlobals() {
std::vector<std::string> OTRFiles;
std::string mqPath = Ship::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName);
std::string mqPath = Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName);
if (std::filesystem::exists(mqPath)) {
OTRFiles.push_back(mqPath);
}
std::string ootPath = Ship::Context::LocateFileAcrossAppDirs("oot.otr", appShortName);
std::string ootPath = Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName);
if (std::filesystem::exists(ootPath)) {
OTRFiles.push_back(ootPath);
}
std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.otr");
std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.o2r");
if (std::filesystem::exists(sohOtrPath)) {
OTRFiles.push_back(sohOtrPath);
}
@ -403,12 +403,19 @@ OTRGlobals::OTRGlobals() {
static_cast<uint32_t>(SOH::ResourceType::SOH_Text), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSampleV2>(), RESOURCE_FORMAT_BINARY,
"AudioSample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 2);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLAudioSampleV0>(), RESOURCE_FORMAT_XML,
"Sample", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSample), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSoundFontV2>(),
RESOURCE_FORMAT_BINARY, "AudioSoundFont",
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 2);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLSoundFontV0>(), RESOURCE_FORMAT_XML,
"SoundFont", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSoundFont), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAudioSequenceV2>(),
RESOURCE_FORMAT_BINARY, "AudioSequence",
static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 2);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryXMLAudioSequenceV0>(), RESOURCE_FORMAT_XML,
"Sequence", static_cast<uint32_t>(SOH::ResourceType::SOH_AudioSequence), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryBackgroundV0>(), RESOURCE_FORMAT_BINARY,
"Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
@ -601,6 +608,12 @@ extern "C" void OTRAudio_Init() {
}
}
extern "C" char** sequenceMap;
extern "C" size_t sequenceMapSize;
extern "C" char** fontMap;
extern "C" size_t fontMapSize;
extern "C" void OTRAudio_Exit() {
// Tell the audio thread to stop
{
@ -611,6 +624,19 @@ extern "C" void OTRAudio_Exit() {
// Wait until the audio thread quit
audio.thread.join();
#if 0
for (size_t i = 0; i < sequenceMapSize; i++) {
free(sequenceMap[i]);
}
free(sequenceMap);
for (size_t i = 0; i < fontMapSize; i++) {
free(fontMap[i]);
}
free(fontMap);
free(gAudioContext.seqLoadStatus);
free(gAudioContext.fontLoadStatus);
#endif
}
extern "C" void VanillaItemTable_Init() {
@ -945,7 +971,7 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
OTRVersion version = {};
// Use a temporary archive instance to load the otr and read the version file
auto archive = std::make_shared<Ship::OtrArchive>(otrPath);
auto archive = std::make_shared<Ship::O2rArchive>(otrPath);
if (archive->Open()) {
auto t = archive->LoadFile("portVersion");
if (t != nullptr && t->IsLoaded) {
@ -963,7 +989,7 @@ OTRVersion ReadPortVersionFromOTR(std::string otrPath) {
return version;
}
// Check that a soh.otr exists and matches the version of soh running
// Check that a soh.o2r exists and matches the version of soh running
// Otherwise show a message and exit
void CheckSoHOTRVersion(std::string otrPath) {
std::string msg;
@ -972,20 +998,20 @@ void CheckSoHOTRVersion(std::string otrPath) {
msg = "\x1b[4;2HPlease re-extract it from the download."
"\x1b[6;2HPress the Home button to exit...";
#elif defined(__WIIU__)
msg = "Please extract the soh.otr from the Ship of Harkinian download\nto your folder.\n\nPress and hold the power "
msg = "Please extract the soh.o2r from the Ship of Harkinian download\nto your folder.\n\nPress and hold the power "
"button to shutdown...";
#else
msg = "Please extract the soh.otr from the Ship of Harkinian download to your folder.\n\nExiting...";
msg = "Please extract the soh.o2r from the Ship of Harkinian download to your folder.\n\nExiting...";
#endif
if (!std::filesystem::exists(otrPath)) {
#if not defined(__SWITCH__) && not defined(__WIIU__)
Extractor::ShowErrorBox("soh.otr file is missing", msg.c_str());
Extractor::ShowErrorBox("soh.o2r file is missing", msg.c_str());
exit(1);
#elif defined(__SWITCH__)
Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou are missing the soh.otr file." + msg).c_str());
Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou are missing the soh.o2r file." + msg).c_str());
#elif defined(__WIIU__)
OSFatal(("You are missing the soh.otr file\n\n" + msg).c_str());
OSFatal(("You are missing the soh.o2r file\n\n" + msg).c_str());
#endif
}
@ -994,12 +1020,12 @@ void CheckSoHOTRVersion(std::string otrPath) {
if (otrVersion.major != gBuildVersionMajor || otrVersion.minor != gBuildVersionMinor ||
otrVersion.patch != gBuildVersionPatch) {
#if not defined(__SWITCH__) && not defined(__WIIU__)
Extractor::ShowErrorBox("soh.otr file version does not match", msg.c_str());
Extractor::ShowErrorBox("soh.o2r file version does not match", msg.c_str());
exit(1);
#elif defined(__SWITCH__)
Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou have an old soh.otr file." + msg).c_str());
Ship::Switch::PrintErrorMessageToScreen(("\x1b[2;2HYou have an old soh.o2r file." + msg).c_str());
#elif defined(__WIIU__)
OSFatal(("You have an old soh.otr file\n\n" + msg).c_str());
OSFatal(("You have an old soh.o2r file\n\n" + msg).c_str());
#endif
}
}
@ -1040,10 +1066,10 @@ void DetectOTRVersion(std::string fileName, bool isMQ) {
if (Extractor::ShowYesNoBox("Old OTR File Found", msgBuf) == IDYES) {
std::string installPath = Ship::Context::GetAppBundlePath();
if (!std::filesystem::exists(installPath + "/assets/extractor")) {
if (!std::filesystem::exists(installPath + "/assets")) {
Extractor::ShowErrorBox(
"Extractor assets not found",
"Unable to regenerate. Missing assets/extractor folder needed to generate OTR file.\n\nExiting...");
"Unable to regenerate. Missing assets/ folder needed to generate OTR file.\n\nExiting...");
exit(1);
}
@ -1070,6 +1096,10 @@ void DetectOTRVersion(std::string fileName, bool isMQ) {
}
}
extern "C" void Messagebox_ShowErrorBox(char* title, char* body) {
Extractor::ShowErrorBox(title, body);
}
bool IsSubpath(const std::filesystem::path& path, const std::filesystem::path& base) {
auto rel = std::filesystem::relative(path, base);
return !rel.empty() && rel.native()[0] != '.';
@ -1151,17 +1181,22 @@ extern "C" void InitOTR() {
CheckAndCreateModFolder();
#endif
CheckSoHOTRVersion(Ship::Context::GetPathRelativeToAppBundle("soh.otr"));
CheckSoHOTRVersion(Ship::Context::GetPathRelativeToAppBundle("soh.o2r"));
const bool ootO2RExists =
std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot-mq.o2r", appShortName)) ||
std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.o2r", appShortName));
const bool ootOTRExists =
std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName)) ||
std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.otr", appShortName));
if (!std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName)) &&
!std::filesystem::exists(Ship::Context::LocateFileAcrossAppDirs("oot.otr", appShortName))) {
if (!ootOTRExists && !ootO2RExists) {
#if not defined(__SWITCH__) && not defined(__WIIU__)
std::string installPath = Ship::Context::GetAppBundlePath();
if (!std::filesystem::exists(installPath + "/assets/extractor")) {
if (!std::filesystem::exists(installPath + "/assets")) {
Extractor::ShowErrorBox(
"Extractor assets not found",
"No OTR files found. Missing assets/extractor folder needed to generate OTR file.\n\nExiting...");
"No OTR files found. Missing assets/ folder needed to generate OTR file.\n\nExiting...");
exit(1);
}
@ -1200,8 +1235,8 @@ extern "C" void InitOTR() {
#endif
}
DetectOTRVersion("oot.otr", false);
DetectOTRVersion("oot-mq.otr", true);
DetectOTRVersion("oot.o2r", false);
DetectOTRVersion("oot-mq.o2r", true);
OTRGlobals::Instance = new OTRGlobals();
CustomMessageManager::Instance = new CustomMessageManager();

View file

@ -166,6 +166,7 @@ void CheckTracker_OnMessageClose();
GetItemID RetrieveGetItemIDFromItemID(ItemID itemID);
RandomizerGet RetrieveRandomizerGetFromItemID(ItemID itemID);
void Messagebox_ShowErrorBox(char* title, char* body);
#endif
#ifdef __cplusplus

View file

@ -429,11 +429,16 @@ extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) {
return *sequence;
}
extern "C" SequenceData* ResourceMgr_LoadSeqPtrByName(const char* path) {
SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path);
return sequence;
}
extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(const char* path) {
return (SoundFontSample*)ResourceGetDataByName(path);
}
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) {
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFontByName(const char* path) {
return (SoundFont*)ResourceGetDataByName(path);
}

View file

@ -51,8 +51,9 @@ void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName);
char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path);
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
Vtx* ResourceMgr_LoadVtxByName(char* path);
SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path);
SoundFont* ResourceMgr_LoadAudioSoundFontByName(const char* path);
SequenceData ResourceMgr_LoadSeqByName(const char* path);
SequenceData* ResourceMgr_LoadSeqPtrByName(const char* path);
SoundFontSample* ResourceMgr_LoadAudioSample(const char* path);
CollisionHeader* ResourceMgr_LoadColByName(const char* path);
bool ResourceMgr_IsAltAssetsEnabled();

View file

@ -1,9 +1,11 @@
//! This file is always optimized by a rule in the CMakeList. This is done because the SIMD functions are very large
//! when unoptimized and clang does not allow optimizing a single function.
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "mixer.h"
#ifndef __clang__
#pragma GCC optimize("unroll-loops")
#endif
@ -14,6 +16,7 @@
#define ROUND_UP_8(v) (((v) + 7) & ~7)
#define ROUND_DOWN_16(v) ((v) & ~0xf)
#define DMEM_BUF_SIZE (0x1000 - 0x3C0 - 0x40)
#define BUF_U8(a) (rspa.buf.as_u8 + ((a)-0x3C0))
#define BUF_S16(a) (rspa.buf.as_s16 + ((a)-0x3C0) / sizeof(int16_t))
@ -35,7 +38,7 @@ static struct {
uint16_t filter_count;
int16_t filter[8];
union {
__attribute__((aligned(16))) union {
int16_t as_s16[DMEM_BUF_SIZE / sizeof(int16_t)];
uint8_t as_u8[DMEM_BUF_SIZE];
} buf;
@ -66,6 +69,9 @@ static int16_t resample_table[64][4] = {
{ 0xffdf, 0x0d46, 0x66ad, 0x0c39 }
};
static void aMixImplSSE2(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
static void aMixImplNEON(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
static inline int16_t clamp16(int32_t v) {
if (v < -0x8000) {
return -0x8000;
@ -99,6 +105,33 @@ void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbyte
#endif
}
#include <opus/opus.h>
#include <opusfile.h>
void aOPUSdecImpl(void* source_addr, uint16_t dest_addr, uint16_t nbytes, struct OggOpusFile** decState, int32_t pos,
uint32_t size) {
int readSamples = 0;
if (*decState == NULL) {
*decState = op_open_memory(source_addr, size, NULL);
}
op_pcm_seek(*decState, pos);
int ret = op_read(*decState, BUF_S16(dest_addr), nbytes / 2, NULL);
if (ret < 0) {
return;
}
readSamples += ret;
while (readSamples < nbytes / 2) {
ret = op_read(*decState, BUF_S16(dest_addr + readSamples * 2), (nbytes - readSamples * 2) / 2, NULL);
if (ret == 0)
break;
readSamples += ret;
}
}
void aOPUSFree(struct OggOpusFile* opusFile) {
op_free(opusFile);
}
void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes) {
memcpy(dest_addr, BUF_S16(source_addr), ROUND_DOWN_16(nbytes));
}
@ -296,7 +329,7 @@ void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool
} while (n > 0);
}
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
static void aMixImplRef(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
int16_t* in = BUF_S16(in_addr);
int16_t* out = BUF_S16(out_addr);
@ -323,6 +356,16 @@ void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr)
}
}
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
#if defined(__SSE2__) || defined(_M_AMD64)
aMixImplSSE2(count, gain, in_addr, out_addr);
#elif defined(__ARM_NEON)
aMixImplNEON(count, gain, in_addr, out_addr);
#else
aMixImplRef(count, gain, in_addr, out_addr);
#endif
}
void aS8DecImpl(uint8_t flags, ADPCM_STATE state) {
uint8_t* in = BUF_U8(rspa.in);
int16_t* out = BUF_S16(rspa.out);
@ -555,3 +598,222 @@ void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_add
nbytes -= 32 * sizeof(int16_t);
} while (nbytes > 0);
}
// From here on there are SIMD implementations of the various mixer functions.
// A note about FORCE_OPTIMIZE...
// Compilers don't handle SIMD code well when not optimizing. It is unlikely that this code will need to be debugged
// outside of specific audio issues. We can assume it should always be optimized.
// SIMD operations expect aligned data
#include "align_asset_macro.h"
#if defined(__SSE2__) || defined(_M_AMD64)
#include <immintrin.h>
static const ALIGN_ASSET(16) int16_t x7fff[8] = {
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
};
static const ALIGN_ASSET(16) int32_t x4000[4] = {
0x4000,
0x4000,
0x4000,
0x4000,
};
static void aMixImplSSE2(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
int16_t* in = BUF_S16(in_addr);
int16_t* out = BUF_S16(out_addr);
int i;
int32_t sample;
if (gain == -0x8000) {
while (nbytes > 0) {
for (unsigned int i = 0; i < 2; i++) {
__m128i outVec = _mm_loadu_si128((__m128i*)out);
__m128i inVec = _mm_loadu_si128((__m128i*)in);
__m128i subsVec = _mm_subs_epi16(outVec, inVec);
_mm_storeu_si128(out, subsVec);
nbytes -= 8 * sizeof(int16_t);
in += 8;
out += 8;
}
}
}
// Load constants into vectors from aligned memory.
__m128i x7fffVec = _mm_load_si128((__m128i*)x7fff);
__m128i x4000Vec = _mm_load_si128((__m128i*)x4000);
__m128i gainVec = _mm_set1_epi16(gain);
while (nbytes > 0) {
for (unsigned int i = 0; i < 2; i++) {
// Load input and output data into vectors
__m128i outVec = _mm_loadu_si128((__m128i*)out);
__m128i inVec = _mm_loadu_si128((__m128i*)in);
// Multiply `out` by `0x7FFF` producing 32 bit results, and store the upper and lower bits in each vector.
// Equivalent to `out[0..8] * 0x7FFF`
__m128i outx7fffLoVec = _mm_mullo_epi16(outVec, x7fffVec);
__m128i outx7fffHiVec = _mm_mulhi_epi16(outVec, x7fffVec);
// Same as above but for in and gain. Equivalent to `in[0..8] * gain`
__m128i inxGainLoVec = _mm_mullo_epi16(inVec, gainVec);
__m128i inxGainHiVec = _mm_mulhi_epi16(inVec, gainVec);
// Interleave the lo and hi bits into one 32 bit value for each vector element.
// So now we have 4 full elements in each vector instead of 8 half elements.
outx7fffLoVec = _mm_unpacklo_epi16(outx7fffLoVec, outx7fffHiVec);
outx7fffHiVec = _mm_unpackhi_epi16(outx7fffLoVec, outx7fffHiVec);
inxGainLoVec = _mm_unpacklo_epi16(inxGainLoVec, inxGainHiVec);
inxGainHiVec = _mm_unpackhi_epi16(inxGainLoVec, inxGainHiVec);
// Now we have 4 32 bit elements. Continue the calculaton per the reference implementation.
// We already did out + 0x7fff and in * gain.
// *out * 0x7fff + *in++ * gain is the final result of these two calculations.
__m128i addLoVec = _mm_add_epi32(outx7fffLoVec, inxGainLoVec);
__m128i addHiVec = _mm_add_epi32(outx7fffHiVec, inxGainHiVec);
// Add 0x4000 to each element
addLoVec = _mm_add_epi32(addLoVec, x4000Vec);
addHiVec = _mm_add_epi32(addHiVec, x4000Vec);
// Shift each element over by 15
__m128i shiftedLoVec = _mm_srai_epi32(addLoVec, 15);
__m128i shiftedHiVec = _mm_srai_epi32(addHiVec, 15);
// Convert each 32 bit element to 16 bit with saturation (clamp) and store in `outVec`
outVec = _mm_packs_epi32(shiftedLoVec, shiftedHiVec);
// Write the final vector back to memory
// The final calculation is ((out[0..8] * 0x7fff + in[0..8] * gain) + 0x4000) >> 15;
_mm_storeu_si128((__m128i*)out, outVec);
in += 8;
out += 8;
nbytes -= 8 * sizeof(int16_t);
}
}
}
#endif
#if defined(__ARM_NEON)
#include <arm_neon.h>
static const int32_t x4000Arr[4] = { 0x4000, 0x4000, 0x4000, 0x4000 };
void aMixImplNEON(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
int16_t* in = BUF_S16(in_addr);
int16_t* out = BUF_S16(out_addr);
int i;
int32_t sample;
if (gain == -0x8000) {
while (nbytes > 0) {
for (unsigned int i = 0; i < 2; i++) {
int16x8_t outVec = vld1q_s16(out);
int16x8_t inVec = vld1q_s16(in);
int16x8_t subVec = vqsubq_s16(outVec, inVec);
vst1q_s16(out, subVec);
nbytes -= 8 * sizeof(int16_t);
out += 8;
in += 8;
}
}
}
int16x8_t gainVec = vdupq_n_s16(gain);
int32x4_t x4000Vec = vld1q_s32(x4000Arr);
while (nbytes > 0) {
for (unsigned int i = 0; i < 2; i++) {
// for (i = 0; i < 16; i++) {
int16x8_t outVec = vld1q_s16(out);
int16x8_t inVec = vld1q_s16(in);
int16x4_t outLoVec = vget_low_s16(outVec);
int16x8_t outLoVec2 = vcombine_s16(outLoVec, outLoVec);
int16x4_t inLoVec = vget_low_s16(inVec);
int16x8_t inLoVec2 = vcombine_s16(inLoVec, inLoVec);
int32x4_t outX7fffHiVec = vmull_high_n_s16(outVec, 0x7FFF);
int32x4_t outX7fffLoVec = vmull_high_n_s16(outLoVec2, 0x7FFF);
int32x4_t inGainLoVec = vmull_high_s16(inLoVec2, gainVec);
int32x4_t inGainHiVec = vmull_high_s16(inVec, gainVec);
int32x4_t addVecLo = vaddq_s32(outX7fffLoVec, inGainLoVec);
int32x4_t addVecHi = vaddq_s32(outX7fffHiVec, inGainHiVec);
addVecHi = vaddq_s32(addVecHi, x4000Vec);
addVecLo = vaddq_s32(addVecLo, x4000Vec);
int32x4_t shiftVecHi = vshrq_n_s32(addVecHi, 15);
int32x4_t shiftVecLo = vshrq_n_s32(addVecLo, 15);
int16x4_t shiftedNarrowHiVec = vqmovn_s32(shiftVecHi);
int16x4_t shiftedNarrowLoVec = vqmovn_s32(shiftVecLo);
vst1_s16(out, shiftedNarrowLoVec);
out += 4;
vst1_s16(out, shiftedNarrowHiVec);
// int16x8_t finalVec = vcombine_s16(shiftedNarrowLoVec, shiftedNarrowHiVec);
// vst1q_s16(out, finalVec);
out += 4;
in += 8;
nbytes -= 8 * sizeof(int16_t);
}
}
}
#endif
#if 0
static const ALIGN_ASSET(32) int16_t x7fff[16] = { 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,};
static const ALIGN_ASSET(32) int32_t x4000[8] = { 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000};
#pragma GCC target("avx2")
// AVX2 version of the SSE2 implementation above. AVX2 wasn't released until 2014 and I don't have a good way of checking for it at compile time.
void aMixImpl256(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
int16_t* in = BUF_S16(in_addr);
int16_t* out = BUF_S16(out_addr);
int i;
int32_t sample;
if (gain == -0x8000) {
while (nbytes > 0) {
__m256i outVec =_mm256_loadu_si256((__m256*)out);
__m256i inVec =_mm256_loadu_si256((__m256i*)in);
__m256i subsVec =_mm256_subs_epi16(outVec, inVec);
_mm256_storeu_si256(out, subsVec);
in += 16;
out += 16;
nbytes -= 16 * sizeof(int16_t);
}
}
// Load constants into vectors from aligned memory.
__m256i x7fffVec = _mm256_load_si256((__m256i*)x7fff);
__m256i x4000Vec = _mm256_load_si256((__m256i*)x4000);
__m256i gainVec = _mm256_set1_epi16(gain);
while (nbytes > 0) {
// Load input and output data into vectors
__m256i outVec = _mm256_loadu_si256((__m256i*)out);
__m256i inVec = _mm256_loadu_si256((__m256i*)in);
// Multiply `out` by `0x7FFF` producing 32 bit results, and store the upper and lower bits in each vector.
// Equivalent to `out[0..16] * 0x7FFF`
__m256i outx7fffLoVec = _mm256_mullo_epi16(outVec, x7fffVec);
__m256i outx7fffHiVec = _mm256_mulhi_epi16(outVec, x7fffVec);
// Same as above but for in and gain. Equivalent to `in[0..16] * gain`
__m256i inxGainLoVec = _mm256_mullo_epi16(inVec, gainVec);
__m256i inxGainHiVec = _mm256_mulhi_epi16(inVec, gainVec);
// Interleave the lo and hi bits into one 32 bit value for each vector element.
// So now we have 8 full elements in each vector instead of 16 half elements.
outx7fffLoVec = _mm256_unpacklo_epi16(outx7fffLoVec, outx7fffHiVec);
outx7fffHiVec = _mm256_unpackhi_epi16(outx7fffLoVec, outx7fffHiVec);
inxGainLoVec = _mm256_unpacklo_epi16(inxGainLoVec, inxGainHiVec);
inxGainHiVec = _mm256_unpackhi_epi16(inxGainLoVec, inxGainHiVec);
// Now we have 8 32 bit elements. Continue the calculaton per the reference implementation.
// We already did out + 0x7fff and in * gain.
// *out * 0x7fff + *in++ * gain is the final result of these two calculations.
__m256i addLoVec = _mm256_add_epi32(outx7fffLoVec, inxGainLoVec);
__m256i addHiVec = _mm256_add_epi32(outx7fffHiVec, inxGainHiVec);
// Add 0x4000 to each element
addLoVec = _mm256_add_epi32(addLoVec, x4000Vec);
addHiVec = _mm256_add_epi32(addHiVec, x4000Vec);
// Shift each element over by 15
__m256i shiftedLoVec = _mm256_srai_epi32(addLoVec, 15);
__m256i shiftedHiVec = _mm256_srai_epi32(addHiVec, 15);
// Convert each 32 bit element to 16 bit with saturation (clamp) and store in `outVec`
outVec = _mm256_packs_epi32(shiftedLoVec, shiftedHiVec);
// Write the final vector back to memory
// The final calculation is ((out[0..16] * 0x7fff + in[0..16] * gain) + 0x4000) >> 15;
_mm256_storeu_si256((__m256i*)out, outVec);
in += 16;
out += 16;
nbytes -= 16 * sizeof(int16_t);
}
}
#endif

View file

@ -57,6 +57,11 @@ void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr);
void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c);
void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr);
struct OggOpusFile;
void aOPUSdecImpl(void* source_addr, uint16_t dest_addr, uint16_t nbytes, struct OggOpusFile** decState, int32_t pos,
uint32_t size);
#define aSegment(pkt, s, b) \
do { \
} while (0)

View file

@ -1,6 +1,7 @@
#include "soh/resource/importer/AnimationFactory.h"
#include "soh/resource/type/Animation.h"
#include "spdlog/spdlog.h"
#include "Context.h"
namespace SOH {
std::shared_ptr<Ship::IResource>
@ -80,7 +81,11 @@ ResourceFactoryBinaryAnimationV0::ReadResource(std::shared_ptr<Ship::File> file,
animation->animationData.linkAnimationHeader.common.frameCount = reader->ReadInt16();
// Read the segment pointer (always 32 bit, doesn't adjust for system pointer size)
animation->animationData.linkAnimationHeader.segment = (void*)reader->ReadUInt32();
std::string path = reader->ReadString();
const auto animData = std::static_pointer_cast<Animation>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(path.c_str()));
animation->animationData.linkAnimationHeader.segment = animData->GetPointer();
} else if (animType == AnimationType::Legacy) {
SPDLOG_DEBUG("BEYTAH ANIMATION?!");
}

View file

@ -1,6 +1,191 @@
#include "soh/resource/importer/AudioSampleFactory.h"
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSample.h"
#include "spdlog/spdlog.h"
#include "z64.h"
#include "z64audio.h"
#include "Context.h"
#include "resource/archive/Archive.h"
#define DR_WAV_IMPLEMENTATION
#include <dr_wav.h>
#define DR_MP3_IMPLEMENTATION
#include <dr_mp3.h>
#define DR_FLAC_IMPLEMENTATION
#include <dr_flac.h>
#include <ogg/ogg.h>
#include <vorbis/codec.h>
#include "vorbis/vorbisfile.h"
struct OggFileData {
void* data;
size_t pos;
size_t size;
};
typedef enum class OggType {
None = -1,
Vorbis,
Opus,
} OggType;
static size_t VorbisReadCallback(void* out, size_t size, size_t elems, void* src) {
OggFileData* data = static_cast<OggFileData*>(src);
size_t toRead = size * elems;
if (toRead > data->size - data->pos) {
toRead = data->size - data->pos;
}
memcpy(out, static_cast<uint8_t*>(data->data) + data->pos, toRead);
data->pos += toRead;
return toRead / size;
}
static int VorbisSeekCallback(void* src, ogg_int64_t pos, int whence) {
OggFileData* data = static_cast<OggFileData*>(src);
size_t newPos;
switch (whence) {
case SEEK_SET:
newPos = pos;
break;
case SEEK_CUR:
newPos = data->pos + pos;
break;
case SEEK_END:
newPos = data->size + pos;
break;
default:
return -1;
}
if (newPos > data->size) {
return -1;
}
data->pos = newPos;
return 0;
}
static int VorbisCloseCallback([[maybe_unused]] void* src) {
return 0;
}
static long VorbisTellCallback(void* src) {
OggFileData* data = static_cast<OggFileData*>(src);
return data->pos;
}
static const ov_callbacks vorbisCallbacks = {
VorbisReadCallback,
VorbisSeekCallback,
VorbisCloseCallback,
VorbisTellCallback,
};
static OggType GetOggType(OggFileData* data) {
ogg_sync_state oy;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
OggType type;
// The first page as the header information, containing, among other things, what kind of data this ogg holds.
ogg_sync_init(&oy);
char* buffer = ogg_sync_buffer(&oy, 4096);
VorbisReadCallback(buffer, 4096, 1, data);
ogg_sync_wrote(&oy, 4096);
ogg_sync_pageout(&oy, &og);
ogg_stream_init(&os, ogg_page_serialno(&og));
ogg_stream_pagein(&os, &og);
ogg_stream_packetout(&os, &op);
// Can't use strmp because op.packet isn't a null terminated string.
if (memcmp((char*)op.packet, "\x01vorbis", 7) == 0) {
type = OggType::Vorbis;
} else if (memcmp((char*)op.packet, "OpusHead", 8) == 0) {
type = OggType::Opus;
} else {
type = OggType::None;
}
ogg_stream_clear(&os);
ogg_sync_clear(&oy);
return type;
}
static void Mp3DecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile) {
drmp3 mp3;
drwav_uint64 numFrames;
drmp3_bool32 ret =
drmp3_init_memory(&mp3, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
numFrames = drmp3_get_pcm_frame_count(&mp3);
drwav_uint64 channels = mp3.channels;
drwav_uint64 sampleRate = mp3.sampleRate;
audioSample->sample.sampleAddr = new uint8_t[numFrames * channels * 2];
drmp3_read_pcm_frames_s16(&mp3, numFrames, (int16_t*)audioSample->sample.sampleAddr);
}
static void FlacDecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile) {
drflac* flac = drflac_open_memory(sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
drflac_uint64 numFrames = flac->totalPCMFrameCount;
audioSample->sample.sampleAddr = new uint8_t[numFrames * flac->channels * 2];
drflac_read_pcm_frames_s16(flac, numFrames, (int16_t*)audioSample->sample.sampleAddr);
drflac_close(flac);
}
static void OggDecoderWorker(std::shared_ptr<SOH::AudioSample> audioSample, std::shared_ptr<Ship::File> sampleFile,
std::shared_ptr<Ship::ResourceInitData> initData) {
OggVorbis_File vf;
char dataBuff[4096];
long read = 0;
size_t pos = 0;
OggFileData fileData = {
.data = sampleFile->Buffer.get()->data(),
.pos = 0,
.size = sampleFile->Buffer.get()->size(),
};
switch (GetOggType(&fileData)) {
case OggType::Vorbis: {
// Getting the type advanced the position. We are going to use a different library to decode the file which
// assumes the file starts at 0
fileData.pos = 0;
int ret = ov_open_callbacks(&fileData, &vf, nullptr, 0, vorbisCallbacks);
vorbis_info* vi = ov_info(&vf, -1);
uint64_t numFrames = ov_pcm_total(&vf, -1);
uint64_t sampleRate = vi->rate;
uint64_t numChannels = vi->channels;
int bitStream = 0;
size_t toRead = numFrames * numChannels * 2;
audioSample->sample.sampleAddr = new uint8_t[toRead];
do {
read = ov_read(&vf, dataBuff, 4096, 0, 2, 1, &bitStream);
memcpy(audioSample->sample.sampleAddr + pos, dataBuff, read);
pos += read;
} while (read != 0);
ov_clear(&vf);
break;
}
case OggType::Opus: {
// OPUS encoded data is decoded by the audio driver.
audioSample->sample.codec = CODEC_OPUS;
audioSample->sample.sampleAddr = new uint8_t[sampleFile->Buffer.get()->size()];
memcpy(audioSample->sample.sampleAddr, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size());
break;
}
case OggType::None: {
char buff[2048];
snprintf(buff, 2048, "Ogg file %s is not Vorbis or OPUS", initData->Path.c_str());
throw std::runtime_error(buff);
break;
}
}
}
namespace SOH {
std::shared_ptr<Ship::IResource>
@ -16,108 +201,155 @@ ResourceFactoryBinaryAudioSampleV2::ReadResource(std::shared_ptr<Ship::File> fil
audioSample->sample.codec = reader->ReadUByte();
audioSample->sample.medium = reader->ReadUByte();
audioSample->sample.unk_bit26 = reader->ReadUByte();
audioSample->sample.unk_bit25 = reader->ReadUByte();
audioSample->sample.isRelocated = reader->ReadUByte();
audioSample->sample.size = reader->ReadUInt32();
audioSample->audioSampleData.reserve(audioSample->sample.size);
audioSample->sample.sampleAddr = new uint8_t[audioSample->sample.size];
for (uint32_t i = 0; i < audioSample->sample.size; i++) {
audioSample->audioSampleData.push_back(reader->ReadUByte());
audioSample->sample.sampleAddr[i] = reader->ReadUByte();
}
audioSample->sample.sampleAddr = audioSample->audioSampleData.data();
audioSample->loop.start = reader->ReadUInt32();
audioSample->loop.end = reader->ReadUInt32();
audioSample->loop.count = reader->ReadUInt32();
audioSample->loopStateCount = reader->ReadUInt32();
// This always seems to be 16. Can it be removed in V3?
uint32_t loopStateCount = reader->ReadUInt32();
for (int i = 0; i < 16; i++) {
audioSample->loop.state[i] = 0;
}
for (uint32_t i = 0; i < audioSample->loopStateCount; i++) {
for (uint32_t i = 0; i < loopStateCount; i++) {
audioSample->loop.state[i] = reader->ReadInt16();
}
audioSample->sample.loop = &audioSample->loop;
audioSample->book.order = reader->ReadInt32();
audioSample->book.npredictors = reader->ReadInt32();
audioSample->bookDataCount = reader->ReadUInt32();
uint32_t bookDataCount = reader->ReadUInt32();
audioSample->bookData.reserve(audioSample->bookDataCount);
for (uint32_t i = 0; i < audioSample->bookDataCount; i++) {
audioSample->bookData.push_back(reader->ReadInt16());
audioSample->book.book = new int16_t[bookDataCount];
for (uint32_t i = 0; i < bookDataCount; i++) {
audioSample->book.book[i] = reader->ReadInt16();
}
audioSample->book.book = audioSample->bookData.data();
audioSample->sample.book = &audioSample->book;
return audioSample;
}
} // namespace SOH
/*
in ResourceMgr_LoadAudioSample we used to have
--------------
if (cachedCustomSFs.find(path) != cachedCustomSFs.end())
return cachedCustomSFs[path];
SoundFontSample* cSample = ReadCustomSample(path);
if (cSample != nullptr)
return cSample;
--------------
before the rest of the standard sample reading, this is the ReadCustomSample code we used to have
extern "C" SoundFontSample* ReadCustomSample(const char* path) {
if (!ExtensionCache.contains(path))
std::shared_ptr<Ship::IResource>
ResourceFactoryXMLAudioSampleV0::ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (!FileHasValidFormatAndReader(file, initData)) {
return nullptr;
ExtensionEntry entry = ExtensionCache[path];
auto sampleRaw = Ship::Context::GetInstance()->GetResourceManager()->LoadFile(entry.path);
uint32_t* strem = (uint32_t*)sampleRaw->Buffer.get();
uint8_t* strem2 = (uint8_t*)strem;
SoundFontSample* sampleC = new SoundFontSample;
if (entry.ext == "wav") {
drwav_uint32 channels;
drwav_uint32 sampleRate;
drwav_uint64 totalPcm;
drmp3_int16* pcmData =
drwav_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &channels, &sampleRate, &totalPcm,
NULL); sampleC->size = totalPcm; sampleC->sampleAddr = (uint8_t*)pcmData; sampleC->codec = CODEC_S16;
sampleC->loop = new AdpcmLoop;
sampleC->loop->start = 0;
sampleC->loop->end = sampleC->size - 1;
sampleC->loop->count = 0;
sampleC->sampleRateMagicValue = 'RIFF';
sampleC->sampleRate = sampleRate;
cachedCustomSFs[path] = sampleC;
return sampleC;
} else if (entry.ext == "mp3") {
drmp3_config mp3Info;
drmp3_uint64 totalPcm;
drmp3_int16* pcmData =
drmp3_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &mp3Info, &totalPcm, NULL);
sampleC->size = totalPcm * mp3Info.channels * sizeof(short);
sampleC->sampleAddr = (uint8_t*)pcmData;
sampleC->codec = CODEC_S16;
sampleC->loop = new AdpcmLoop;
sampleC->loop->start = 0;
sampleC->loop->end = sampleC->size;
sampleC->loop->count = 0;
sampleC->sampleRateMagicValue = 'RIFF';
sampleC->sampleRate = mp3Info.sampleRate;
cachedCustomSFs[path] = sampleC;
return sampleC;
}
return nullptr;
auto audioSample = std::make_shared<AudioSample>(initData);
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
const char* customFormatStr = child->Attribute("CustomFormat");
memset(&audioSample->sample, 0, sizeof(audioSample->sample));
audioSample->sample.isRelocated = 0;
audioSample->sample.codec = CodecStrToInt(child->Attribute("Codec"), initData->Path.c_str());
audioSample->sample.medium =
ResourceFactoryXMLSoundFontV0::MediumStrToInt(child->Attribute("Medium"), initData->Path.c_str());
audioSample->sample.unk_bit26 = child->IntAttribute("bit26");
tinyxml2::XMLElement* loopRoot = child->FirstChildElement("ADPCMLoop");
if (loopRoot != nullptr) {
size_t i = 0;
audioSample->loop.start = loopRoot->UnsignedAttribute("Start");
audioSample->loop.end = loopRoot->UnsignedAttribute("End");
audioSample->loop.count = loopRoot->UnsignedAttribute("Count");
tinyxml2::XMLElement* predictor = loopRoot->FirstChildElement("Predictor");
while (predictor != nullptr) {
audioSample->loop.state[i++] = predictor->IntAttribute("State");
predictor = predictor->NextSiblingElement();
}
}
tinyxml2::XMLElement* bookRoot = child->FirstChildElement("ADPCMBook");
if (bookRoot != nullptr) {
size_t i = 0;
audioSample->book.npredictors = bookRoot->IntAttribute("Npredictors");
audioSample->book.order = bookRoot->IntAttribute("Order");
tinyxml2::XMLElement* book = bookRoot->FirstChildElement("Book");
size_t numBooks = audioSample->book.npredictors * audioSample->book.order * 8;
audioSample->book.book = new int16_t[numBooks];
while (book != nullptr) {
audioSample->book.book[i++] = book->IntAttribute("Page");
book = book->NextSiblingElement();
}
audioSample->sample.book = &audioSample->book;
}
audioSample->sample.loop = &audioSample->loop;
size_t size = child->Int64Attribute("Size");
audioSample->sample.size = size;
const char* path = child->Attribute("Path");
auto sampleFile = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFile(path);
audioSample->sample.fileSize = sampleFile->Buffer.get()->size();
if (customFormatStr != nullptr) {
// Compressed files can take a really long time to decode (~250ms per).
// This worked when we tested it (09/04/2024) (Works on my machine)
if (strcmp(customFormatStr, "wav") == 0) {
drwav wav;
drwav_uint64 numFrames;
drwav_bool32 ret =
drwav_init_memory(&wav, sampleFile->Buffer.get()->data(), sampleFile->Buffer.get()->size(), nullptr);
drwav_get_length_in_pcm_frames(&wav, &numFrames);
audioSample->tuning = (wav.sampleRate * wav.channels) / 32000.0f;
audioSample->sample.sampleAddr = new uint8_t[numFrames * wav.channels * 2];
drwav_read_pcm_frames_s16(&wav, numFrames, (int16_t*)audioSample->sample.sampleAddr);
return audioSample;
} else if (strcmp(customFormatStr, "mp3") == 0) {
std::thread fileDecoderThread = std::thread(Mp3DecoderWorker, audioSample, sampleFile);
fileDecoderThread.detach();
return audioSample;
} else if (strcmp(customFormatStr, "ogg") == 0) {
std::thread fileDecoderThread = std::thread(OggDecoderWorker, audioSample, sampleFile, initData);
fileDecoderThread.detach();
return audioSample;
} else if (strcmp(customFormatStr, "flac") == 0) {
std::thread fileDecoderThread = std::thread(FlacDecoderWorker, audioSample, sampleFile);
fileDecoderThread.detach();
return audioSample;
}
}
// Not a normal streamed sample. Fallback to the original ADPCM sample to be decoded by the audio engine.
audioSample->sample.sampleAddr = new uint8_t[size];
// Can't use memcpy due to endianness issues.
for (uint32_t i = 0; i < size; i++) {
audioSample->sample.sampleAddr[i] = sampleFile->Buffer.get()->data()[i];
}
return audioSample;
}
*/
uint8_t ResourceFactoryXMLAudioSampleV0::CodecStrToInt(const char* str, const char* file) {
if (strcmp("ADPCM", str) == 0) {
return CODEC_ADPCM;
} else if (strcmp("S8", str) == 0) {
return CODEC_S8;
} else if (strcmp("S16MEM", str) == 0) {
return CODEC_S16_INMEMORY;
} else if (strcmp("ADPCMSMALL", str) == 0) {
return CODEC_SMALL_ADPCM;
} else if (strcmp("REVERB", str) == 0) {
return CODEC_REVERB;
} else if (strcmp("S16", str) == 0) {
return CODEC_S16;
} else {
char buff[2048];
snprintf(buff, 2048,
"Invalid codec in %s. Got %s, expected ADPCM, S8, S16MEM, ADPCMSMALL, REVERB, S16.", file,
str);
throw std::runtime_error(buff);
}
}
} // namespace SOH

View file

@ -2,11 +2,22 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
namespace SOH {
class ResourceFactoryBinaryAudioSampleV2 : public Ship::ResourceFactoryBinary {
class ResourceFactoryBinaryAudioSampleV2 : public Ship::ResourceFactoryBinary {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
};
class ResourceFactoryXMLAudioSampleV0 : public Ship::ResourceFactoryXML {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
private:
static uint8_t CodecStrToInt(const char* str, const char* file);
};
} // namespace SOH

View file

@ -1,7 +1,13 @@
#include "soh/resource/importer/AudioSequenceFactory.h"
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSequence.h"
#include "spdlog/spdlog.h"
#include "Context.h"
#include "resource/archive/Archive.h"
#include "BinaryWriter.h"
#include <type_traits>
namespace SOH {
std::shared_ptr<Ship::IResource>
ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> file,
@ -13,12 +19,11 @@ ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> f
auto audioSequence = std::make_shared<AudioSequence>(initData);
auto reader = std::get<std::shared_ptr<Ship::BinaryReader>>(file->Reader);
audioSequence->sequence.seqDataSize = reader->ReadInt32();
audioSequence->sequenceData.reserve(audioSequence->sequence.seqDataSize);
audioSequence->sequence.seqDataSize = reader->ReadUInt32();
audioSequence->sequence.seqData = new char[audioSequence->sequence.seqDataSize];
for (uint32_t i = 0; i < audioSequence->sequence.seqDataSize; i++) {
audioSequence->sequenceData.push_back(reader->ReadChar());
audioSequence->sequence.seqData[i] = reader->ReadChar();
}
audioSequence->sequence.seqData = audioSequence->sequenceData.data();
audioSequence->sequence.seqNumber = reader->ReadUByte();
audioSequence->sequence.medium = reader->ReadUByte();
@ -34,4 +39,355 @@ ResourceFactoryBinaryAudioSequenceV2::ReadResource(std::shared_ptr<Ship::File> f
return audioSequence;
}
template <typename T> static void WriteInsnOneArg(Ship::BinaryWriter* writer, uint8_t opcode, T arg) {
static_assert(std::is_fundamental<T>::value);
writer->Write(opcode);
writer->Write(arg);
}
template <typename T1, typename T2>
static void WriteInsnTwoArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2) {
static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
writer->Write(opcode);
writer->Write(arg1);
writer->Write(arg2);
}
template <typename T1, typename T2, typename T3>
static void WriteInsnThreeArg(Ship::BinaryWriter* writer, uint8_t opcode, T1 arg1, T2 arg2, T3 arg3) {
static_assert(std::is_fundamental<T1>::value && std::is_fundamental<T2>::value);
writer->Write(opcode);
writer->Write(arg1);
writer->Write(arg2);
writer->Write(arg3);
}
static void WriteInsnNoArg(Ship::BinaryWriter* writer, uint8_t opcode) {
writer->Write(opcode);
}
static void WriteLegato(Ship::BinaryWriter* writer) {
WriteInsnNoArg(writer, 0xC4);
}
static void WriteNoLegato(Ship::BinaryWriter* writer) {
WriteInsnNoArg(writer, 0xC5);
}
static void WriteMuteBhv(Ship::BinaryWriter* writer, uint8_t arg) {
WriteInsnOneArg(writer, 0xD3, arg);
}
static void WriteMuteScale(Ship::BinaryWriter* writer, uint8_t arg) {
WriteInsnOneArg(writer, 0xD5, arg);
}
static void WriteInitchan(Ship::BinaryWriter* writer, uint16_t channels) {
WriteInsnOneArg(writer, 0xD7, channels);
}
static void WriteLdchan(Ship::BinaryWriter* writer, uint8_t channel, uint16_t offset) {
WriteInsnOneArg(writer, 0x90 | channel, offset);
}
static void WriteVolSHeader(Ship::BinaryWriter* writer, uint8_t vol) {
WriteInsnOneArg(writer, 0xDB, vol);
}
static void WriteVolCHeader(Ship::BinaryWriter* writer, uint8_t vol) {
WriteInsnOneArg(writer, 0xDF, vol);
}
static void WriteTempo(Ship::BinaryWriter* writer, uint8_t tempo) {
WriteInsnOneArg(writer, 0xDD, tempo);
}
static void WriteJump(Ship::BinaryWriter* writer, uint16_t offset) {
WriteInsnOneArg(writer, 0xFB, offset);
}
static void WriteDisablecan(Ship::BinaryWriter* writer, uint16_t channels) {
WriteInsnOneArg(writer, 0xD6, channels);
}
static void WriteNoshort(Ship::BinaryWriter* writer) {
WriteInsnNoArg(writer, 0xC4);
}
static void WriteLdlayer(Ship::BinaryWriter* writer, uint8_t layer, uint16_t offset) {
WriteInsnOneArg(writer, 0x88 | layer, offset);
}
static void WritePan(Ship::BinaryWriter* writer, uint8_t pan) {
WriteInsnOneArg(writer, 0xDD, pan);
}
static void WriteBend(Ship::BinaryWriter* writer, uint8_t bend) {
WriteInsnOneArg(writer, 0xD3, bend);
}
static void WriteInstrument(Ship::BinaryWriter* writer, uint8_t instrument) {
WriteInsnOneArg(writer, 0xC1, instrument);
}
static void WriteTranspose(Ship::BinaryWriter* writer, int8_t transpose) {
WriteInsnOneArg(writer, 0xC2, transpose);
}
static void WriteDelay(Ship::BinaryWriter* writer, uint16_t delay) {
if (delay > 0x7F) {
WriteInsnOneArg(writer, 0xFD, static_cast<uint16_t>(delay | 0x8000));
} else {
WriteInsnOneArg(writer, 0xFD, static_cast<uint8_t>(delay));
}
}
template <typename T> static void WriteLDelay(Ship::BinaryWriter* writer, T delay) {
WriteInsnOneArg(writer, 0xC0, delay);
}
template <typename T> static void WriteNotedv(Ship::BinaryWriter* writer, uint8_t note, T delay, uint8_t velocity) {
WriteInsnTwoArg(writer, note, delay, velocity);
}
static void WriteNotedvg(Ship::BinaryWriter* writer, uint8_t note, uint16_t delay, uint8_t velocity, uint8_t gateTime) {
if (delay > 0x7F) {
WriteInsnThreeArg(writer, note, static_cast<uint16_t>(delay | 0x8000), velocity, gateTime);
} else {
WriteInsnThreeArg(writer, note, static_cast<uint8_t>(delay), velocity, gateTime);
}
}
static void WriteMonoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
uint16_t channelStart;
uint16_t channelPlaceholderOff;
uint16_t loopPoint;
uint16_t layerPlaceholderOff;
uint16_t layerStart;
if (looped) {
delay = 0x7FFF;
}
// Write seq header
// These two values are always the same in OOT and MM
WriteMuteBhv(writer, 0x20);
WriteMuteScale(writer, 0x32);
// We only have one channel
WriteInitchan(writer, 0b11);
// Store the current position so we can write the address of the channel when we are ready.
channelPlaceholderOff = writer->GetBaseAddress();
// Store the current position so we can loop here after the song ends.
loopPoint = writer->GetBaseAddress();
WriteLdchan(writer, 0, 0); // Fill in the actual address later
WriteVolSHeader(writer, 127); // Max volume
WriteTempo(writer, tempo);
WriteDelay(writer, delay);
if (looped) {
WriteJump(writer, loopPoint);
}
WriteDisablecan(writer, 0b11);
writer->Write(static_cast<uint8_t>(0xFF));
// Fill in the ldchan from before
channelStart = writer->GetBaseAddress();
writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
WriteLdchan(writer, 0, channelStart);
writer->Seek(channelStart, Ship::SeekOffsetType::Start);
// Channel header
layerPlaceholderOff = writer->GetBaseAddress();
WriteNoshort(writer);
WriteLdlayer(writer, 0, 0);
WritePan(writer, 64);
WriteVolCHeader(writer, 127); // Max volume
WriteBend(writer, 0);
WriteInstrument(writer, 0);
WriteDelay(writer, delay);
writer->Write(static_cast<uint8_t>(0xFF));
layerStart = writer->GetBaseAddress();
writer->Seek(layerPlaceholderOff, Ship::SeekOffsetType::Start);
WriteLdlayer(writer, 0, layerStart);
writer->Seek(layerStart, Ship::SeekOffsetType::Start);
// Note layer
WriteLegato(writer);
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
writer->Write(static_cast<uint8_t>(0xFF));
}
static void WriteStereoSingleSeq(Ship::BinaryWriter* writer, uint16_t delay, uint8_t tempo, bool looped) {
uint16_t lChannelStart;
uint16_t rChannelStart;
uint16_t channelPlaceholderOff;
uint16_t loopPoint;
uint16_t lLayerPlaceholderOff;
uint16_t rLayerPlaceholderOff;
uint16_t lLayerOffset;
uint16_t rLayerOffset;
uint16_t layerStart;
// Write seq header
if (looped) {
delay = 0x7FFF;
}
// These two values are always the same in OOT and MM
WriteMuteBhv(writer, 0x20);
WriteMuteScale(writer, 0x32);
// We only have one channel
WriteInitchan(writer, 0b11);
// Store the current position so we can write the address of the channel when we are ready.
channelPlaceholderOff = writer->GetBaseAddress();
// Store the current position so we can loop here after the song ends.
loopPoint = writer->GetBaseAddress();
// Left note channel
WriteLdchan(writer, 0, 0); // Fill in the actual address later
// Right note channel
WriteLdchan(writer, 1, 0); // Fill in the actual address later
WriteVolSHeader(writer, 127); // Max volume
WriteTempo(writer, tempo);
WriteDelay(writer, delay);
if (looped) {
WriteJump(writer, loopPoint);
}
WriteDisablecan(writer, 0b11);
writer->Write(static_cast<uint8_t>(0xFF));
lChannelStart = writer->GetBaseAddress();
// Left Channel header
WriteNoshort(writer);
lLayerPlaceholderOff = writer->GetBaseAddress();
WriteLdlayer(writer, 0, 0);
WritePan(writer, 0);
WriteVolCHeader(writer, 127); // Max volume
WriteBend(writer, 0);
WriteInstrument(writer, 0);
WriteDelay(writer, delay);
writer->Write(static_cast<uint8_t>(0xFF));
rChannelStart = writer->GetBaseAddress();
// Right Channel header
WriteNoshort(writer);
rLayerPlaceholderOff = writer->GetBaseAddress();
WriteLdlayer(writer, 1, 0);
WritePan(writer, 127);
WriteVolCHeader(writer, 127); // Max volume
WriteBend(writer, 0);
WriteInstrument(writer, 1);
WriteDelay(writer, delay);
writer->Write(static_cast<uint8_t>(0xFF));
uint16_t placeHolder = writer->GetBaseAddress();
writer->Seek(channelPlaceholderOff, Ship::SeekOffsetType::Start);
WriteLdchan(writer, 0, lChannelStart);
WriteLdchan(writer, 1, rChannelStart);
writer->Seek(placeHolder, Ship::SeekOffsetType::Start);
// Left Note layer
lLayerOffset = writer->GetBaseAddress();
WriteLegato(writer);
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
writer->Write(static_cast<uint8_t>(0xFF));
// Right Note layer
rLayerOffset = writer->GetBaseAddress();
WriteLegato(writer);
WriteNotedvg(writer, 39, 0x7FFF - 1, static_cast<uint8_t>(0x7F), static_cast<uint8_t>(1));
writer->Write(static_cast<uint8_t>(0xFF));
writer->Seek(lLayerPlaceholderOff, Ship::SeekOffsetType::Start);
WriteLdlayer(writer, 0, lLayerOffset);
writer->Seek(rLayerPlaceholderOff, Ship::SeekOffsetType::Start);
WriteLdlayer(writer, 1, rLayerOffset);
}
std::shared_ptr<Ship::IResource>
ResourceFactoryXMLAudioSequenceV0::ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (!FileHasValidFormatAndReader(file, initData)) {
return nullptr;
}
auto sequence = std::make_shared<AudioSequence>(initData);
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
unsigned int i = 0;
sequence->sequence.medium =
ResourceFactoryXMLSoundFontV0::MediumStrToInt(child->Attribute("Medium"), initData->Path.c_str());
sequence->sequence.cachePolicy =
ResourceFactoryXMLSoundFontV0::CachePolicyToInt(child->Attribute("CachePolicy"), initData->Path.c_str());
sequence->sequence.seqDataSize = child->IntAttribute("Size");
sequence->sequence.seqNumber = child->IntAttribute("Index");
bool streamed = child->BoolAttribute("Streamed");
memset(sequence->sequence.fonts, 0, sizeof(sequence->sequence.fonts));
tinyxml2::XMLElement* fontsElement = child->FirstChildElement();
tinyxml2::XMLElement* fontElement = fontsElement->FirstChildElement();
while (fontElement != nullptr) {
sequence->sequence.fonts[i] = fontElement->IntAttribute("FontIdx");
fontElement = fontElement->NextSiblingElement();
i++;
}
sequence->sequence.numFonts = i;
const char* path = child->Attribute("Path");
std::shared_ptr<Ship::File> seqFile;
if (path != nullptr) {
seqFile = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFile(path);
}
if (!streamed) {
sequence->sequence.seqDataSize = seqFile->Buffer.get()->size();
sequence->sequence.seqData = new char[seqFile->Buffer.get()->size()];
memcpy(sequence->sequence.seqData, seqFile->Buffer.get()->data(), seqFile->Buffer.get()->size());
} else {
// setting numFonts to -1 tells the game's audio engine the sound font to used is CRC64 encoded in the font
// indicies.
sequence->sequence.numFonts = -1;
if (path != nullptr) {
sequence->sequence.seqDataSize = seqFile->Buffer.get()->size();
sequence->sequence.seqData = new char[seqFile->Buffer.get()->size()];
memcpy(sequence->sequence.seqData, seqFile->Buffer.get()->data(), seqFile->Buffer.get()->size());
} else {
unsigned int length = child->UnsignedAttribute("Length");
bool looped = child->BoolAttribute("Looped", true);
bool stereo = child->BoolAttribute("Stereo", false);
Ship::BinaryWriter writer = Ship::BinaryWriter();
writer.SetEndianness(Ship::Endianness::Big);
// 1 second worth of ticks can be found by using `ticks = 60 / (bpm * 48)`
// Get the number of ticks per second and then divide the length by this number to get the number of ticks
// for the song.
constexpr uint8_t TEMPO = 1;
constexpr float TEMPO_F = TEMPO;
// Use floats for this first calculation so we can round up
float delayF = length / (60.0f / (TEMPO_F * 48.0f));
// Convert to u16. This way this value is encoded changes depending on the value.
// It can be at most 0xFFFF so store it in a u16 for now.
uint16_t delay;
if (delayF >= 65535.0f) {
delay = 0x7FFF;
} else {
delay = delayF;
}
if (stereo) {
WriteStereoSingleSeq(&writer, delay, TEMPO, looped);
} else {
WriteMonoSingleSeq(&writer, delay, TEMPO, looped);
}
sequence->sequence.seqDataSize = writer.ToVector().size();
sequence->sequence.seqData = new char[sequence->sequence.seqDataSize];
memcpy(sequence->sequence.seqData, writer.ToVector().data(), sequence->sequence.seqDataSize);
}
}
return sequence;
}
} // namespace SOH

View file

@ -2,11 +2,19 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
namespace SOH {
class ResourceFactoryBinaryAudioSequenceV2 : public Ship::ResourceFactoryBinary {
class ResourceFactoryBinaryAudioSequenceV2 : public Ship::ResourceFactoryBinary {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
};
class ResourceFactoryXMLAudioSequenceV0 : public Ship::ResourceFactoryXML {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
} // namespace SOH

View file

@ -1,7 +1,9 @@
#include "soh/resource/importer/AudioSoundFontFactory.h"
#include "soh/resource/type/AudioSoundFont.h"
#include "spdlog/spdlog.h"
#include "libultraship/libultraship.h"
#include "z64.h"
#include "z64audio.h"
#include "Context.h"
#include "resource/archive/Archive.h"
namespace SOH {
std::shared_ptr<Ship::IResource>
@ -35,117 +37,115 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
audioSoundFont->soundFont.numSfx = soundEffectCount;
// 🥁 DRUMS 🥁
audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
// audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums);
audioSoundFont->drumAddresses.reserve(audioSoundFont->soundFont.numDrums);
for (uint32_t i = 0; i < audioSoundFont->soundFont.numDrums; i++) {
Drum drum;
drum.releaseRate = reader->ReadUByte();
drum.pan = reader->ReadUByte();
drum.loaded = reader->ReadUByte();
drum.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
Drum* drum = new Drum;
drum->releaseRate = reader->ReadUByte();
drum->pan = reader->ReadUByte();
drum->loaded = reader->ReadUByte();
drum->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
uint32_t envelopeCount = reader->ReadUInt32();
audioSoundFont->drumEnvelopeCounts.push_back(envelopeCount);
std::vector<AdsrEnvelope> drumEnvelopes;
drumEnvelopes.reserve(audioSoundFont->drumEnvelopeCounts[i]);
for (uint32_t j = 0; j < audioSoundFont->drumEnvelopeCounts.back(); j++) {
AdsrEnvelope env;
drum->envelope = new AdsrEnvelope[envelopeCount];
for (uint32_t j = 0; j < envelopeCount; j++) {
int16_t delay = reader->ReadInt16();
int16_t arg = reader->ReadInt16();
env.delay = BE16SWAP(delay);
env.arg = BE16SWAP(arg);
drumEnvelopes.push_back(env);
drum->envelope[j].delay = BE16SWAP(delay);
drum->envelope[j].arg = BE16SWAP(arg);
}
audioSoundFont->drumEnvelopeArrays.push_back(drumEnvelopes);
drum.envelope = audioSoundFont->drumEnvelopeArrays.back().data();
bool hasSample = reader->ReadInt8();
std::string sampleFileName = reader->ReadString();
drum.sound.tuning = reader->ReadFloat();
drum->sound.tuning = reader->ReadFloat();
if (sampleFileName.empty()) {
drum.sound.sample = nullptr;
drum->sound.sample = nullptr;
} else {
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
drum.sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
drum->sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
}
audioSoundFont->drums.push_back(drum);
audioSoundFont->drumAddresses.push_back(&audioSoundFont->drums.back());
// audioSoundFont->drums.push_back(drum);
// BENTODO clean this up in V3.
if (drum->sound.sample == nullptr) {
delete[] drum->envelope;
delete drum;
audioSoundFont->drumAddresses.push_back(nullptr);
} else {
audioSoundFont->drumAddresses.push_back(drum);
}
}
audioSoundFont->soundFont.drums = audioSoundFont->drumAddresses.data();
// 🎺🎻🎷🎸🎹 INSTRUMENTS 🎹🎸🎷🎻🎺
audioSoundFont->instruments.reserve(audioSoundFont->soundFont.numInstruments);
for (uint32_t i = 0; i < audioSoundFont->soundFont.numInstruments; i++) {
Instrument instrument;
Instrument* instrument = new Instrument;
uint8_t isValidEntry = reader->ReadUByte();
instrument.loaded = reader->ReadUByte();
instrument.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont
instrument->loaded = reader->ReadUByte();
instrument->loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFontByName
instrument.normalRangeLo = reader->ReadUByte();
instrument.normalRangeHi = reader->ReadUByte();
instrument.releaseRate = reader->ReadUByte();
instrument->normalRangeLo = reader->ReadUByte();
instrument->normalRangeHi = reader->ReadUByte();
instrument->releaseRate = reader->ReadUByte();
uint32_t envelopeCount = reader->ReadInt32();
audioSoundFont->instrumentEnvelopeCounts.push_back(envelopeCount);
std::vector<AdsrEnvelope> instrumentEnvelopes;
for (uint32_t j = 0; j < audioSoundFont->instrumentEnvelopeCounts.back(); j++) {
AdsrEnvelope env;
instrument->envelope = new AdsrEnvelope[envelopeCount];
for (uint32_t j = 0; j < envelopeCount; j++) {
int16_t delay = reader->ReadInt16();
int16_t arg = reader->ReadInt16();
env.delay = BE16SWAP(delay);
env.arg = BE16SWAP(arg);
instrumentEnvelopes.push_back(env);
instrument->envelope[j].delay = BE16SWAP(delay);
instrument->envelope[j].arg = BE16SWAP(arg);
}
audioSoundFont->instrumentEnvelopeArrays.push_back(instrumentEnvelopes);
instrument.envelope = audioSoundFont->instrumentEnvelopeArrays.back().data();
bool hasLowNoteSoundFontEntry = reader->ReadInt8();
if (hasLowNoteSoundFontEntry) {
bool hasSampleRef = reader->ReadInt8();
std::string sampleFileName = reader->ReadString();
instrument.lowNotesSound.tuning = reader->ReadFloat();
instrument->lowNotesSound.tuning = reader->ReadFloat();
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
instrument.lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.lowNotesSound.sample = nullptr;
instrument.lowNotesSound.tuning = 0;
instrument->lowNotesSound.sample = nullptr;
instrument->lowNotesSound.tuning = 0;
}
bool hasNormalNoteSoundFontEntry = reader->ReadInt8();
if (hasNormalNoteSoundFontEntry) {
// BENTODO remove in V3
bool hasSampleRef = reader->ReadInt8();
std::string sampleFileName = reader->ReadString();
instrument.normalNotesSound.tuning = reader->ReadFloat();
instrument->normalNotesSound.tuning = reader->ReadFloat();
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
instrument.normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.normalNotesSound.sample = nullptr;
instrument.normalNotesSound.tuning = 0;
instrument->normalNotesSound.sample = nullptr;
instrument->normalNotesSound.tuning = 0;
}
bool hasHighNoteSoundFontEntry = reader->ReadInt8();
if (hasHighNoteSoundFontEntry) {
bool hasSampleRef = reader->ReadInt8();
std::string sampleFileName = reader->ReadString();
instrument.highNotesSound.tuning = reader->ReadFloat();
instrument->highNotesSound.tuning = reader->ReadFloat();
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str());
instrument.highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
instrument->highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
instrument.highNotesSound.sample = nullptr;
instrument.highNotesSound.tuning = 0;
instrument->highNotesSound.sample = nullptr;
instrument->highNotesSound.tuning = 0;
}
audioSoundFont->instruments.push_back(instrument);
audioSoundFont->instrumentAddresses.push_back(isValidEntry ? &audioSoundFont->instruments.back() : nullptr);
if (isValidEntry) {
audioSoundFont->instrumentAddresses.push_back(instrument);
} else {
delete[] instrument->envelope;
delete instrument;
audioSoundFont->instrumentAddresses.push_back(nullptr);
}
}
audioSoundFont->soundFont.instruments = audioSoundFont->instrumentAddresses.data();
@ -169,4 +169,302 @@ ResourceFactoryBinaryAudioSoundFontV2::ReadResource(std::shared_ptr<Ship::File>
return audioSoundFont;
}
int8_t ResourceFactoryXMLSoundFontV0::MediumStrToInt(const char* str, const char* file) {
if (!strcmp("Ram", str)) {
return MEDIUM_RAM;
} else if (!strcmp("Unk", str)) {
return MEDIUM_UNK;
} else if (!strcmp("Cart", str)) {
return MEDIUM_CART;
} else if (!strcmp("Disk", str)) {
return MEDIUM_DISK_DRIVE;
// 4 is skipped
} else {
char buff[2048];
snprintf(buff, 2048, "Bad medium value in %s. Got %s, expected Ram, Unk, Cart, or Disk.", file, str);
throw std::runtime_error(buff);
}
}
int8_t ResourceFactoryXMLSoundFontV0::CachePolicyToInt(const char* str, const char* file) {
if (!strcmp("Temporary", str)) {
return CACHE_TEMPORARY;
} else if (!strcmp("Persistent", str)) {
return CACHE_PERSISTENT;
} else if (!strcmp("Either", str)) {
return CACHE_EITHER;
} else if (!strcmp("Permanent", str)) {
return CACHE_PERMANENT;
} else {
char buff[2048];
snprintf(buff, 2048,
"Bad cache policy value in %s. Got %s, expected Temporary, Persistent, Either, or Permanent.", file,
str);
throw std::runtime_error(buff);
}
}
void ResourceFactoryXMLSoundFontV0::ParseDrums(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
element = element->FirstChildElement();
// No drums
if (element == nullptr) {
soundFont->soundFont.drums = nullptr;
soundFont->soundFont.numDrums = 0;
return;
}
do {
int patch = element->IntAttribute("Patches", -1);
Drum* drum;
if (patch != -1) {
drum = soundFont->drumAddresses[patch];
} else {
drum = new Drum;
}
std::vector<AdsrEnvelope> envelopes;
drum->releaseRate = element->IntAttribute("ReleaseRate");
drum->pan = element->IntAttribute("Pan");
drum->loaded = element->IntAttribute("Loaded");
drum->sound.tuning = element->FloatAttribute("Tuning");
const char* sampleStr = element->Attribute("SampleRef");
if (sampleStr != nullptr && sampleStr[0] != 0) {
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr);
drum->sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
} else {
drum->sound.sample = nullptr;
}
element = element->FirstChildElement();
if (!strcmp(element->Name(), "Envelopes")) {
// element = (tinyxml2::XMLElement*)element->FirstChildElement();
unsigned int envCount = 0;
envelopes = ParseEnvelopes(soundFont, element, &envCount);
element = (tinyxml2::XMLElement*)element->Parent();
soundFont->drumEnvelopeArrays.push_back(envelopes);
// If we are applying a patch the envelopes are already allocated
// TODO revert this if we enable editing envelopes in a patch
if (patch == -1) {
drum->envelope = new AdsrEnvelope[envelopes.size()];
}
memcpy(drum->envelope, envelopes.data(), envelopes.size() * sizeof(AdsrEnvelope));
} else {
drum->envelope = nullptr;
}
if (drum->sound.sample == nullptr) {
soundFont->drumAddresses.push_back(nullptr);
} else {
soundFont->drumAddresses.push_back(drum);
}
element = element->NextSiblingElement();
} while (element != nullptr);
soundFont->soundFont.numDrums = soundFont->drumAddresses.size();
soundFont->soundFont.drums = soundFont->drumAddresses.data();
}
void ResourceFactoryXMLSoundFontV0::ParseInstruments(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
element = element->FirstChildElement();
if (element == nullptr) {
return;
}
do {
int patch = element->IntAttribute("Patches", -1);
Instrument* instrument;
// Same as drums, if applying a patch, don't re-allocate and clear.
if (patch != -1) {
instrument = soundFont->instrumentAddresses[patch];
} else {
instrument = new Instrument;
memset(instrument, 0, sizeof(Instrument));
}
unsigned int envCount = 0;
std::vector<AdsrEnvelope> envelopes;
int isValid = element->BoolAttribute("IsValid");
instrument->loaded = element->IntAttribute("Loaded");
instrument->normalRangeLo = element->IntAttribute("NormalRangeLo");
instrument->normalRangeHi = element->IntAttribute("NormalRangeHi");
instrument->releaseRate = element->IntAttribute("ReleaseRate");
tinyxml2::XMLElement* instrumentElement = element->FirstChildElement();
tinyxml2::XMLElement* instrumentElementCopy = instrumentElement;
if (instrumentElement != nullptr && !strcmp(instrumentElement->Name(), "Envelopes")) {
envelopes = ParseEnvelopes(soundFont, instrumentElement, &envCount);
if (patch == -1) {
instrument->envelope = new AdsrEnvelope[envelopes.size()];
}
memcpy(instrument->envelope, envelopes.data(), envelopes.size() * sizeof(AdsrEnvelope));
instrumentElement = instrumentElement->NextSiblingElement();
}
if (instrumentElement != nullptr && !strcmp("LowNotesSound", instrumentElement->Name())) {
instrument->lowNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
const char* sampleStr = instrumentElement->Attribute("SampleRef");
if (sampleStr != nullptr && sampleStr[0] != 0) {
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
if (res->tuning != -1.0f) {
instrument->lowNotesSound.tuning = res->tuning;
}
instrument->lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
}
instrumentElement = instrumentElement->NextSiblingElement();
}
if (instrumentElement != nullptr && !strcmp("NormalNotesSound", instrumentElement->Name())) {
instrument->normalNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
const char* sampleStr = instrumentElement->Attribute("SampleRef");
if (sampleStr != nullptr && sampleStr[0] != 0) {
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
if (res->tuning != -1.0f) {
instrument->normalNotesSound.tuning = res->tuning;
}
instrument->normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
}
instrumentElement = instrumentElement->NextSiblingElement();
}
if (instrumentElement != nullptr && !strcmp("HighNotesSound", instrumentElement->Name())) {
instrument->highNotesSound.tuning = instrumentElement->FloatAttribute("Tuning");
const char* sampleStr = instrumentElement->Attribute("SampleRef");
if (sampleStr != nullptr && sampleStr[0] != 0) {
std::shared_ptr<SOH::AudioSample> res = static_pointer_cast<SOH::AudioSample>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
if (res->tuning != -1.0f) {
instrument->highNotesSound.tuning = res->tuning;
}
instrument->highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
}
instrumentElement = instrumentElement->NextSiblingElement();
}
// Don't add it to the list if applying a patch
if (patch == -1) {
soundFont->instrumentAddresses.push_back(instrument);
}
element = instrumentElementCopy;
element = (tinyxml2::XMLElement*)element->Parent();
element = element->NextSiblingElement();
} while (element != nullptr);
soundFont->soundFont.instruments = soundFont->instrumentAddresses.data();
soundFont->soundFont.numInstruments = soundFont->instrumentAddresses.size();
}
void ResourceFactoryXMLSoundFontV0::ParseSfxTable(AudioSoundFont* soundFont, tinyxml2::XMLElement* element) {
size_t count = element->IntAttribute("Count");
element = element->FirstChildElement();
while (element != nullptr) {
int patch = element->IntAttribute("Patches", -1);
SoundFontSound sound = {};
const char* sampleStr = element->Attribute("SampleRef");
// Insert an empty sound effect. The game assumes the empty slots are
// filled so we can't just skip them
if (sampleStr == nullptr)
goto skip;
sound.tuning = element->FloatAttribute("Tuning");
if (sampleStr[0] != 0) {
auto res = static_pointer_cast<SOH::AudioSample>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleStr));
if (res->tuning != -1.0f) {
sound.tuning = res->tuning;
}
sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr);
}
skip:
element = element->NextSiblingElement();
if (patch != -1) {
soundFont->soundEffects[patch] = sound;
} else {
soundFont->soundEffects.push_back(sound);
}
}
soundFont->soundFont.soundEffects = soundFont->soundEffects.data();
soundFont->soundFont.numSfx = soundFont->soundEffects.size();
}
std::vector<AdsrEnvelope> SOH::ResourceFactoryXMLSoundFontV0::ParseEnvelopes(AudioSoundFont* soundFont,
tinyxml2::XMLElement* element,
unsigned int* count) {
std::vector<AdsrEnvelope> envelopes;
unsigned int total = 0;
element = element->FirstChildElement("Envelope");
while (element != nullptr) {
AdsrEnvelope env = {
.delay = (s16)element->IntAttribute("Delay"),
.arg = (s16)element->IntAttribute("Arg"),
};
env.delay = BSWAP16(env.delay);
env.arg = BSWAP16(env.arg);
envelopes.emplace_back(env);
element = element->NextSiblingElement("Envelope");
total++;
}
*count = total;
return envelopes;
}
std::shared_ptr<Ship::IResource>
ResourceFactoryXMLSoundFontV0::ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (!FileHasValidFormatAndReader(file, initData)) {
return nullptr;
}
auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
const char* patch = child->Attribute("Patches");
std::shared_ptr<Ship::IResource> sf;
std::shared_ptr<AudioSoundFont> audioSoundFont;
// If we are patching an existing SF, load the original, otherwise create and clear a new one.
if (patch != nullptr) {
std::string origName = "audio/fonts/";
origName += patch;
audioSoundFont = dynamic_pointer_cast<AudioSoundFont>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(origName));
} else {
audioSoundFont = std::make_shared<AudioSoundFont>(initData);
memset(&audioSoundFont->soundFont, 0, sizeof(audioSoundFont->soundFont));
}
// Header data
audioSoundFont->soundFont.fntIndex = child->IntAttribute("Num", 0);
const char* mediumStr = child->Attribute("Medium");
audioSoundFont->medium = MediumStrToInt(mediumStr, initData->Path.c_str());
const char* cachePolicyStr = child->Attribute("CachePolicy");
audioSoundFont->cachePolicy = CachePolicyToInt(cachePolicyStr, initData->Path.c_str());
audioSoundFont->data1 = child->IntAttribute("Data1");
audioSoundFont->data2 = child->IntAttribute("Data2");
audioSoundFont->data3 = child->IntAttribute("Data3");
audioSoundFont->soundFont.sampleBankId1 = audioSoundFont->data1 >> 8;
audioSoundFont->soundFont.sampleBankId2 = audioSoundFont->data1 & 0xFF;
child = (tinyxml2::XMLElement*)child->FirstChildElement();
while (child != nullptr) {
const char* name = child->Name();
if (!strcmp(name, "Drums")) {
ParseDrums(audioSoundFont.get(), child);
} else if (!strcmp(name, "Instruments")) {
ParseInstruments(audioSoundFont.get(), child);
} else if (!strcmp(name, "SfxTable")) {
ParseSfxTable(audioSoundFont.get(), child);
}
child = child->NextSiblingElement();
}
return audioSoundFont;
}
} // namespace SOH

View file

@ -2,11 +2,29 @@
#include "Resource.h"
#include "ResourceFactoryBinary.h"
#include "ResourceFactoryXML.h"
#include "soh/resource/type/AudioSoundFont.h"
namespace SOH {
class ResourceFactoryBinaryAudioSoundFontV2 : public Ship::ResourceFactoryBinary {
class ResourceFactoryBinaryAudioSoundFontV2 : public Ship::ResourceFactoryBinary {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
};
class ResourceFactoryXMLSoundFontV0 : public Ship::ResourceFactoryXML {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
static int8_t MediumStrToInt(const char* str, const char* file);
static int8_t CachePolicyToInt(const char* str, const char* file);
private:
void ParseDrums(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
void ParseInstruments(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
void ParseSfxTable(AudioSoundFont* soundFont, tinyxml2::XMLElement* element);
std::vector<AdsrEnvelope> ParseEnvelopes(AudioSoundFont* soundFont, tinyxml2::XMLElement* element,
unsigned int* count);
};
} // namespace SOH

View file

@ -1,11 +1,19 @@
#include "AudioSample.h"
namespace SOH {
Sample* AudioSample::GetPointer() {
AudioSample::~AudioSample() {
if (sample.book != nullptr && sample.book->book != nullptr) {
delete[] sample.book->book;
}
if (sample.sampleAddr != nullptr) {
delete[] sample.sampleAddr;
}
}
Sample* AudioSample::GetPointer() {
return &sample;
}
}
size_t AudioSample::GetPointerSize() {
size_t AudioSample::GetPointerSize() {
return sizeof(Sample);
}
}
} // namespace SOH

View file

@ -1,62 +1,60 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Resource.h"
#include <libultraship/libultra/types.h>
namespace SOH {
typedef struct {
/* 0x00 */ uintptr_t start;
/* 0x04 */ uintptr_t end;
typedef struct {
/* 0x00 */ u32 start;
/* 0x04 */ u32 end;
/* 0x08 */ u32 count;
/* 0x0C */ char unk_0C[0x4];
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned
} AdpcmLoop; // size = 0x30 (or 0x10)
} AdpcmLoop; // size = 0x30 (or 0x10)
typedef struct {
typedef struct {
/* 0x00 */ s32 order;
/* 0x04 */ s32 npredictors;
/* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned
} AdpcmBook; // s
} AdpcmBook; // s
typedef struct {
typedef struct Sample {
union {
struct {
/* 0x00 */ u32 codec : 4;
/* 0x00 */ u32 medium : 2;
/* 0x00 */ u32 unk_bit26 : 1;
/* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret
/* 0x01 */ u32 size : 24;
///* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
};
u32 asU32;
};
/* 0x1 */ u32 size; // Size of the sample
u32 fileSize;
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either
// rom or ram
/* 0x8 */ AdpcmLoop*
loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram
/* 0xC */ AdpcmBook*
book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram
} Sample; // size = 0x10
/* 0x04 */ u8* sampleAddr;
/* 0x08 */ AdpcmLoop* loop;
/* 0x0C */ AdpcmBook* book;
u32 sampleRateMagicValue; // For wav samples only...
s32 sampleRate; // For wav samples only...
} Sample; // size = 0x10
class AudioSample : public Ship::Resource<Sample> {
class AudioSample : public Ship::Resource<Sample> {
public:
using Resource::Resource;
AudioSample() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSample();
Sample* GetPointer();
size_t GetPointerSize();
Sample sample;
std::vector<uint8_t> audioSampleData;
AdpcmLoop loop;
uint32_t loopStateCount;
AdpcmBook book;
uint32_t bookDataCount;
std::vector<int16_t> bookData;
};
// Only applies to streamed audio
float tuning = -1.0f;
};
}; // namespace SOH

View file

@ -2,11 +2,17 @@
namespace SOH {
Sequence* AudioSequence::GetPointer() {
Sequence* AudioSequence::GetPointer() {
return &sequence;
}
}
size_t AudioSequence::GetPointerSize() {
size_t AudioSequence::GetPointerSize() {
return sizeof(Sequence);
}
}
AudioSequence::~AudioSequence() {
delete[] sequence.seqData;
sequence.seqData = nullptr;
}
} // namespace SOH

View file

@ -1,33 +1,31 @@
#pragma once
#include <cstdint>
#include <vector>
#include "Resource.h"
#include <libultraship/libultra/types.h>
namespace SOH {
typedef struct {
typedef struct {
char* seqData;
int32_t seqDataSize;
uint32_t seqDataSize;
uint16_t seqNumber;
uint8_t medium;
uint8_t cachePolicy;
int32_t numFonts;
uint32_t numFonts;
uint8_t fonts[16];
} Sequence;
} Sequence;
class AudioSequence : public Ship::Resource<Sequence> {
class AudioSequence : public Ship::Resource<Sequence> {
public:
using Resource::Resource;
AudioSequence() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSequence();
Sequence* GetPointer();
size_t GetPointerSize();
Sequence sequence;
std::vector<char> sequenceData;
};
};
}; // namespace SOH

View file

@ -1,11 +1,28 @@
#include "AudioSoundFont.h"
namespace SOH {
SoundFont* AudioSoundFont::GetPointer() {
return &soundFont;
}
size_t AudioSoundFont::GetPointerSize() {
AudioSoundFont::~AudioSoundFont() {
for (auto i : instrumentAddresses) {
if (i != nullptr) {
delete[] i->envelope;
delete i;
}
}
for (auto d : drumAddresses) {
if (d != nullptr) {
delete[] d->envelope;
delete d;
}
}
}
SoundFont* AudioSoundFont::GetPointer() {
return &soundFont;
}
size_t AudioSoundFont::GetPointerSize() {
return sizeof(SoundFont);
}
}
} // namespace SOH

View file

@ -8,20 +8,20 @@
namespace SOH {
typedef struct {
typedef struct {
/* 0x0 */ s16 delay;
/* 0x2 */ s16 arg;
} AdsrEnvelope; // size = 0x4
} AdsrEnvelope; // size = 0x4
typedef struct {
typedef struct {
/* 0x00 */ Sample* sample;
/* 0x04 */ union {
u32 tuningAsU32;
f32 tuning; // frequency scale factor
};
} SoundFontSound; // size = 0x8
} SoundFontSound; // size = 0x8
typedef struct {
typedef struct {
/* 0x00 */ u8 loaded;
/* 0x01 */ u8 normalRangeLo;
/* 0x02 */ u8 normalRangeHi;
@ -30,17 +30,17 @@ typedef struct {
/* 0x08 */ SoundFontSound lowNotesSound;
/* 0x10 */ SoundFontSound normalNotesSound;
/* 0x18 */ SoundFontSound highNotesSound;
} Instrument; // size = 0x20
} Instrument; // size = 0x20
typedef struct {
typedef struct {
/* 0x00 */ u8 releaseRate;
/* 0x01 */ u8 pan;
/* 0x02 */ u8 loaded;
/* 0x04 */ SoundFontSound sound;
/* 0x14 */ AdsrEnvelope* envelope;
} Drum; // size = 0x14
} Drum; // size = 0x14
typedef struct {
typedef struct {
/* 0x00 */ u8 numInstruments;
/* 0x01 */ u8 numDrums;
/* 0x02 */ u8 sampleBankId1;
@ -50,14 +50,15 @@ typedef struct {
/* 0x0C */ Drum** drums;
/* 0x10 */ SoundFontSound* soundEffects;
s32 fntIndex;
} SoundFont; // size = 0x14
} SoundFont; // size = 0x14
class AudioSoundFont : public Ship::Resource<SoundFont> {
class AudioSoundFont : public Ship::Resource<SoundFont> {
public:
using Resource::Resource;
AudioSoundFont() : Resource(std::shared_ptr<Ship::ResourceInitData>()) {
}
~AudioSoundFont();
SoundFont* GetPointer();
size_t GetPointerSize();
@ -68,18 +69,13 @@ class AudioSoundFont : public Ship::Resource<SoundFont> {
uint16_t data2;
uint16_t data3;
std::vector<Drum> drums;
std::vector<Drum*> drumAddresses;
std::vector<uint32_t> drumEnvelopeCounts;
std::vector<std::vector<AdsrEnvelope>> drumEnvelopeArrays;
std::vector<Instrument> instruments;
std::vector<Instrument*> instrumentAddresses;
std::vector<uint32_t> instrumentEnvelopeCounts;
std::vector<std::vector<AdsrEnvelope>> instrumentEnvelopeArrays;
std::vector<SoundFontSound> soundEffects;
SoundFont soundFont;
};
};
}; // namespace SOH

View file

@ -41,7 +41,7 @@ void func_800DDE3C(void) {
void AudioHeap_ResetLoadStatus(void) {
s32 i;
for (i = 0; i < 0x30; i++) {
for (i = 0; i < fontMapSize; i++) {
if (gAudioContext.fontLoadStatus[i] != 5) {
gAudioContext.fontLoadStatus[i] = 0;
}
@ -940,7 +940,7 @@ void AudioHeap_Init(void) {
reverb->sample.sampleAddr = (u8*)reverb->leftRingBuf;
reverb->loop.start = 0;
reverb->loop.count = 1;
reverb->loop.end = reverb->windowSize;
reverb->loop.loopEnd = reverb->windowSize;
if (reverb->downsampleRate != 1) {
reverb->unk_0E = 0x8000 / reverb->downsampleRate;

View file

@ -8,6 +8,10 @@
#include "soh/Enhancements/audio/AudioCollection.h"
#include "soh/Enhancements/audio/AudioEditor.h"
#include "soh/ResourceManagerHelpers.h"
#include <stdio.h>
#ifdef _MSC_VER
#define strdup _strdup
#endif
#define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status))
#define ASYNC_TBLTYPE(v) ((u8)(v >> 16))
@ -82,7 +86,8 @@ char** sequenceMap;
size_t sequenceMapSize;
// A map of authentic sequence IDs to their cache policies, for use with sequence swapping.
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
char* fontMap[256];
size_t fontMapSize;
char** fontMap;
uintptr_t fontStart;
uint32_t fontOffsets[8192];
@ -419,7 +424,7 @@ void AudioLoad_SyncLoadSeqParts(s32 seqId, s32 arg1) {
s32 AudioLoad_SyncLoadSample(SoundFontSample* sample, s32 fontId) {
void* sampleAddr;
if (sample->unk_bit25 == 1) {
if (sample->isRelocated == 1) {
if (sample->medium != MEDIUM_RAM) {
sampleAddr = AudioHeap_AllocSampleCache(sample->size, fontId, (void*)sample->sampleAddr, sample->medium,
CACHE_PERSISTENT);
@ -701,7 +706,7 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
sampleBankId1 = sf->sampleBankId1;
sampleBankId2 = sf->sampleBankId2;
@ -759,7 +764,7 @@ uintptr_t AudioLoad_SyncLoad(u32 tableType, u32 id, s32* didAllocate) {
cachePolicy = sData.cachePolicy;
romAddr = 0;
} else if (tableType == FONT_TABLE) {
fnt = ResourceMgr_LoadAudioSoundFont(fontMap[id]);
fnt = ResourceMgr_LoadAudioSoundFontByName(fontMap[id]);
size = sizeof(SoundFont);
medium = 2;
cachePolicy = 0;
@ -887,6 +892,7 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) {
}
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo) {
return;
uintptr_t reloc;
uintptr_t reloc2;
Instrument* inst;
@ -898,7 +904,7 @@ void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, RelocInfo* relocInfo
s32 numInstruments = 0;
s32 numSfx = 0;
sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
@ -1247,12 +1253,13 @@ int strcmp_sort(const void* str1, const void* str2) {
}
void AudioLoad_Init(void* heap, size_t heapSize) {
char pad[0x48];
s32 pad1[9];
s32 numFonts;
void* temp_v0_3;
s32 pad2[2];
u8* audioCtxPtr;
void* addr;
s32 i;
u64* heapP;
s16* u2974p;
s32 j;
D_801755D0 = NULL;
gAudioContext.resetTimer = 0;
@ -1266,10 +1273,12 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.unk_2960 = 20.03042f;
gAudioContext.refreshRate = 50;
break;
case OS_TV_MPAL:
gAudioContext.unk_2960 = 16.546f;
gAudioContext.refreshRate = 60;
break;
case OS_TV_NTSC:
default:
gAudioContext.unk_2960 = 16.713f;
@ -1278,7 +1287,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
Audio_InitMesgQueues();
for (i = 0; i < 3; i++) {
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) {
gAudioContext.aiBufLengths[i] = 0xA0;
}
@ -1289,12 +1298,14 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.currTask = NULL;
gAudioContext.rspTask[0].task.t.data_size = 0;
gAudioContext.rspTask[1].task.t.data_size = 0;
osCreateMesgQueue(&gAudioContext.syncDmaQueue, &gAudioContext.syncDmaMesg, 1);
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf, 0x40);
osCreateMesgQueue(&gAudioContext.currAudioFrameDmaQueue, gAudioContext.currAudioFrameDmaMesgBuf,
ARRAY_COUNT(gAudioContext.currAudioFrameDmaMesgBuf));
osCreateMesgQueue(&gAudioContext.externalLoadQueue, gAudioContext.externalLoadMesgBuf,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
osCreateMesgQueue(&gAudioContext.preloadSampleQueue, gAudioContext.preloadSampleMesgBuf,
ARRAY_COUNT(gAudioContext.externalLoadMesgBuf));
ARRAY_COUNT(gAudioContext.preloadSampleMesgBuf));
gAudioContext.curAudioFrameDmaCount = 0;
gAudioContext.sampleDmaCount = 0;
gAudioContext.cartHandle = osCartRomInit();
@ -1304,20 +1315,24 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.audioHeapSize = D_8014A6C4.heapSize;
} else {
void** hp = &heap;
gAudioContext.audioHeap = *hp;
gAudioContext.audioHeapSize = heapSize;
}
for (i = 0; i < gAudioContext.audioHeapSize / 8; i++) {
for (i = 0; i < ((s32)gAudioContext.audioHeapSize / (s32)sizeof(u64)); i++) {
((u64*)gAudioContext.audioHeap)[i] = 0;
}
// Main Pool Split (split entirety of audio heap into initPool and sessionPool)
AudioHeap_InitMainPools(D_8014A6C4.initPoolSize);
for (i = 0; i < 3; i++) {
// Initialize the audio interface buffers
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBuffers); i++) {
gAudioContext.aiBuffers[i] = AudioHeap_AllocZeroed(&gAudioContext.audioInitPool, AIBUF_LEN * sizeof(s16));
}
// Connect audio tables to their tables in memory
// gAudioContext.sequenceTable = (AudioTable*)gSequenceTable;
// gAudioContext.soundFontTable = (AudioTable*)gSoundFontTable;
// gAudioContext.sampleBankTable = (AudioTable*)gSampleBankTable;
@ -1325,31 +1340,60 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
// gAudioContext.numSequences = gAudioContext.sequenceTable->numEntries;
gAudioContext.audioResetSpecIdToLoad = 0;
gAudioContext.resetStatus = 1;
gAudioContext.resetStatus = 1; // Set reset to immediately initialize the audio heap
AudioHeap_ResetStep();
// Initialize audio tables
// AudioLoad_InitTable(gAudioContext.sequenceTable, SEGMENT_ROM_START(Audioseq), 0);
// AudioLoad_InitTable(gAudioContext.soundFontTable, SEGMENT_ROM_START(Audiobank), 0);
// AudioLoad_InitTable(gAudioContext.sampleBankTable, SEGMENT_ROM_START(Audiotable), 0);
// #region 2S2H [Port] Audio in the archive and custom sequences
// Only load the original sequences right now because custom songs may require data from sound fonts and samples
int seqListSize = 0;
int customSeqListSize = 0;
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize);
sequenceMapSize = (size_t)(AudioCollection_SequenceMapSize() + customSeqListSize);
sequenceMap = malloc(sequenceMapSize * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize * sizeof(char*));
sequenceMapSize = (size_t)(seqListSize + customSeqListSize );
sequenceMap = malloc((sequenceMapSize + 0xF) * sizeof(char*));
gAudioContext.seqLoadStatus = malloc(sequenceMapSize);
memset(gAudioContext.seqLoadStatus, 5, sequenceMapSize);
for (size_t i = 0; i < seqListSize; i++) {
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
char* str = malloc(strlen(seqList[i]) + 1);
strcpy(str, seqList[i]);
sequenceMap[sDat.seqNumber] = str;
sequenceMap[sDat.seqNumber] = strdup(seqList[i]);
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
}
free(seqList);
int startingSeqNum = MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
// 2S2H [Streamed Audio] We need to load the custom songs after the fonts because streamed songs will use a hash to
// find its soundfont
int fntListSize = 0;
int customFntListSize = 0;
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
char** customFntList = ResourceMgr_ListFiles("custom/fonts/*", &customFntListSize);
gAudioContext.fontLoadStatus = malloc(customFntListSize + fntListSize);
fontMap = calloc(customFntListSize + fntListSize, sizeof(char*));
fontMapSize = customFntListSize + fntListSize;
for (int i = 0; i < fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fntList[i]);
fontMap[sf->fntIndex] = strdup(fntList[i]);
}
free(fntList);
int customFontStart = fntListSize;
for (int i = customFontStart; i < customFntListSize + fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(customFntList[i - customFontStart]);
sf->fntIndex = i;
fontMap[i] = strdup(customFntList[i - customFontStart]);
}
free(customFntList);
// 2S2H Port I think we need to take use seqListSize because entry 0x7A is missing.
int startingSeqNum = seqListSize; // MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence
qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort);
// Because AudioCollection's sequenceMap actually has more than sequences (including instruments from 130-135 and
@ -1361,48 +1405,61 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) {
// ensure that what would be the next sequence number is actually unassigned in AudioCollection
int j = i - startingSeqNum;
SequenceData* sDat = ResourceMgr_LoadSeqPtrByName(customSeqList[j]);
if (sDat->numFonts == -1) {
uint64_t crc;
memcpy(&crc, sDat->fonts, sizeof(uint64_t));
const char* res = ResourceGetNameByCrc(crc);
if (res == NULL) {
// Passing a null buffer and length of 0 to snprintf will return the required numbers of characters the
// buffer needs to be.
int len =
snprintf(NULL, 0, "Could not find sound font for sequence %s. It will not be in the audio editor.",
customSeqList[j]);
char* error = malloc(len + 1);
snprintf(error, len, "Could not find sound font for sequence %s. It will not be in the audio editor.",
customSeqList[j]);
LUSLOG_ERROR("%s", error);
Messagebox_ShowErrorBox("Invalid Sequence", error);
free(error);
continue;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(res);
memset(&sDat->fonts[0], 0, sizeof(sDat->fonts));
sDat->fonts[0] = sf->fntIndex;
sDat->numFonts = 1;
}
while (AudioCollection_HasSequenceNum(seqNum)) {
seqNum++;
}
int j = i - startingSeqNum;
AudioCollection_AddToCollection(customSeqList[j], seqNum);
SequenceData sDat = ResourceMgr_LoadSeqByName(customSeqList[j]);
sDat.seqNumber = seqNum;
char* str = malloc(strlen(customSeqList[j]) + 1);
strcpy(str, customSeqList[j]);
sequenceMap[sDat.seqNumber] = str;
sDat->seqNumber = seqNum;
printf("%d\n", seqNum);
sequenceMap[sDat->seqNumber] = strdup(customSeqList[j]);
seqNum++;
}
free(customSeqList);
int fntListSize = 0;
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
for (int i = 0; i < fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fntList[i]);
char* str = malloc(strlen(fntList[i]) + 1);
strcpy(str, fntList[i]);
fontMap[sf->fntIndex] = str;
}
numFonts = fntListSize;
free(fntList);
// #end region
gAudioContext.soundFonts = AudioHeap_Alloc(&gAudioContext.audioInitPool, numFonts * sizeof(SoundFont));
if (temp_v0_3 = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), temp_v0_3 == NULL) {
if (addr = AudioHeap_Alloc(&gAudioContext.audioInitPool, D_8014A6C4.permanentPoolSize), addr == NULL) {
// cast away const from D_8014A6C4
// *((u32*)&D_8014A6C4.permanentPoolSize) = 0;
*((u32*)&D_8014A6C4.permanentPoolSize) = 0;
}
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, temp_v0_3, D_8014A6C4.permanentPoolSize);
AudioHeap_AllocPoolInit(&gAudioContext.permanentPool, addr, D_8014A6C4.permanentPoolSize);
gAudioContextInitalized = true;
osSendMesg32(gAudioContext.taskStartQueueP, gAudioContext.totalTaskCnt, OS_MESG_NOBLOCK);
osSendMesg(gAudioContext.taskStartQueueP, OS_MESG_32(gAudioContext.totalTaskCnt), OS_MESG_NOBLOCK);
}
void AudioLoad_InitSlowLoads(void) {
@ -2059,7 +2116,7 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, RelocInfo* relocInfo
gAudioContext.numUsedSamples = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
@ -2188,7 +2245,7 @@ void AudioLoad_LoadPermanentSamples(void) {
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioContext.permanentCache[i].id);
// fontId = gAudioContext.permanentCache[i].id;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
relocInfo.sampleBankId1 = sf->sampleBankId1;
relocInfo.sampleBankId2 = sf->sampleBankId2;

View file

@ -147,6 +147,7 @@ void Audio_NoteInit(Note* note) {
note->noteSubEu = gDefaultNoteSub;
}
extern void aOPUSFree(struct OggOpusFile* opusFile);
void Audio_NoteDisable(Note* note) {
if (note->noteSubEu.bitField0.needsInit == true) {
note->noteSubEu.bitField0.needsInit = false;
@ -159,6 +160,10 @@ void Audio_NoteDisable(Note* note) {
note->playbackState.prevParentLayer = NO_LAYER;
note->playbackState.adsr.action.s.state = ADSR_STATE_DISABLED;
note->playbackState.adsr.current = 0;
if (note->synthesisState.opusFile != NULL) {
aOPUSFree(note->synthesisState.opusFile);
note->synthesisState.opusFile = NULL;
}
}
void Audio_ProcessNotes(void) {
@ -293,13 +298,6 @@ void Audio_ProcessNotes(void) {
f32 resampRate = gAudioContext.audioBufferParameters.resampleRate;
// CUSTOM SAMPLE CHECK
if (!noteSubEu2->bitField1.isSyntheticWave && noteSubEu2->sound.soundFontSound != NULL &&
noteSubEu2->sound.soundFontSound->sample != NULL &&
noteSubEu2->sound.soundFontSound->sample->sampleRateMagicValue == 'RIFF') {
resampRate = CALC_RESAMPLE_FREQ(noteSubEu2->sound.soundFontSound->sample->sampleRate);
}
subAttrs.frequency *= resampRate;
subAttrs.velocity *= scale;
@ -335,7 +333,7 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) {
}
int instCnt = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (instId >= sf->numInstruments)
return NULL;
@ -362,7 +360,7 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (drumId < sf->numDrums) {
drum = sf->drums[drumId];
}
@ -386,7 +384,7 @@ SoundFontSound* Audio_GetSfx(s32 fontId, s32 sfxId) {
return NULL;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]);
SoundFont* sf = ResourceMgr_LoadAudioSoundFontByName(fontMap[fontId]);
if (sfxId < sf->numSfx) {
sfx = &sf->soundEffects[sfxId];
}

View file

@ -789,7 +789,7 @@ s32 AudioSeq_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd) {
layer->freqScale *= layer->unk_34;
if (layer->delay == 0) {
if (layer->sound != NULL) {
time = (f32)layer->sound->sample->loop->end;
time = (f32)layer->sound->sample->loop->loopEnd;
} else {
time = 0.0f;
}

View file

@ -761,7 +761,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
audioFontSample = noteSubEu->sound.soundFontSound->sample;
loopInfo = audioFontSample->loop;
loopEndPos = loopInfo->end;
loopEndPos = loopInfo->loopEnd;
sampleAddr = audioFontSample->sampleAddr;
resampledTempLen = 0;
@ -853,14 +853,28 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
s5 = samplesLenAdjusted;
goto skip;
case CODEC_S16:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, (samplesLenAdjusted * 2) + 0x20);
AudioSynth_LoadBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE, ALIGN16(nSamplesToLoad * 2),
audioFontSample->sampleAddr + (synthState->samplePosInt * 2));
case CODEC_OPUS:
AudioSynth_ClearBuffer(cmd++, DMEM_UNCOMPRESSED_NOTE,
(samplesLenAdjusted + 16) * 2);
flags = A_CONTINUE;
skipBytes = 0;
nSamplesProcessed = samplesLenAdjusted;
s5 = samplesLenAdjusted;
size_t bytesToRead;
nSamplesProcessed += samplesLenAdjusted;
if (((synthState->samplePosInt * 2) + (samplesLenAdjusted)*2) < audioFontSample->size) {
bytesToRead = (samplesLenAdjusted)*2;
} else {
bytesToRead = audioFontSample->size - (synthState->samplePosInt * 2);
}
// 2S2H [Port] [Custom audio] Handle decoding OPUS data
if (audioFontSample->codec == CODEC_OPUS) {
aOPUSdecImpl(sampleAddr, DMEM_UNCOMPRESSED_NOTE, bytesToRead, &synthState->opusFile,
synthState->samplePosInt, audioFontSample->fileSize);
} else {
aLoadBuffer(cmd++, sampleAddr + (synthState->samplePosInt * 2), DMEM_UNCOMPRESSED_NOTE,
bytesToRead);
}
goto skip;
case CODEC_REVERB:
break;
@ -886,6 +900,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
sampleDataStartPad = (uintptr_t)sampleData & 0xF;
aligned = ALIGN16((nFramesToDecode * frameSize) + 16);
addr = DMEM_COMPRESSED_ADPCM_DATA - aligned;
aLoadBuffer(cmd++, sampleData - sampleDataStartPad, addr, aligned);
} else {
nSamplesToDecode = 0;
@ -893,7 +908,7 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSubEu, NoteSynthesisS
}
if (synthState->restart) {
aSetLoop(cmd++, audioFontSample->loop->state);
aSetLoop(cmd++, audioFontSample->loop->predictorState);
flags = A_LOOP;
synthState->restart = false;
}

View file

@ -792,7 +792,7 @@ s32 func_800E6590(s32 playerIdx, s32 arg1, s32 arg2) {
if (sound == NULL) {
return 0;
}
loopEnd = sound->sample->loop->end;
loopEnd = sound->sample->loop->loopEnd;
samplePos = note->synthesisState.samplePosInt;
return loopEnd - samplePos;
}

View file

@ -899,33 +899,25 @@ void AnimationContext_SetLoadFrame(PlayState* play, LinkAnimationHeader* animati
if (ResourceMgr_OTRSigCheck(animation) != 0)
animation = ResourceMgr_LoadAnimByName(animation);
LinkAnimationHeader* linkAnimHeader = SEGMENTED_TO_VIRTUAL(animation);
LinkAnimationHeader* playerAnimHeader = animation;
Vec3s* ram = frameTable;
osCreateMesgQueue(&entry->data.load.msgQueue, &entry->data.load.msg, 1);
char animPath[2048];
snprintf(animPath, sizeof(animPath), "misc/link_animetion/gPlayerAnimData_%06X",
(((uintptr_t)linkAnimHeader->segment - 0x07000000)));
// osCreateMesgQueue(&entry->data.load.msgQueue, &entry->data.load.msg, 1);
//
// char animPath[2048];
//
// snprintf(animPath, sizeof(animPath), "misc/link_animetion/gPlayerAnimData_%06X",
// (((uintptr_t)linkAnimHeader->segmentVoid - 0x07000000)));
//
// printf("Streaming %s, seg = %08X\n", animPath, linkAnimHeader->segment);
s16* animData = ResourceMgr_LoadPlayerAnimByName(animPath);
s16* animData = /* ResourceMgr_LoadPlayerAnimByName*/ (animation->segment);
// 2S2H [Port] sometimes a HESS can set a negative frame value from a negative playback speed. When converted to
// a signed value this will cause a crash due to copying way much data.
if (frame < 0) {
frame = 0;
}
memcpy(ram, (uintptr_t)animData + (((sizeof(Vec3s) * limbCount + 2) * frame)), sizeof(Vec3s) * limbCount + 2);
/*u32* ramPtr = (u32*)ram;
for (int i = 0; i < 1024; i++)
{
ramPtr[i] = i * 7;
}*/
// DmaMgr_SendRequest2(&entry->data.load.req, ram,
// LINK_ANIMATION_OFFSET(linkAnimHeader->segment, ((sizeof(Vec3s) * limbCount + 2) * frame)),
// sizeof(Vec3s) * limbCount + 2, 0, &entry->data.load.msgQueue, NULL, __FILE__,
//__LINE__);
}
}