summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2025-02-02 23:34:11 -0600
committerKiritoDv <kiritodev01@gmail.com>2025-02-02 23:34:11 -0600
commit4b00d75517fbb22e08b409a08256f3e09c212c03 (patch)
tree49822f8f5353366056636af28f702dcf67994c74
parent1f79880fd55564d75d0d5225cd5842261abe37de (diff)
First implementation of louist system
-rw-r--r--.github/workflows/linux.yml2
-rw-r--r--.github/workflows/mac.yml2
-rw-r--r--.github/workflows/main.yml4
-rw-r--r--CMakeLists.txt26
-rw-r--r--assets/yaml/cn/rev0/ast_audio.yaml31
-rw-r--r--cmake/modules/FindOgg.cmake61
-rw-r--r--cmake/modules/FindVorbis.cmake197
-rw-r--r--docs/BUILDING.md18
-rw-r--r--src/audio/audio_synthesis.c3
-rw-r--r--src/port/Engine.cpp5
-rw-r--r--src/port/resource/importers/audio/SampleFactory.cpp242
-rw-r--r--src/port/resource/importers/audio/SampleFactory.h12
m---------tools/Torch0
13 files changed, 565 insertions, 38 deletions
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 251ddcc8..c0b68d29 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -14,7 +14,7 @@ jobs:
- name: Update machine
run: sudo apt update
- name: Install dependencies
- run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
+ run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev libvorbis-dev
- name: Install latest SDL
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml
index 2cc8c768..f70c52e2 100644
--- a/.github/workflows/mac.yml
+++ b/.github/workflows/mac.yml
@@ -12,7 +12,7 @@ jobs:
with:
submodules: recursive
- name: Install dependencies
- run: brew install sdl2 libpng glew ninja cmake libzip nlohmann-json tinyxml2 spdlog
+ run: brew install sdl2 libpng glew ninja cmake libzip nlohmann-json tinyxml2 spdlog vorbis-tools
- name: Build
run: |
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 160e17e2..54ac983f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -81,7 +81,7 @@ jobs:
with:
submodules: recursive
- name: Install dependencies
- run: brew install sdl2 libpng glew ninja cmake libzip nlohmann-json tinyxml2 spdlog
+ run: brew install sdl2 libpng glew ninja cmake libzip nlohmann-json tinyxml2 spdlog vorbis-tools
- name: Build
run: |
cmake -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE=Release
@@ -115,7 +115,7 @@ jobs:
- name: Update machine
run: sudo apt update
- name: Install dependencies
- run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
+ run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev libvorbis-dev
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.14
with:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 557a23c4..ffe5a58f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR)
# Set the project version and language
project(Starship VERSION 0.1.0 LANGUAGES C CXX ASM)
+include(FetchContent)
if(APPLE)
enable_language(OBJCXX)
@@ -26,7 +27,7 @@ include(cmake/automate-vcpkg.cmake)
set(VCPKG_TRIPLET x64-windows-static)
set(VCPKG_TARGET_TRIPLET x64-windows-static)
vcpkg_bootstrap()
-vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 glew glfw3 nlohmann-json tinyxml2 spdlog)
+vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
@@ -188,6 +189,13 @@ if (MSVC)
endif()
endif()
+FetchContent_Declare(
+ dr_libs
+ GIT_REPOSITORY https://github.com/mackron/dr_libs.git
+ GIT_TAG da35f9d6c7374a95353fd1df1d394d44ab66cf01
+)
+FetchContent_MakeAvailable(dr_libs)
+
#==============================================================================#
# Libultraship Integration #
#==============================================================================#
@@ -224,6 +232,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/libultraship/src/graphic
${SDL2_INCLUDE_DIRS}
${GLEW_INCLUDE_DIRS}
+ ${dr_libs_SOURCE_DIR}
)
add_subdirectory(libultraship ${CMAKE_CURRENT_SOURCE_DIR}/libultraship)
@@ -280,8 +289,17 @@ endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ find_package(Ogg CONFIG REQUIRED)
+ link_libraries(Ogg::ogg)
+
+ find_package(Vorbis CONFIG REQUIRED)
+ link_libraries(Vorbis::vorbisfile)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"$<$<BOOL:${USE_NETWORKING}>:SDL2_net::SDL2_net-static>"
+ "Ogg::ogg"
+ "Vorbis::vorbis"
+ "Vorbis::vorbisenc"
+ "Vorbis::vorbisfile"
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
@@ -295,8 +313,14 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
${DEVKITPRO}/portlibs/wiiu/include/
)
else()
+ find_package(Ogg REQUIRED)
+ find_package(Vorbis REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"$<$<BOOL:${USE_NETWORKING}>:SDL2_net::SDL2_net>"
+ "Ogg::ogg"
+ "Vorbis::vorbis"
+ "Vorbis::vorbisenc"
+ "Vorbis::vorbisfile"
)
endif()
diff --git a/assets/yaml/cn/rev0/ast_audio.yaml b/assets/yaml/cn/rev0/ast_audio.yaml
new file mode 100644
index 00000000..e6bb775a
--- /dev/null
+++ b/assets/yaml/cn/rev0/ast_audio.yaml
@@ -0,0 +1,31 @@
+:config:
+ force: true
+ header:
+ code:
+ - '#include "sys.h"'
+ - '#include "sf64audio_provisional.h"'
+
+audio_setup:
+ type: NAUDIO:V1:AUDIO_SETUP
+ driver: SF64
+ audio_seq:
+ size: 0x3AFD0
+ offset: 0xE9950
+ audio_bank:
+ size: 0x1CB20
+ offset: 0x1183A0
+ audio_table:
+ size: 0x691AF0
+ offset: 0x134EC0
+
+audio_sample_bank_table:
+ { type: NAUDIO:V1:AUDIO_TABLE, format: SAMPLE, offset: 0xC1460, symbol: gSampleBankTableInit }
+
+audio_seq_table:
+ { type: NAUDIO:V1:AUDIO_TABLE, format: SEQUENCE, offset: 0xC14A0, symbol: gSeqTableInit }
+
+audio_soundfont_table:
+ { type: NAUDIO:V1:AUDIO_TABLE, format: SOUNDFONT, offset: 0xC18D0, symbol: gSoundFontTableInit }
+
+audio_seq_font_table:
+ { type: ARRAY, count: 283, array_type: u8, offset: 0xC1AF0, symbol: gSeqFontTableInit } \ No newline at end of file
diff --git a/cmake/modules/FindOgg.cmake b/cmake/modules/FindOgg.cmake
new file mode 100644
index 00000000..f606144f
--- /dev/null
+++ b/cmake/modules/FindOgg.cmake
@@ -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) \ No newline at end of file
diff --git a/cmake/modules/FindVorbis.cmake b/cmake/modules/FindVorbis.cmake
new file mode 100644
index 00000000..0d3d6624
--- /dev/null
+++ b/cmake/modules/FindVorbis.cmake
@@ -0,0 +1,197 @@
+#[=======================================================================[.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) \ No newline at end of file
diff --git a/docs/BUILDING.md b/docs/BUILDING.md
index d042a25c..aac581e6 100644
--- a/docs/BUILDING.md
+++ b/docs/BUILDING.md
@@ -83,34 +83,34 @@ C:\Program Files\CMake\bin\cmake.exe --build build-cmake --target clean
#### Debian/Ubuntu
```sh
# using gcc
-apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
+apt-get install gcc g++ git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev ibvorbis-dev
# or using clang
-apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev
+apt-get install clang git cmake ninja-build lsb-release libsdl2-dev libpng-dev libsdl2-net-dev libzip-dev zipcmp zipmerge ziptool nlohmann-json3-dev libtinyxml2-dev libspdlog-dev libboost-dev libopengl-dev libogg-dev libvorbis-dev
```
#### Arch
```sh
# using gcc
-pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost
+pacman -S gcc git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost libogg libvorbis
# or using clang
-pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost
+pacman -S clang git cmake ninja lsb-release sdl2 libpng libzip nlohmann-json tinyxml2 spdlog sdl2_net boost libogg libvorbis
```
#### Fedora
```sh
# using gcc
-dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel
+dnf install gcc gcc-c++ git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel libogg-devel libvorbis-devel
# or using clang
-dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel
+dnf install clang git cmake ninja-build lsb_release SDL2-devel libpng-devel libzip-devel libzip-tools nlohmann-json-devel tinyxml2-devel spdlog-devel boost-devel libogg-devel libvorbis-devel
```
#### openSUSE
```sh
# using gcc
-zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel
+zypper in gcc gcc-c++ git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel libogg-devel libvorbis-devel
# or using clang
-zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel
+zypper in clang libstdc++-devel git cmake ninja SDL2-devel libpng16-devel libzip-devel libzip-tools nlohmann_json-devel tinyxml2-devel spdlog-devel libogg-devel libvorbis-devel
```
### Build
@@ -160,7 +160,7 @@ cmake --build build-cmake --target clean
```
## macOS
-Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake, nlohmann-json, libzip` (can be installed via homebrew, macports, etc)
+Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, ninja, cmake, nlohmann-json, libzip, vorbis-tools` (can be installed via homebrew, macports, etc)
**Important: For maximum performance make sure you have ninja build tools installed!**
diff --git a/src/audio/audio_synthesis.c b/src/audio/audio_synthesis.c
index 090e5128..f360229a 100644
--- a/src/audio/audio_synthesis.c
+++ b/src/audio/audio_synthesis.c
@@ -1036,13 +1036,14 @@ Acmd* AudioSynth_ProcessNote(s32 noteIndex, NoteSubEu* noteSub, NoteSynthesisSta
goto skip;
case CODEC_S16:
+ flags = A_CONTINUE;
skipBytes = 0;
size_t bytesToRead;
numSamplesProcessed += numSamplesToLoadAdj;
dmemUncompressedAddrOffset1 = numSamplesToLoadAdj;
if (((synthState->samplePosInt * 2) + (numSamplesToLoadAdj)*SAMPLE_SIZE) < bookSample->size) {
- bytesToRead = (numSamplesToLoadAdj)*SAMPLE_SIZE;
+ bytesToRead = (numSamplesToLoadAdj) * SAMPLE_SIZE;
} else {
bytesToRead = bookSample->size - (synthState->samplePosInt * 2);
}
diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp
index 98492a67..aaebe67a 100644
--- a/src/port/Engine.cpp
+++ b/src/port/Engine.cpp
@@ -237,8 +237,9 @@ GameEngine::GameEngine() {
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySampleV1>(), RESOURCE_FORMAT_BINARY,
"Sample", static_cast<uint32_t>(SF64::ResourceType::Sample), 1);
- loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySampleV2>(), RESOURCE_FORMAT_BINARY,
- "Sample", static_cast<uint32_t>(SF64::ResourceType::Sample), 2);
+
+ loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryXMLSampleV0>(), RESOURCE_FORMAT_XML,
+ "Sample", static_cast<uint32_t>(SF64::ResourceType::Sample), 0);
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySoundFontV0>(), RESOURCE_FORMAT_BINARY,
"SoundFont", static_cast<uint32_t>(SF64::ResourceType::SoundFont), 0);
diff --git a/src/port/resource/importers/audio/SampleFactory.cpp b/src/port/resource/importers/audio/SampleFactory.cpp
index cac380d2..8289266a 100644
--- a/src/port/resource/importers/audio/SampleFactory.cpp
+++ b/src/port/resource/importers/audio/SampleFactory.cpp
@@ -1,6 +1,14 @@
#include "SampleFactory.h"
#include "../ResourceUtil.h"
#include "port/resource/type/audio/Sample.h"
+#include "sf64audio_provisional.h"
+#define DR_WAV_IMPLEMENTATION
+#include <dr_wav.h>
+
+#define DR_MP3_IMPLEMENTATION
+#include <dr_mp3.h>
+
+#include "vorbis/vorbisfile.h"
namespace SF64 {
std::shared_ptr<Ship::IResource> ResourceFactoryBinarySampleV1::ReadResource(std::shared_ptr<Ship::File> file) {
@@ -23,7 +31,7 @@ std::shared_ptr<Ship::IResource> ResourceFactoryBinarySampleV1::ReadResource(std
if(sample->mSample.codec == 2){
sample->mSample.medium = 2;
for(size_t i = 0; i < sample->mSample.size / 2; i++){
- int16_t* sampleData = (int16_t*) sample->mSample.sampleAddr;
+ auto sampleData = (int16_t*) sample->mSample.sampleAddr;
sampleData[i] = BSWAP16(sampleData[i]);
}
} else {
@@ -35,36 +43,230 @@ std::shared_ptr<Ship::IResource> ResourceFactoryBinarySampleV1::ReadResource(std
return sample;
}
-std::shared_ptr<Ship::IResource> ResourceFactoryBinarySampleV2::ReadResource(std::shared_ptr<Ship::File> file) {
+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 void Mp3DecoderWorker(std::shared_ptr<Sample> sample, 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;
+
+ sample->mSample.sampleAddr = new uint8_t[numFrames * channels * 2];
+ drmp3_read_pcm_frames_s16(&mp3, numFrames, (int16_t*)sample->mSample.sampleAddr);
+}
+
+static void OggDecoderWorker(std::shared_ptr<Sample> sample, std::shared_ptr<Ship::File> sampleFile) {
+ 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(),
+ };
+ 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;
+ sample->mSample.sampleAddr = new uint8_t[toRead];
+ do {
+ read = ov_read(&vf, dataBuff, 4096, 0, 2, 1, &bitStream);
+ memcpy(sample->mSample.sampleAddr + pos, dataBuff, read);
+ pos += read;
+ } while (read != 0);
+ ov_clear(&vf);
+}
+
+std::shared_ptr<Ship::IResource> ResourceFactoryXMLSampleV0::ReadResource(std::shared_ptr<Ship::File> file) {
if (!FileHasValidFormatAndReader(file)) {
return nullptr;
}
auto sample = std::make_shared<Sample>(file->InitData);
- auto reader = std::get<std::shared_ptr<Ship::BinaryReader>>(file->Reader);
+ auto child = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement();
+ std::shared_ptr<Ship::ResourceInitData> initData = std::make_shared<Ship::ResourceInitData>();
+ const char* customFormatStr = child->Attribute("CustomFormat");
+ memset(&sample->mSample, 0, sizeof(sample->mSample));
+ sample->mSample.isRelocated = 0;
+ sample->mSample.codec = CodecStrToInt(child->Attribute("Codec"), file->InitData->Path.c_str());
+ sample->mSample.medium = MediumStrToInt(child->Attribute("Medium"));
+ sample->mSample.unk = child->IntAttribute("bit26");
- sample->mSample.codec = reader->ReadUByte();
- sample->mSample.medium = reader->ReadUByte();
- sample->mSample.unk = reader->ReadUByte();
- sample->mSample.size = reader->ReadUInt32();
- sample->mSample.tuning = reader->ReadFloat();
- sample->mSample.loop = LoadChild<AdpcmLoopData*>(reader->ReadUInt64());
- sample->mSample.book = LoadChild<AdpcmBookData*>(reader->ReadUInt64());
- sample->mSample.sampleAddr = new uint8_t[sample->mSample.size];
- reader->Read((char*) sample->mSample.sampleAddr, sample->mSample.size);
+ tinyxml2::XMLElement* loopRoot = child->FirstChildElement("ADPCMLoop");
+ if (loopRoot != nullptr) {
+ size_t i = 0;
+ sample->mSample.loop = new AdpcmLoopData();
+ sample->mSample.loop->start = loopRoot->UnsignedAttribute("Start");
+ sample->mSample.loop->end = loopRoot->UnsignedAttribute("End");
+ sample->mSample.loop->count = loopRoot->UnsignedAttribute("Count");
+ tinyxml2::XMLElement* predictor = loopRoot->FirstChildElement("Predictor");
+ while (predictor != nullptr) {
+ sample->mSample.loop->predictorState[i++] = predictor->IntAttribute("State");
+ predictor = predictor->NextSiblingElement();
+ }
+ }
- if(sample->mSample.codec == 2){
- sample->mSample.medium = 2;
- for(size_t i = 0; i < sample->mSample.size / 2; i++){
- int16_t* sampleData = (int16_t*) sample->mSample.sampleAddr;
- sampleData[i] = BSWAP16(sampleData[i]);
+ tinyxml2::XMLElement* bookRoot = child->FirstChildElement("ADPCMBook");
+ if (bookRoot != nullptr) {
+ size_t i = 0;
+ sample->mSample.book = new AdpcmBookData();
+ sample->mSample.book->numPredictors = bookRoot->IntAttribute("Npredictors");
+ sample->mSample.book->order = bookRoot->IntAttribute("Order");
+ tinyxml2::XMLElement* book = bookRoot->FirstChildElement("Book");
+ size_t numBooks = sample->mSample.book->numPredictors * sample->mSample.book->order * 8;
+ sample->mSample.book->book = new int16_t[numBooks];
+ while (book != nullptr) {
+ sample->mSample.book->book[i++] = book->IntAttribute("Page");
+ book = book->NextSiblingElement();
}
- } else {
- sample->mSample.medium = 0;
}
- sample->mSample.isRelocated = 1;
+ size_t size = child->Int64Attribute("Size");
+ sample->mSample.size = size;
+
+ const char* path = child->Attribute("Path");
+ initData->Path = path;
+ initData->IsCustom = false;
+ initData->ByteOrder = Ship::Endianness::Native;
+ auto sampleFile = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->LoadFile(path, initData);
+ 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);
+
+ sample->mSample.tuning = (wav.sampleRate * wav.channels) / 32000.0f;
+ sample->mSample.sampleAddr = new uint8_t[numFrames * wav.channels * 2];
+
+ drwav_read_pcm_frames_s16(&wav, numFrames, (int16_t*)sample->mSample.sampleAddr);
+ return sample;
+ } else if (strcmp(customFormatStr, "ogg") == 0) {
+ std::thread fileDecoderThread = std::thread(OggDecoderWorker, sample, sampleFile);
+ fileDecoderThread.detach();
+ return sample;
+ } else if (strcmp(customFormatStr, "mp3") == 0) {
+ std::thread fileDecoderThread = std::thread(Mp3DecoderWorker, sample, sampleFile);
+ fileDecoderThread.detach();
+ return sample;
+ }
+ }
+ // Not a normal streamed sample. Fallback to the original ADPCM sample to be decoded by the audio engine.
+ sample->mSample.sampleAddr = new uint8_t[size];
+ // Can't use memcpy due to endianness issues.
+ for (uint32_t i = 0; i < size; i++) {
+ sample->mSample.sampleAddr[i] = (*sampleFile->Buffer)[i];
+ }
return sample;
}
+
+uint8_t ResourceFactoryXMLSampleV0::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, UNK6, UNK7.", file,
+ str);
+ throw std::runtime_error(buff);
+ }
+}
+
+uint32_t ResourceFactoryXMLSampleV0::MediumStrToInt(const char* str) {
+ if (!strcmp("Ram", str)) {
+ return 0;
+ } else if (!strcmp("Unk", str)) {
+ return 1;
+ } else if (!strcmp("Cart", str)) {
+ return 2;
+ } else if (!strcmp("Disk", str)) {
+ return 3;
+ // 4 is skipped
+ } else if (!strcmp("RamUnloaded", str)) {
+ return 5;
+ } else {
+ char buff[2048];
+ snprintf(buff, 2048,
+ "Bad medium value. Got %s, expected Ram, Unk, Cart, or Disk.", str);
+ throw std::runtime_error(buff);
+ }
+}
} // namespace LUS
diff --git a/src/port/resource/importers/audio/SampleFactory.h b/src/port/resource/importers/audio/SampleFactory.h
index 4b2017eb..01fbf97e 100644
--- a/src/port/resource/importers/audio/SampleFactory.h
+++ b/src/port/resource/importers/audio/SampleFactory.h
@@ -1,16 +1,26 @@
#pragma once
#include "Resource.h"
+#include "ResourceFactoryXML.h"
#include "ResourceFactoryBinary.h"
namespace SF64 {
+struct OggFileData {
+ void* data;
+ size_t pos;
+ size_t size;
+};
+
class ResourceFactoryBinarySampleV1 : public Ship::ResourceFactoryBinary {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file) override;
};
-class ResourceFactoryBinarySampleV2 : public Ship::ResourceFactoryBinary {
+class ResourceFactoryXMLSampleV0 : public Ship::ResourceFactoryXML {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file) override;
+ private:
+ static uint8_t CodecStrToInt(const char* str, const char* file);
+ static uint32_t MediumStrToInt(const char* str);
};
}; // namespace LUS
diff --git a/tools/Torch b/tools/Torch
-Subproject 28dcd128b0406a43ab7ef9718213f7ab7d3736f
+Subproject 053d97a433f3cfc9607b7cedb512d2e7ee1dc78