diff --git a/.gitmodules b/.gitmodules index c5d05edd3..c0ba5e79d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -120,3 +120,6 @@ [submodule "externals/miniz"] path = externals/miniz url = https://github.com/richgel999/miniz +[submodule "externals/aacdec/fdk-aac"] + path = externals/aacdec/fdk-aac + url = https://android.googlesource.com/platform/external/aac diff --git a/CMakeLists.txt b/CMakeLists.txt index e838030bf..99aca5268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,8 @@ include_directories(src) set(AJM_LIB src/core/libraries/ajm/ajm.cpp src/core/libraries/ajm/ajm.h + src/core/libraries/ajm/ajm_aac.cpp + src/core/libraries/ajm/ajm_aac.h src/core/libraries/ajm/ajm_at9.cpp src/core/libraries/ajm/ajm_at9.h src/core/libraries/ajm/ajm_batch.cpp @@ -1085,7 +1087,7 @@ 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 ZLIB::ZLIB PNG::PNG) target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml) -target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz) +target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz fdk-aac) 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") diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index eb3723f2c..8e96f9bec 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -258,6 +258,10 @@ if (WIN32) add_subdirectory(ext-wepoll) endif() +if (NOT TARGET fdk-aac) +add_subdirectory(aacdec) +endif() + #nlohmann json set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(json) diff --git a/externals/aacdec/CMakeLists.txt b/externals/aacdec/CMakeLists.txt new file mode 100644 index 000000000..2adfa032b --- /dev/null +++ b/externals/aacdec/CMakeLists.txt @@ -0,0 +1,154 @@ +# SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +set(AACDEC_SRC + fdk-aac/libAACdec/src/FDK_delay.cpp + fdk-aac/libAACdec/src/aac_ram.cpp + fdk-aac/libAACdec/src/aac_rom.cpp + fdk-aac/libAACdec/src/aacdec_drc.cpp + fdk-aac/libAACdec/src/aacdec_hcr.cpp + fdk-aac/libAACdec/src/aacdec_hcr_bit.cpp + fdk-aac/libAACdec/src/aacdec_hcrs.cpp + fdk-aac/libAACdec/src/aacdec_pns.cpp + fdk-aac/libAACdec/src/aacdec_tns.cpp + fdk-aac/libAACdec/src/aacdecoder.cpp + fdk-aac/libAACdec/src/aacdecoder_lib.cpp + fdk-aac/libAACdec/src/block.cpp + fdk-aac/libAACdec/src/channel.cpp + fdk-aac/libAACdec/src/channelinfo.cpp + fdk-aac/libAACdec/src/conceal.cpp + fdk-aac/libAACdec/src/ldfiltbank.cpp + fdk-aac/libAACdec/src/pulsedata.cpp + fdk-aac/libAACdec/src/rvlc.cpp + fdk-aac/libAACdec/src/rvlcbit.cpp + fdk-aac/libAACdec/src/rvlcconceal.cpp + fdk-aac/libAACdec/src/stereo.cpp + fdk-aac/libAACdec/src/usacdec_ace_d4t64.cpp + fdk-aac/libAACdec/src/usacdec_ace_ltp.cpp + fdk-aac/libAACdec/src/usacdec_acelp.cpp + fdk-aac/libAACdec/src/usacdec_fac.cpp + fdk-aac/libAACdec/src/usacdec_lpc.cpp + fdk-aac/libAACdec/src/usacdec_lpd.cpp + fdk-aac/libAACdec/src/usacdec_rom.cpp +) + +set(FDK_SRC + fdk-aac/libFDK/src/FDK_bitbuffer.cpp + fdk-aac/libFDK/src/FDK_core.cpp + fdk-aac/libFDK/src/FDK_crc.cpp + fdk-aac/libFDK/src/FDK_decorrelate.cpp + fdk-aac/libFDK/src/FDK_hybrid.cpp + fdk-aac/libFDK/src/FDK_lpc.cpp + fdk-aac/libFDK/src/FDK_matrixCalloc.cpp + fdk-aac/libFDK/src/FDK_qmf_domain.cpp + fdk-aac/libFDK/src/FDK_tools_rom.cpp + fdk-aac/libFDK/src/FDK_trigFcts.cpp + fdk-aac/libFDK/src/autocorr2nd.cpp + fdk-aac/libFDK/src/dct.cpp + fdk-aac/libFDK/src/fft.cpp + fdk-aac/libFDK/src/fft_rad2.cpp + fdk-aac/libFDK/src/fixpoint_math.cpp + fdk-aac/libFDK/src/huff_nodes.cpp + fdk-aac/libFDK/src/mdct.cpp + fdk-aac/libFDK/src/nlc_dec.cpp + fdk-aac/libFDK/src/qmf.cpp + fdk-aac/libFDK/src/scale.cpp +) + +set(SYS_SRC + fdk-aac/libSYS/src/genericStds.cpp + fdk-aac/libSYS/src/syslib_channelMapDescr.cpp +) + +set(ARITHCODING_SRC + fdk-aac/libArithCoding/src/ac_arith_coder.cpp +) + +set(MPEGTPDEC_SRC + fdk-aac/libMpegTPDec/src/tpdec_adif.cpp + fdk-aac/libMpegTPDec/src/tpdec_adts.cpp + fdk-aac/libMpegTPDec/src/tpdec_asc.cpp + fdk-aac/libMpegTPDec/src/tpdec_drm.cpp + fdk-aac/libMpegTPDec/src/tpdec_latm.cpp + fdk-aac/libMpegTPDec/src/tpdec_lib.cpp +) + +set(SBRDEC_SRC + fdk-aac/libSBRdec/src/HFgen_preFlat.cpp + fdk-aac/libSBRdec/src/env_calc.cpp + fdk-aac/libSBRdec/src/env_dec.cpp + fdk-aac/libSBRdec/src/env_extr.cpp + fdk-aac/libSBRdec/src/hbe.cpp + fdk-aac/libSBRdec/src/huff_dec.cpp + fdk-aac/libSBRdec/src/lpp_tran.cpp + fdk-aac/libSBRdec/src/psbitdec.cpp + fdk-aac/libSBRdec/src/psdec.cpp + fdk-aac/libSBRdec/src/psdec_drm.cpp + fdk-aac/libSBRdec/src/psdecrom_drm.cpp + fdk-aac/libSBRdec/src/pvc_dec.cpp + fdk-aac/libSBRdec/src/sbr_deb.cpp + fdk-aac/libSBRdec/src/sbr_dec.cpp + fdk-aac/libSBRdec/src/sbr_ram.cpp + fdk-aac/libSBRdec/src/sbr_rom.cpp + fdk-aac/libSBRdec/src/sbrdec_drc.cpp + fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp + fdk-aac/libSBRdec/src/sbrdecoder.cpp +) + +set(PCMUTILS_SRC + fdk-aac/libPCMutils/src/limiter.cpp + fdk-aac/libPCMutils/src/pcm_utils.cpp + fdk-aac/libPCMutils/src/pcmdmx_lib.cpp +) + +set(DRCDEC_SRC + fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp + fdk-aac/libDRCdec/src/drcDec_gainDecoder.cpp + fdk-aac/libDRCdec/src/drcDec_reader.cpp + fdk-aac/libDRCdec/src/drcDec_rom.cpp + fdk-aac/libDRCdec/src/drcDec_selectionProcess.cpp + fdk-aac/libDRCdec/src/drcDec_tools.cpp + fdk-aac/libDRCdec/src/drcGainDec_init.cpp + fdk-aac/libDRCdec/src/drcGainDec_preprocess.cpp + fdk-aac/libDRCdec/src/drcGainDec_process.cpp +) + +set(SACDEC_SRC + fdk-aac/libSACdec/src/sac_bitdec.cpp + fdk-aac/libSACdec/src/sac_calcM1andM2.cpp + fdk-aac/libSACdec/src/sac_dec.cpp + fdk-aac/libSACdec/src/sac_dec_conceal.cpp + fdk-aac/libSACdec/src/sac_dec_lib.cpp + fdk-aac/libSACdec/src/sac_process.cpp + fdk-aac/libSACdec/src/sac_qmf.cpp + fdk-aac/libSACdec/src/sac_reshapeBBEnv.cpp + fdk-aac/libSACdec/src/sac_rom.cpp + fdk-aac/libSACdec/src/sac_smoothing.cpp + fdk-aac/libSACdec/src/sac_stp.cpp + fdk-aac/libSACdec/src/sac_tsd.cpp +) + +add_library(fdk-aac + ${AACDEC_SRC} + ${FDK_SRC} + ${SYS_SRC} + ${ARITHCODING_SRC} + ${MPEGTPDEC_SRC} + ${SBRDEC_SRC} + ${PCMUTILS_SRC} + ${DRCDEC_SRC} + ${SACDEC_SRC} +) + +target_include_directories(fdk-aac + PUBLIC + fdk-aac/libAACdec/include + fdk-aac/libFDK/include + fdk-aac/libSYS/include + fdk-aac/libArithCoding/include + fdk-aac/libMpegTPDec/include + fdk-aac/libSBRdec/include + fdk-aac/libPCMutils/include + fdk-aac/libDRCdec/include + fdk-aac/libSACdec/include +) diff --git a/externals/aacdec/fdk-aac b/externals/aacdec/fdk-aac new file mode 160000 index 000000000..ee76460ef --- /dev/null +++ b/externals/aacdec/fdk-aac @@ -0,0 +1 @@ +Subproject commit ee76460efbdb147e26d804c798949c23f174460b diff --git a/src/core/libraries/ajm/ajm.cpp b/src/core/libraries/ajm/ajm.cpp index 83620250b..b64bb47fd 100644 --- a/src/core/libraries/ajm/ajm.cpp +++ b/src/core/libraries/ajm/ajm.cpp @@ -144,9 +144,8 @@ int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* p_context_id) { return ORBIS_OK; } -int PS4_SYSV_ABI sceAjmInstanceCodecType() { - LOG_ERROR(Lib_Ajm, "(STUBBED) called"); - return ORBIS_OK; +AjmCodecType PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance_id) { + return static_cast((instance_id >> 14) & 0x1F); } int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context_id, AjmCodecType codec_type, diff --git a/src/core/libraries/ajm/ajm.h b/src/core/libraries/ajm/ajm.h index d68a4c0f4..1bfd88351 100644 --- a/src/core/libraries/ajm/ajm.h +++ b/src/core/libraries/ajm/ajm.h @@ -82,8 +82,6 @@ enum class AjmStatisticsFlags : u64 { DECLARE_ENUM_FLAG_OPERATORS(AjmStatisticsFlags) union AjmStatisticsJobFlags { - AjmStatisticsJobFlags(AjmJobFlags job_flags) : raw(job_flags.raw) {} - u64 raw; struct { u64 version : 3; @@ -217,7 +215,7 @@ int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* stream, u32 stream_size, int p AjmDecMp3ParseFrame* frame); int PS4_SYSV_ABI sceAjmFinalize(); int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* out_context); -int PS4_SYSV_ABI sceAjmInstanceCodecType(); +AjmCodecType PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance_id); int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmInstanceFlags flags, u32* instance); int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance); diff --git a/src/core/libraries/ajm/ajm_aac.cpp b/src/core/libraries/ajm/ajm_aac.cpp new file mode 100644 index 000000000..b96394b72 --- /dev/null +++ b/src/core/libraries/ajm/ajm_aac.cpp @@ -0,0 +1,194 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "ajm.h" +#include "ajm_aac.h" +#include "ajm_result.h" + +// using this internal header to manually configure the decoder in RAW mode +#include "externals/aacdec/fdk-aac/libAACdec/src/aacdecoder.h" + +#include +#include + +namespace Libraries::Ajm { + +AjmAacDecoder::AjmAacDecoder(AjmFormatEncoding format, AjmAacCodecFlags flags, u32 channels) + : m_format(format), m_flags(flags), m_channels(channels), m_pcm_buffer(2048 * 8), + m_skip_frames(True(flags & AjmAacCodecFlags::EnableNondelayOutput) ? 0 : 2) {} + +AjmAacDecoder::~AjmAacDecoder() { + aacDecoder_Close(m_decoder); +} + +TRANSPORT_TYPE TransportTypeFromConfigType(ConfigType config_type) { + switch (config_type) { + case ConfigType::ADTS: + return TT_MP4_ADTS; + case ConfigType::RAW: + return TT_MP4_RAW; + default: + UNREACHABLE(); + } +} + +static UINT g_freq[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, +}; + +void AjmAacDecoder::Reset() { + if (m_decoder) { + aacDecoder_Close(m_decoder); + } + + m_decoder = aacDecoder_Open(TransportTypeFromConfigType(m_init_params.config_type), 1); + if (m_init_params.config_type == ConfigType::RAW) { + // Manually configure the decoder + // Things may be incorrect due to limited documentation + CSAudioSpecificConfig asc{}; + asc.m_aot = AOT_AAC_LC; + asc.m_samplingFrequency = g_freq[m_init_params.sampling_freq_type]; + asc.m_samplingFrequencyIndex = m_init_params.sampling_freq_type; + asc.m_samplesPerFrame = 1024; + asc.m_epConfig = -1; + switch (m_channels) { + case 0: + asc.m_channelConfiguration = 2; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + asc.m_channelConfiguration = m_channels; + break; + case 7: + asc.m_channelConfiguration = 11; + break; + case 8: + asc.m_channelConfiguration = 12; // 7, 12 or 14 ? + break; + default: + UNREACHABLE(); + } + + UCHAR changed = 1; + CAacDecoder_Init(m_decoder, &asc, AC_CM_ALLOC_MEM, &changed); + } + m_skip_frames = True(m_flags & AjmAacCodecFlags::EnableNondelayOutput) ? 0 : 2; +} + +void AjmAacDecoder::Initialize(const void* buffer, u32 buffer_size) { + ASSERT(buffer_size == 8); + m_init_params = *reinterpret_cast(buffer); + Reset(); +} + +void AjmAacDecoder::GetInfo(void* out_info) const { + auto* codec_info = reinterpret_cast(out_info); + *codec_info = { + .heaac = True(m_flags & AjmAacCodecFlags::EnableSbrDecode), + }; +} + +AjmSidebandFormat AjmAacDecoder::GetFormat() const { + const auto* const info = aacDecoder_GetStreamInfo(m_decoder); + return { + .num_channels = static_cast(info->numChannels), + .channel_mask = GetChannelMask(info->numChannels), + .sampl_freq = static_cast(info->sampleRate), + .sample_encoding = m_format, // AjmFormatEncoding + .bitrate = static_cast(info->bitRate), + }; +} + +u32 AjmAacDecoder::GetMinimumInputSize() const { + return 0; +} + +u32 AjmAacDecoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const { + const auto* const info = aacDecoder_GetStreamInfo(m_decoder); + if (info->aacSamplesPerFrame <= 0) { + return 0; + } + const auto skip_samples = std::min(gapless.current.skip_samples, info->frameSize); + const auto samples = + gapless.init.total_samples != 0 + ? std::min(gapless.current.total_samples, info->frameSize - skip_samples) + : info->frameSize - skip_samples; + return samples * info->numChannels * GetPCMSize(m_format); +} + +DecoderResult AjmAacDecoder::ProcessData(std::span& input, SparseOutputBuffer& output, + AjmInstanceGapless& gapless) { + DecoderResult result{}; + + // Discard the previous contents of the internal buffer and replace them with new ones + aacDecoder_SetParam(m_decoder, AAC_TPDEC_CLEAR_BUFFER, 1); + UCHAR* buffers[] = {input.data()}; + const UINT sizes[] = {static_cast(input.size())}; + UINT valid = sizes[0]; + aacDecoder_Fill(m_decoder, buffers, sizes, &valid); + auto ret = aacDecoder_DecodeFrame(m_decoder, reinterpret_cast(m_pcm_buffer.data()), + m_pcm_buffer.size() / 2, 0); + + switch (ret) { + case AAC_DEC_OK: + break; + case AAC_DEC_NOT_ENOUGH_BITS: + result.result = ORBIS_AJM_RESULT_PARTIAL_INPUT; + return result; + default: + LOG_ERROR(Lib_Ajm, "aacDecoder_DecodeFrame failed ret = {:#x}", static_cast(ret)); + result.result = ORBIS_AJM_RESULT_CODEC_ERROR | ORBIS_AJM_RESULT_FATAL; + result.internal_result = ret; + return result; + } + + const auto* const info = aacDecoder_GetStreamInfo(m_decoder); + auto bytes_used = info->numTotalBytes; + + result.frames_decoded += 1; + input = input.subspan(bytes_used); + + if (m_skip_frames > 0) { + --m_skip_frames; + return result; + } + + u32 skip_samples = 0; + if (gapless.current.skip_samples > 0) { + skip_samples = std::min(info->frameSize, gapless.current.skip_samples); + gapless.current.skip_samples -= skip_samples; + } + + const auto max_samples = + gapless.init.total_samples != 0 ? gapless.current.total_samples : info->aacSamplesPerFrame; + + size_t pcm_written = 0; + switch (m_format) { + case AjmFormatEncoding::S16: + pcm_written = WriteOutputSamples(output, skip_samples * info->numChannels, + max_samples * info->numChannels); + break; + case AjmFormatEncoding::S32: + UNREACHABLE_MSG("NOT IMPLEMENTED"); + break; + case AjmFormatEncoding::Float: + UNREACHABLE_MSG("NOT IMPLEMENTED"); + break; + default: + UNREACHABLE(); + } + + result.samples_written = pcm_written / info->numChannels; + gapless.current.skipped_samples += info->frameSize - result.samples_written; + if (gapless.init.total_samples != 0) { + gapless.current.total_samples -= result.samples_written; + } + + return result; +} + +} // namespace Libraries::Ajm diff --git a/src/core/libraries/ajm/ajm_aac.h b/src/core/libraries/ajm/ajm_aac.h new file mode 100644 index 000000000..7ca8ecbf8 --- /dev/null +++ b/src/core/libraries/ajm/ajm_aac.h @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/enum.h" +#include "common/types.h" +#include "core/libraries/ajm/ajm_instance.h" + +#include +#include + +struct AAC_DECODER_INSTANCE; + +namespace Libraries::Ajm { + +enum ConfigType : u32 { + ADTS = 1, + RAW = 2, +}; + +enum AjmAacCodecFlags : u32 { + EnableSbrDecode = 1 << 0, + EnableNondelayOutput = 1 << 1, + SurroundChannelInterleaveOrderExtlExtrLsRs = 1 << 2, + SurroundChannelInterleaveOrderLsRsExtlExtr = 1 << 3, +}; +DECLARE_ENUM_FLAG_OPERATORS(AjmAacCodecFlags) + +struct AjmSidebandDecM4aacCodecInfo { + u32 heaac; + u32 reserved; +}; + +struct AjmAacDecoder final : AjmCodec { + explicit AjmAacDecoder(AjmFormatEncoding format, AjmAacCodecFlags flags, u32 channels); + ~AjmAacDecoder() override; + + void Reset() override; + void Initialize(const void* buffer, u32 buffer_size) override; + void GetInfo(void* out_info) const override; + AjmSidebandFormat GetFormat() const override; + u32 GetMinimumInputSize() const override; + u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override; + DecoderResult ProcessData(std::span& input, SparseOutputBuffer& output, + AjmInstanceGapless& gapless) override; + +private: + struct InitializeParameters { + ConfigType config_type; + u32 sampling_freq_type; + }; + + template + size_t WriteOutputSamples(SparseOutputBuffer& output, u32 skipped_pcm, u32 max_pcm) { + std::span pcm_data{reinterpret_cast(m_pcm_buffer.data()), + m_pcm_buffer.size() / sizeof(T)}; + pcm_data = pcm_data.subspan(skipped_pcm); + const auto pcm_size = std::min(u32(pcm_data.size()), max_pcm); + return output.Write(pcm_data.subspan(0, pcm_size)); + } + + const AjmFormatEncoding m_format; + const AjmAacCodecFlags m_flags; + const u32 m_channels; + std::vector m_pcm_buffer; + + u32 m_skip_frames = 0; + InitializeParameters m_init_params = {}; + AAC_DECODER_INSTANCE* m_decoder = nullptr; +}; + +} // namespace Libraries::Ajm diff --git a/src/core/libraries/ajm/ajm_at9.cpp b/src/core/libraries/ajm/ajm_at9.cpp index ea7add4f3..4452d032d 100644 --- a/src/core/libraries/ajm/ajm_at9.cpp +++ b/src/core/libraries/ajm/ajm_at9.cpp @@ -54,7 +54,7 @@ struct RIFFHeader { }; static_assert(sizeof(RIFFHeader) == 12); -AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags) +AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags, u32) : m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {} AjmAt9Decoder::~AjmAt9Decoder() { diff --git a/src/core/libraries/ajm/ajm_at9.h b/src/core/libraries/ajm/ajm_at9.h index 94a718824..8eb6166e2 100644 --- a/src/core/libraries/ajm/ajm_at9.h +++ b/src/core/libraries/ajm/ajm_at9.h @@ -3,6 +3,7 @@ #pragma once +#include "common/enum.h" #include "common/types.h" #include "core/libraries/ajm/ajm_instance.h" @@ -13,8 +14,6 @@ namespace Libraries::Ajm { -constexpr s32 ORBIS_AJM_DEC_AT9_MAX_CHANNELS = 8; - enum AjmAt9CodecFlags : u32 { ParseRiffHeader = 1 << 0, NonInterleavedOutput = 1 << 8, @@ -29,7 +28,7 @@ struct AjmSidebandDecAt9CodecInfo { }; struct AjmAt9Decoder final : AjmCodec { - explicit AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags); + explicit AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags, u32 channels); ~AjmAt9Decoder() override; void Reset() override; diff --git a/src/core/libraries/ajm/ajm_batch.cpp b/src/core/libraries/ajm/ajm_batch.cpp index 30e1deb71..61f80e482 100644 --- a/src/core/libraries/ajm/ajm_batch.cpp +++ b/src/core/libraries/ajm/ajm_batch.cpp @@ -165,7 +165,7 @@ AjmJob AjmStatisticsJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buf ASSERT(job_flags.has_value()); job.flags = job_flags.value(); - AjmStatisticsJobFlags flags(job.flags); + AjmStatisticsJobFlags flags{.raw = job.flags.raw}; if (input_control_buffer.has_value()) { AjmBatchBuffer input_batch(input_control_buffer.value()); if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) { diff --git a/src/core/libraries/ajm/ajm_context.cpp b/src/core/libraries/ajm/ajm_context.cpp index 83d38c5b5..8ce8f3434 100644 --- a/src/core/libraries/ajm/ajm_context.cpp +++ b/src/core/libraries/ajm/ajm_context.cpp @@ -18,7 +18,8 @@ namespace Libraries::Ajm { -static constexpr u32 ORBIS_AJM_WAIT_INFINITE = -1; +constexpr u32 ORBIS_AJM_WAIT_INFINITE = -1; +constexpr int INSTANCE_ID_MASK = 0x3FFF; AjmContext::AjmContext() { worker_thread = std::jthread([this](std::stop_token stop) { this->WorkerThread(stop); }); @@ -84,7 +85,7 @@ void AjmContext::ProcessBatch(u32 id, std::span jobs) { std::shared_ptr instance; { std::shared_lock lock(instances_mutex); - auto* p_instance = instances.Get(job.instance_id); + auto* p_instance = instances.Get(job.instance_id & INSTANCE_ID_MASK); ASSERT_MSG(p_instance != nullptr, "Attempting to execute job on null instance"); instance = *p_instance; } @@ -176,15 +177,15 @@ s32 AjmContext::InstanceCreate(AjmCodecType codec_type, AjmInstanceFlags flags, if (!opt_index.has_value()) { return ORBIS_AJM_ERROR_OUT_OF_RESOURCES; } - *out_instance = opt_index.value(); + *out_instance = opt_index.value() | (static_cast(codec_type) << 14); LOG_INFO(Lib_Ajm, "instance = {}", *out_instance); return ORBIS_OK; } -s32 AjmContext::InstanceDestroy(u32 instance) { +s32 AjmContext::InstanceDestroy(u32 instance_id) { std::unique_lock lock(instances_mutex); - if (!instances.Destroy(instance)) { + if (!instances.Destroy(instance_id & INSTANCE_ID_MASK)) { return ORBIS_AJM_ERROR_INVALID_INSTANCE; } return ORBIS_OK; diff --git a/src/core/libraries/ajm/ajm_instance.cpp b/src/core/libraries/ajm/ajm_instance.cpp index 35685e6a4..d25517c81 100644 --- a/src/core/libraries/ajm/ajm_instance.cpp +++ b/src/core/libraries/ajm/ajm_instance.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "ajm_aac.h" #include "ajm_at9.h" #include "ajm_instance.h" #include "ajm_mp3.h" @@ -26,13 +27,18 @@ u8 GetPCMSize(AjmFormatEncoding format) { AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_flags(flags) { switch (codec_type) { case AjmCodecType::At9Dec: { - m_codec = std::make_unique(AjmFormatEncoding(flags.format), - AjmAt9CodecFlags(flags.codec)); + m_codec = std::make_unique( + AjmFormatEncoding(flags.format), AjmAt9CodecFlags(flags.codec), u32(flags.channels)); break; } case AjmCodecType::Mp3Dec: { - m_codec = std::make_unique(AjmFormatEncoding(flags.format), - AjmMp3CodecFlags(flags.codec)); + m_codec = std::make_unique( + AjmFormatEncoding(flags.format), AjmMp3CodecFlags(flags.codec), u32(flags.channels)); + break; + } + case AjmCodecType::M4aacDec: { + m_codec = std::make_unique( + AjmFormatEncoding(flags.format), AjmAacCodecFlags(flags.codec), u32(flags.channels)); break; } default: diff --git a/src/core/libraries/ajm/ajm_mp3.cpp b/src/core/libraries/ajm/ajm_mp3.cpp index f8d77f031..f4ce22b8b 100644 --- a/src/core/libraries/ajm/ajm_mp3.cpp +++ b/src/core/libraries/ajm/ajm_mp3.cpp @@ -105,7 +105,7 @@ AVFrame* AjmMp3Decoder::ConvertAudioFrame(AVFrame* frame) { return new_frame; } -AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags) +AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags, u32) : m_format(format), m_flags(flags), m_codec(avcodec_find_decoder(AV_CODEC_ID_MP3)), m_codec_context(avcodec_alloc_context3(m_codec)), m_parser(av_parser_init(m_codec->id)) { int ret = avcodec_open2(m_codec_context, m_codec, nullptr); @@ -311,7 +311,8 @@ int AjmMp3Decoder::ParseMp3Header(const u8* p_begin, u32 stream_size, int parse_ BitReader reader(p_current); if (header->protection_type == 0) { - reader.Skip(16); // crc = reader.Read(16); + // crc = reader.Read(16); + reader.Skip(16); } if (header->version == Mp3AudioVersion::V1) { diff --git a/src/core/libraries/ajm/ajm_mp3.h b/src/core/libraries/ajm/ajm_mp3.h index c03d5ba15..ecbc77051 100644 --- a/src/core/libraries/ajm/ajm_mp3.h +++ b/src/core/libraries/ajm/ajm_mp3.h @@ -3,6 +3,7 @@ #pragma once +#include "common/enum.h" #include "common/types.h" #include "core/libraries/ajm/ajm_instance.h" @@ -63,7 +64,7 @@ struct AjmSidebandDecMp3CodecInfo { class AjmMp3Decoder : public AjmCodec { public: - explicit AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags); + explicit AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags, u32 channels); ~AjmMp3Decoder() override; void Reset() override;