Skip to content

Commit

Permalink
Ajm (#1456)
Browse files Browse the repository at this point in the history
* ajm: Initial ajm implementation

* AJM code improvements (#1453)

* Fix sideband buffer order (#1454)

* ajm: Attempt to add gapless support

* ajm_at9: Return superframes decoded in a single job

* WIP (#1460)

* Fix gapless decode and combine split buffers

* Fixed linux build

* fix number of samples reported with gapless decoding

* fixed number of remaining samples calculation

should fix the small crackling sounds that play every now and again

* refactor half ajm

* refactored most of ajm

* refactored ajm

* clang-format, in-repo libatrac9, removed debug stuff

---------

Co-authored-by: auser1337 <[email protected]>
Co-authored-by: Vladislav Mikhalin <[email protected]>
Co-authored-by: IndecisiveTurtle <[email protected]>
  • Loading branch information
4 people authored Nov 5, 2024
1 parent 76f4408 commit f068f13
Show file tree
Hide file tree
Showing 17 changed files with 1,678 additions and 58 deletions.
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,7 @@
[submodule "externals/discord-rpc"]
path = externals/discord-rpc
url = https://github.com/shadps4-emu/ext-discord-rpc.git
shallow = true
shallow = true
[submodule "externals/LibAtrac9"]
path = externals/LibAtrac9
url = https://github.com/shadps4-emu/ext-LibAtrac9.git
23 changes: 18 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,25 @@ set(AUDIO_CORE src/audio_core/sdl_audio.cpp
src/audio_core/sdl_audio.h
)

set(AJM_LIB src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm.h
src/core/libraries/ajm/ajm_at9.cpp
src/core/libraries/ajm/ajm_at9.h
src/core/libraries/ajm/ajm_batch.cpp
src/core/libraries/ajm/ajm_batch.h
src/core/libraries/ajm/ajm_context.cpp
src/core/libraries/ajm/ajm_context.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/ajm/ajm_instance.cpp
src/core/libraries/ajm/ajm_instance.h
src/core/libraries/ajm/ajm_mp3.cpp
src/core/libraries/ajm/ajm_mp3.h
)

set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
src/core/libraries/audio/audioin.h
src/core/libraries/audio/audioout.cpp
src/core/libraries/audio/audioout.h
src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm.h
src/core/libraries/ngs2/ngs2.cpp
src/core/libraries/ngs2/ngs2.h
)
Expand All @@ -194,8 +207,7 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
src/core/libraries/gnmdriver/gnm_error.h
)

set(KERNEL_LIB
src/core/libraries/kernel/event_flag/event_flag.cpp
set(KERNEL_LIB src/core/libraries/kernel/event_flag/event_flag.cpp
src/core/libraries/kernel/event_flag/event_flag.h
src/core/libraries/kernel/event_flag/event_flag_obj.cpp
src/core/libraries/kernel/event_flag/event_flag_obj.h
Expand Down Expand Up @@ -494,6 +506,7 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/libraries/error_codes.h
src/core/libraries/libs.h
src/core/libraries/libs.cpp
${AJM_LIB}
${AUDIO_LIB}
${GNM_LIB}
${KERNEL_LIB}
Expand Down Expand Up @@ -795,7 +808,7 @@ endif()
create_target_directory_groups(shadps4)

target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)

target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
Expand Down
5 changes: 5 additions & 0 deletions externals/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ if (NOT TARGET FFmpeg::ffmpeg)
add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
endif()

# LibAtrac9
file(GLOB LIBATRAC9_SOURCES LibAtrac9/C/src/*.c)
add_library(LibAtrac9 STATIC ${LIBATRAC9_SOURCES})
target_include_directories(LibAtrac9 INTERFACE LibAtrac9/C/src)

# Zlib-Ng
if (NOT TARGET zlib-ng::zlib)
set(ZLIB_ENABLE_TESTS OFF)
Expand Down
1 change: 1 addition & 0 deletions externals/LibAtrac9
Submodule LibAtrac9 added at 82767f
63 changes: 63 additions & 0 deletions src/common/slot_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

// #include <boost/icl/interval_set.hpp>

#include <limits>
#include <optional>
#include <shared_mutex>
#include <unordered_map>

#include <memory>
#include <numeric>

namespace Common {

template <class IndexType, class ResourceType,
IndexType MaxIndex = std::numeric_limits<IndexType>::max(), IndexType MinIndex = 0>
class SlotArray {
public:
SlotArray() {
std::iota(m_free_indices.begin(), m_free_indices.end(), MinIndex);
}

template <class... Types>
std::optional<IndexType> Create(Types&&... args) {
if (!HasFreeSlots()) {
return std::nullopt;
}
const auto index = m_free_indices[m_curr_cursor];
m_resources[index - MinIndex] = ResourceType(std::forward<Types>(args)...);
m_curr_cursor += 1;
return index;
}

bool Destroy(IndexType index) {
if (!m_resources[index - MinIndex].has_value()) {
return false;
}
m_curr_cursor -= 1;
m_free_indices[m_curr_cursor] = index;
m_resources[index - MinIndex] = std::nullopt;
return true;
}

ResourceType* Get(IndexType index) {
auto& resource = m_resources[index - MinIndex];
if (!resource.has_value()) {
return nullptr;
}
return &resource.value();
}

bool HasFreeSlots() {
return m_curr_cursor < m_free_indices.size();
}

private:
size_t m_curr_cursor = 0;
std::array<IndexType, MaxIndex - MinIndex> m_free_indices;
std::array<std::optional<ResourceType>, MaxIndex - MinIndex> m_resources;
};

} // namespace Common
116 changes: 77 additions & 39 deletions src/core/libraries/ajm/ajm.cpp
Original file line number Diff line number Diff line change
@@ -1,72 +1,105 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "ajm.h"
#include "ajm_error.h"

#include "common/logging/log.h"
#include "core/libraries/ajm/ajm.h"
#include "core/libraries/ajm/ajm_context.h"
#include "core/libraries/ajm/ajm_error.h"
#include "core/libraries/ajm/ajm_mp3.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"

#include <magic_enum.hpp>

namespace Libraries::Ajm {

int PS4_SYSV_ABI sceAjmBatchCancel() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
static std::unique_ptr<AjmContext> context{};

int PS4_SYSV_ABI sceAjmBatchCancel(const u32 context_id, const u32 batch_id) {
LOG_INFO(Lib_Ajm, "called context_id = {} batch_id = {}", context_id, batch_id);
return context->BatchCancel(batch_id);
}

int PS4_SYSV_ABI sceAjmBatchErrorDump() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
}

int PS4_SYSV_ABI sceAjmBatchJobControlBufferRa() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(void* p_buffer, u32 instance_id, u64 flags,
void* p_sideband_input, size_t sideband_input_size,
void* p_sideband_output,
size_t sideband_output_size,
void* p_return_address) {
return BatchJobControlBufferRa(p_buffer, instance_id, flags, p_sideband_input,
sideband_input_size, p_sideband_output, sideband_output_size,
p_return_address);
}

int PS4_SYSV_ABI sceAjmBatchJobInlineBuffer() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
void* PS4_SYSV_ABI sceAjmBatchJobInlineBuffer(void* p_buffer, const void* p_data_input,
size_t data_input_size,
const void** pp_batch_address) {
return BatchJobInlineBuffer(p_buffer, p_data_input, data_input_size, pp_batch_address);
}

int PS4_SYSV_ABI sceAjmBatchJobRunBufferRa() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(void* p_buffer, u32 instance_id, u64 flags,
void* p_data_input, size_t data_input_size,
void* p_data_output, size_t data_output_size,
void* p_sideband_output, size_t sideband_output_size,
void* p_return_address) {
return BatchJobRunBufferRa(p_buffer, instance_id, flags, p_data_input, data_input_size,
p_data_output, data_output_size, p_sideband_output,
sideband_output_size, p_return_address);
}

int PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(
void* p_buffer, u32 instance_id, u64 flags, const AjmBuffer* p_data_input_buffers,
size_t num_data_input_buffers, const AjmBuffer* p_data_output_buffers,
size_t num_data_output_buffers, void* p_sideband_output, size_t sideband_output_size,
void* p_return_address) {
return BatchJobRunSplitBufferRa(p_buffer, instance_id, flags, p_data_input_buffers,
num_data_input_buffers, p_data_output_buffers,
num_data_output_buffers, p_sideband_output,
sideband_output_size, p_return_address);
}

int PS4_SYSV_ABI sceAjmBatchStartBuffer() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context_id, u8* p_batch, u32 batch_size,
const int priority, AjmBatchError* batch_error,
u32* out_batch_id) {
LOG_TRACE(Lib_Ajm, "called context = {}, batch_size = {:#x}, priority = {}", context_id,
batch_size, priority);
return context->BatchStartBuffer(p_batch, batch_size, priority, batch_error, out_batch_id);
}

int PS4_SYSV_ABI sceAjmBatchWait() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmBatchWait(const u32 context_id, const u32 batch_id, const u32 timeout,
AjmBatchError* const batch_error) {
LOG_TRACE(Lib_Ajm, "called context = {}, batch_id = {}, timeout = {}", context_id, batch_id,
timeout);
return context->BatchWait(batch_id, timeout, batch_error);
}

int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
}

int PS4_SYSV_ABI sceAjmDecMp3ParseFrame() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* buf, u32 stream_size, int parse_ofl,
AjmDecMp3ParseFrame* frame) {
return AjmMp3Decoder::ParseMp3Header(buf, stream_size, parse_ofl, frame);
}

int PS4_SYSV_ABI sceAjmFinalize() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
}

int PS4_SYSV_ABI sceAjmInitialize() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* p_context_id) {
LOG_INFO(Lib_Ajm, "called reserved = {}", reserved);
ASSERT_MSG(context == nullptr, "Multiple contexts are currently unsupported.");
if (p_context_id == nullptr || reserved != 0) {
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
}
*p_context_id = 1;
context = std::make_unique<AjmContext>();
return ORBIS_OK;
}

Expand All @@ -75,14 +108,16 @@ int PS4_SYSV_ABI sceAjmInstanceCodecType() {
return ORBIS_OK;
}

int PS4_SYSV_ABI sceAjmInstanceCreate() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context_id, AjmCodecType codec_type,
AjmInstanceFlags flags, u32* out_instance) {
LOG_INFO(Lib_Ajm, "called context = {}, codec_type = {}, flags = {:#x}", context_id,
magic_enum::enum_name(codec_type), flags.raw);
return context->InstanceCreate(codec_type, flags, out_instance);
}

int PS4_SYSV_ABI sceAjmInstanceDestroy() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context_id, u32 instance_id) {
LOG_INFO(Lib_Ajm, "called context = {}, instance = {}", context_id, instance_id);
return context->InstanceDestroy(instance_id);
}

int PS4_SYSV_ABI sceAjmInstanceExtend() {
Expand All @@ -105,9 +140,12 @@ int PS4_SYSV_ABI sceAjmMemoryUnregister() {
return ORBIS_OK;
}

int PS4_SYSV_ABI sceAjmModuleRegister() {
LOG_ERROR(Lib_Ajm, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAjmModuleRegister(u32 context_id, AjmCodecType codec_type, s64 reserved) {
LOG_INFO(Lib_Ajm, "called context = {}, codec_type = {}", context_id, u32(codec_type));
if (reserved != 0) {
return ORBIS_AJM_ERROR_INVALID_PARAMETER;
}
return context->ModuleRegister(codec_type);
}

int PS4_SYSV_ABI sceAjmModuleUnregister() {
Expand Down Expand Up @@ -145,4 +183,4 @@ void RegisterlibSceAjm(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("AxhcqVv5AYU", "libSceAjm", 1, "libSceAjm", 1, 1, sceAjmStrError);
};

} // namespace Libraries::Ajm
} // namespace Libraries::Ajm
Loading

0 comments on commit f068f13

Please sign in to comment.