diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 6df5399fc..95093c5ca 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -54,7 +54,7 @@ file(GLOB LIBATRAC9_SOURCES ) add_library(LibAtrac9 STATIC ${LIBATRAC9_SOURCES}) -target_include_directories(LibAtrac9 PUBLIC LibAtrac9/C/src) +target_include_directories(LibAtrac9 INTERFACE LibAtrac9/C/src) # Zlib-Ng if (NOT TARGET zlib-ng::zlib) diff --git a/src/core/libraries/ajm/ajm.cpp b/src/core/libraries/ajm/ajm.cpp index cb3f0e265..39e25445e 100644 --- a/src/core/libraries/ajm/ajm.cpp +++ b/src/core/libraries/ajm/ajm.cpp @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma clang optimize off +#include #include #include #include "ajm_at9.h" #include "common/assert.h" -#include "common/debug.h" #include "common/logging/log.h" #include "core/libraries/ajm/ajm.h" #include "core/libraries/ajm/ajm_error.h" @@ -16,7 +16,6 @@ #include "core/libraries/libs.h" extern "C" { -#include #include #include #include @@ -28,18 +27,34 @@ namespace Libraries::Ajm { static constexpr u32 AJM_INSTANCE_STATISTICS = 0x80000; +static constexpr u32 SCE_AJM_WAIT_INFINITE = -1; + static constexpr u32 MaxInstances = 0x2fff; +static constexpr u32 MaxBatches = 1000; + +struct BatchInfo { + u16 instance{}; + u16 offset_in_qwords{}; // Needed for AjmBatchError? + bool waiting{}; + bool finished{}; + std::mutex mtx; + std::condition_variable cv; + int result{}; +}; + struct AjmDevice { - u32 max_prio; - u32 min_prio; + u32 max_prio{}; + u32 min_prio{}; u32 curr_cursor{}; u32 release_cursor{MaxInstances - 1}; std::array is_registered{}; std::array free_instances{}; - std::array, MaxInstances> instances; + std::array, MaxInstances> instances; + std::vector> batches{}; + std::mutex batches_mutex; - bool IsRegistered(AjmCodecType type) const { + [[nodiscard]] bool IsRegistered(AjmCodecType type) const { return is_registered[static_cast(type)]; } @@ -86,11 +101,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(AjmSingleJob* batch_pos, u32 in batch_pos->opcode.is_statistic = instance == AJM_INSTANCE_STATISTICS; batch_pos->opcode.is_control = true; - if (instance == AJM_INSTANCE_STATISTICS) { - BREAKPOINT(); - } - - AjmInOutJob* job = nullptr; + AjmInOutJob* job; if (ret_addr == nullptr) { batch_pos->job_size = sizeof(AjmInOutJob); job = &batch_pos->job; @@ -121,45 +132,10 @@ void* PS4_SYSV_ABI sceAjmBatchJobInlineBuffer(AjmSingleJob* batch_pos, const voi return nullptr; } -auto ParseWavHeader = [](void* buf, WavHeader* header) { - if (!buf) { - // buf is passed as nullptr in some cases (i.e. GetCodecInfo) - return; - } - std::memcpy(header, buf, sizeof(WavHeader)); - - std::string riff(header->RIFF, 4); - std::string wave(header->WAVE, 4); - std::string fmt(header->fmt, 4); - std::string dataID(header->Subchunk2ID, 4); - - if (std::memcmp(header->RIFF, "RIFF", 4) != 0 || std::memcmp(header->WAVE, "WAVE", 4) != 0 || - std::memcmp(header->fmt, "fmt ", 4) != 0 || - std::memcmp(header->Subchunk2ID, "data", 4) != 0) { - LOG_ERROR(Lib_Ajm, "Invalid WAV file."); - return; - } - - LOG_INFO(Lib_Ajm, "RIFF header: {}", riff); - LOG_INFO(Lib_Ajm, "WAVE header: {}", wave); - LOG_INFO(Lib_Ajm, "FMT: {}", fmt); - LOG_INFO(Lib_Ajm, "Data size: {}", header->ChunkSize); - LOG_INFO(Lib_Ajm, "Sampling Rate: {}", header->SamplesPerSec); - LOG_INFO(Lib_Ajm, "Number of bits used: {}", header->bitsPerSample); - LOG_INFO(Lib_Ajm, "Number of channels: {}", header->NumOfChan); - LOG_INFO(Lib_Ajm, "Number of bytes per second: {}", header->bytesPerSec); - LOG_INFO(Lib_Ajm, "Data length: {}", header->Subchunk2Size); - LOG_INFO(Lib_Ajm, "Audio Format: {}", header->AudioFormat); - LOG_INFO(Lib_Ajm, "Block align: {}", header->blockAlign); - LOG_INFO(Lib_Ajm, "Data string: {}", dataID); -}; - void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instance, AjmFlags flags, - void* in_buffer, u32 in_size, u8* out_buffer, + u8* in_buffer, u32 in_size, u8* out_buffer, const u32 out_size, u8* sideband_output, const u32 sideband_output_size, const void* ret_addr) { - WavHeader header{}; - ParseWavHeader(in_buffer, &header); LOG_INFO(Lib_Ajm, "called instance = {:#x}, flags = {:#x}, cmd = {}, in_size = {:#x}, out_size = {:#x}, " "ret_addr = {}", @@ -178,7 +154,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instan batch_pos->opcode.is_statistic = false; batch_pos->opcode.is_control = false; - AjmInOutJob* job = nullptr; + AjmInOutJob* job; if (ret_addr == nullptr) { batch_pos->job_size = sizeof(AjmInOutJob) + 16; job = &batch_pos->job; @@ -188,16 +164,17 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instan job = &batch_pos->ret.job; } - // todo: add some missing stuff + // TODO: Check if all the fields are being set, might be missing some job->input.buf_size = in_size; - job->input.buffer = static_cast(in_buffer); + job->input.buffer = in_buffer; job->flags = u32(flags.raw); job->unk1 = (job->unk1 & 0xfc000030) + (flags.raw >> 0x1a) + 4; job->output.buf_size = out_size; job->output.buffer = out_buffer; job->output.props &= 0xffffffe0; job->output.props |= 0x12; - *reinterpret_cast(reinterpret_cast(job) + 32) = sideband_output; + // *reinterpret_cast(reinterpret_cast(job) + 32) = sideband_output; + job->sideband_output = sideband_output; return job; } @@ -213,6 +190,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 in instance, flags.raw, magic_enum::enum_name(AjmJobRunFlags(flags.command)), magic_enum::enum_name(AjmJobSidebandFlags(flags.sideband)), num_in_buffers, num_out_buffers, fmt::ptr(ret_addr)); + const u32 job_size = (num_in_buffers * 2 + 1 + num_out_buffers * 2) * 8; const bool is_debug = ret_addr != nullptr; batch_pos->opcode.instance = instance; @@ -223,7 +201,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 in batch_pos->opcode.is_statistic = false; batch_pos->opcode.is_control = false; - u32* job = nullptr; + u32* job; if (!is_debug) { batch_pos->job_size = job_size + 16; job = batch_pos->job; @@ -237,7 +215,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 in } for (s32 i = 0; i < num_in_buffers; i++) { - AjmJobBuffer* in_buf = reinterpret_cast(job); + auto* in_buf = reinterpret_cast(job); in_buf->props &= 0xffffffe0; in_buf->props |= 1; in_buf->buf_size = in_buffers[i].size; @@ -250,7 +228,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 in job += 2; for (s32 i = 0; i < num_out_buffers; i++) { - AjmJobBuffer* out_buf = reinterpret_cast(job); + auto* out_buf = reinterpret_cast(job); out_buf->props &= 0xffffffe0; out_buf->props |= 0x11; out_buf->buf_size = out_buffers[i].size; @@ -273,23 +251,23 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_ return ORBIS_AJM_ERROR_MALFORMED_BATCH; } - static constexpr u32 MaxBatches = 1000; + const auto batch_info = std::make_shared(); - struct BatchInfo { - u16 instance; - u16 offset_in_qwords; - }; - std::array batches{}; - u32 num_batches = 0; - - const u8* batch_ptr = batch; - const u8* batch_end = batch + batch_size; - while (batch_ptr < batch_end) { - if (num_batches >= MaxBatches) { + { + if (dev->batches.size() >= MaxBatches) { LOG_ERROR(Lib_Ajm, "Too many batches in job!"); return ORBIS_AJM_ERROR_OUT_OF_MEMORY; } - AjmJobHeader header; + + *out_batch_id = static_cast(dev->batches.size()); + dev->batches.push_back(batch_info); + } + + const u8* batch_ptr = batch; + const u8* batch_end = batch + batch_size; + AjmJobHeader header{}; + + while (batch_ptr < batch_end) { std::memcpy(&header, batch_ptr, sizeof(u64)); const auto& opcode = header.opcode; @@ -297,34 +275,57 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_ const u8* job_ptr = batch_ptr + sizeof(AjmJobHeader) + opcode.is_debug * 16; if (opcode.is_control) { - // ASSERT_MSG(!opcode.is_statistic, "Statistic instance is not handled"); const auto command = AjmJobControlFlags(opcode.command_flags); switch (command) { case AjmJobControlFlags::Reset: { - LOG_INFO(Lib_Ajm, "Resetting instance {}", opcode.instance); - dev->instances[opcode.instance]->Reset(); + LOG_INFO(Lib_Ajm, "Resetting instance {}", instance); + dev->instances[instance]->Reset(); break; } - case (AjmJobControlFlags::Initialize | AjmJobControlFlags::Reset): - LOG_INFO(Lib_Ajm, "Initializing instance {}", opcode.instance); + case AjmJobControlFlags::Initialize: + LOG_INFO(Lib_Ajm, "Initializing instance {}", instance); + if (dev->instances[instance]->codec_type == AjmCodecType::At9Dec) { + const auto at9_instance = + dynamic_cast(dev->instances[instance].get()); + const auto in_buffer = reinterpret_cast(job_ptr); + std::memcpy( + at9_instance->config_data, + reinterpret_cast(in_buffer->buffer) + ->config_data, + SCE_AT9_CONFIG_DATA_SIZE); + LOG_INFO( + Lib_Ajm, "Initialize params: {}, config_data: {}, reserved: {}", + fmt::ptr(reinterpret_cast( + in_buffer->buffer)), + fmt::ptr(reinterpret_cast( + in_buffer->buffer) + ->config_data), + reinterpret_cast(in_buffer->buffer) + ->reserved); + } break; case AjmJobControlFlags::Resample: - LOG_INFO(Lib_Ajm, "Set resample params of instance {}", opcode.instance); + LOG_INFO(Lib_Ajm, "Set resample params of instance {}", instance); + break; + case AjmJobControlFlags::StatisticsEngine: + ASSERT_MSG(instance == AJM_INSTANCE_STATISTICS, + "Expected AJM_INSTANCE_STATISTICS for StatisticsEngine command"); + LOG_TRACE(Lib_Ajm, "StatisticsEngine flag not implemented"); break; default: break; } // Write sideband structures. - const AjmJobBuffer* out_buffer = reinterpret_cast(job_ptr + 24); + const auto* out_buffer = reinterpret_cast(job_ptr + 24); auto* result = reinterpret_cast(out_buffer->buffer); result->result = 0; result->internal_result = 0; } else { const auto command = AjmJobRunFlags(opcode.command_flags); const auto sideband = AjmJobSidebandFlags(opcode.sideband_flags); - const AjmJobBuffer* in_buffer = reinterpret_cast(job_ptr); - const AjmJobBuffer* out_buffer = reinterpret_cast(job_ptr + 24); + const auto* in_buffer = reinterpret_cast(job_ptr); + const auto* out_buffer = reinterpret_cast(job_ptr + 24); job_ptr += 24; LOG_INFO(Lib_Ajm, "Decode job cmd = {}, sideband = {}, in_addr = {}, in_size = {}", @@ -332,7 +333,7 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_ fmt::ptr(in_buffer->buffer), in_buffer->buf_size); // Decode as much of the input bitstream as possible. - AjmAt9Decoder* decoder_instance = dev->instances[opcode.instance].get(); + AjmInstance* decoder_instance = dev->instances[instance].get(); const auto [in_remain, out_remain, num_frames] = decoder_instance->Decode( in_buffer->buffer, in_buffer->buf_size, out_buffer->buffer, out_buffer->buf_size); @@ -357,27 +358,81 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_ sideband_ptr += sizeof(AjmSidebandMFrame); } if (True(command & AjmJobRunFlags::GetCodecInfo)) { - LOG_TRACE(Lib_Ajm, "GetCodecInfo called, supplying dummy info for now"); - auto* codec_info = reinterpret_cast(sideband_ptr); - codec_info->uiFrameSamples = 0; - codec_info->uiFramesInSuperFrame = 0; - codec_info->uiNextFrameSize = 0; - codec_info->uiSuperFrameSize = 0; - sideband_ptr += sizeof(SceAjmSidebandDecAt9CodecInfo); + // TODO: Implement this for MP3 + + if (decoder_instance->codec_type == AjmCodecType::At9Dec) { + const auto at9_decoder_instance = + dynamic_cast(decoder_instance); + + Atrac9CodecInfo decoder_codec_info; + Atrac9GetCodecInfo(at9_decoder_instance->handle, &decoder_codec_info); + + auto* codec_info = + reinterpret_cast(sideband_ptr); + codec_info->uiFrameSamples = decoder_codec_info.frameSamples; + codec_info->uiFramesInSuperFrame = decoder_codec_info.framesInSuperframe; + codec_info->uiNextFrameSize = + static_cast(at9_decoder_instance->handle)->Config.FrameBytes; + codec_info->uiSuperFrameSize = decoder_codec_info.superframeSize; + sideband_ptr += sizeof(SceAjmSidebandDecAt9CodecInfo); + } } } batch_ptr += sizeof(AjmJobHeader) + header.job_size; } - static int batch_id = 0; - *out_batch_id = ++batch_id; + + batch_info->finished = true; return ORBIS_OK; } -int PS4_SYSV_ABI sceAjmBatchWait() { - LOG_ERROR(Lib_Ajm, "(STUBBED) called"); - return ORBIS_OK; +// useless for now because batch processing isn't asynchronous +int PS4_SYSV_ABI sceAjmBatchWait(const u32 context, const u32 batch_id, const u32 timeout, + AjmBatchError* const batch_error) { + LOG_INFO(Lib_Ajm, "called context = {}, batch_id = {}, timeout = {}", context, batch_id, + timeout); + + if (batch_id > 0xFF) { + return ORBIS_AJM_ERROR_INVALID_BATCH; + } + + if (batch_id >= dev->batches.size()) { + return ORBIS_AJM_ERROR_INVALID_BATCH; + } + + const std::shared_ptr batch = dev->batches[batch_id]; + + if (batch->waiting) { + return ORBIS_AJM_ERROR_BUSY; + } + + batch->waiting = true; + + if (timeout > 0 && timeout != SCE_AJM_WAIT_INFINITE) { + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + + if (!batch->finished) { + batch->waiting = false; + return ORBIS_AJM_ERROR_IN_PROGRESS; + } + } + + if (timeout == SCE_AJM_WAIT_INFINITE) { + while (!batch->finished) { + std::this_thread::yield(); + } + } + + // timeout == 0 = non-blocking poll + if (!batch->finished) { + batch->waiting = false; + return ORBIS_AJM_ERROR_IN_PROGRESS; + } + + dev->batches.erase(dev->batches.begin() + batch_id); + + return 0; } int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData() { @@ -433,16 +488,16 @@ int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmI } const u32 index = dev->free_instances[dev->curr_cursor++]; dev->curr_cursor %= MaxInstances; - std::unique_ptr instance; + std::unique_ptr instance; switch (codec_type) { case AjmCodecType::Mp3Dec: - instance = std::make_unique(); + instance = std::make_unique(); break; case AjmCodecType::At9Dec: instance = std::make_unique(); break; default: - break; + UNREACHABLE_MSG("Codec #{} not implemented", u32(codec_type)); } instance->index = index; instance->codec_type = codec_type; diff --git a/src/core/libraries/ajm/ajm.h b/src/core/libraries/ajm/ajm.h index 3fbda7659..e3d474abc 100644 --- a/src/core/libraries/ajm/ajm.h +++ b/src/core/libraries/ajm/ajm.h @@ -41,12 +41,14 @@ struct AjmInOutJob { u32 unk1; u32 flags; AjmJobBuffer output; + void* sideband_output; }; enum class AjmJobControlFlags : u32 { Reset = 1 << 2, Initialize = 1 << 3, Resample = 1 << 4, + StatisticsEngine = 1U << 31, }; DECLARE_ENUM_FLAG_OPERATORS(AjmJobControlFlags) @@ -92,7 +94,7 @@ struct AjmSingleJob { }; }; -static_assert(sizeof(AjmSingleJob) == 0x40); +static_assert(sizeof(AjmSingleJob) == 0x48); struct AjmMultiJob { AjmHLEOpcode opcode; @@ -149,7 +151,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(AjmSingleJob* batch_pos, u32 in void* PS4_SYSV_ABI sceAjmBatchJobInlineBuffer(AjmSingleJob* batch_pos, const void* in_buffer, size_t in_size, const void** batch_address); void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(AjmSingleJob* batch_pos, u32 instance, AjmFlags flags, - void * in_buffer, u32 in_size, u8* out_buffer, + u8* in_buffer, u32 in_size, u8* out_buffer, const u32 out_size, u8* sideband_output, const u32 sideband_output_size, const void* ret_addr); void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 instance, @@ -159,9 +161,10 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa(AjmMultiJob* batch_pos, u32 in u64 num_output_buffers, void* sideband_output, u64 sideband_output_size, const void* ret_addr); int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_size, - const int priority, AjmBatchError* patch_error, + const int priority, AjmBatchError* batch_error, u32* out_batch_id); -int PS4_SYSV_ABI sceAjmBatchWait(); +int PS4_SYSV_ABI sceAjmBatchWait(const u32 context, const u32 batch_id, const u32 timeout, + AjmBatchError* const batch_error); int PS4_SYSV_ABI sceAjmDecAt9ParseConfigData(); int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* stream, u32 stream_size, int parse_ofl, AjmDecMp3ParseFrame* frame); diff --git a/src/core/libraries/ajm/ajm_at9.cpp b/src/core/libraries/ajm/ajm_at9.cpp index c1a208881..ddcd8854c 100644 --- a/src/core/libraries/ajm/ajm_at9.cpp +++ b/src/core/libraries/ajm/ajm_at9.cpp @@ -4,8 +4,10 @@ #include #include "common/assert.h" #include "core/libraries/ajm/ajm_at9.h" +#include "error_codes.h" extern "C" { +#include #include } @@ -17,9 +19,14 @@ AjmAt9Decoder::AjmAt9Decoder() { AjmAt9Decoder::Reset(); } -AjmAt9Decoder::~AjmAt9Decoder() {} +AjmAt9Decoder::~AjmAt9Decoder() { + Atrac9ReleaseHandle(handle); +} void AjmAt9Decoder::Reset() { + Atrac9ReleaseHandle(handle); + handle = Atrac9GetHandle(); + ASSERT_MSG(handle, "Atrac9GetHandle failed"); decoded_samples = 0; static int filename = 0; file.close(); @@ -28,31 +35,40 @@ void AjmAt9Decoder::Reset() { std::tuple AjmAt9Decoder::Decode(const u8* in_buf, u32 in_size, u8* out_buf, u32 out_size) { - auto ParseWavHeader = [](const uint8_t* buf, WavHeader* header) { - std::memcpy(header, buf, sizeof(WavHeader)); - }; - if (in_size <= 0 || out_size <= 0) { return std::tuple(in_size, out_size, 0); } - WavHeader header{}; - ParseWavHeader(in_buf - 0x64, &header); + Atrac9InitDecoder(handle, config_data); - if (!decoder_initialized) { - Atrac9InitDecoder(handle, header.configData); - decoder_initialized = true; - } - - // todo: do something with decoded data :p + const auto decoder_handle = static_cast(handle); + int frame_count; int bytes_used; - Atrac9Decode(handle, in_buf, nullptr, &bytes_used); Atrac9CodecInfo codec_info; Atrac9GetCodecInfo(handle, &codec_info); - return std::tuple(in_size, out_size, 0); + decoded_samples = 0; + + const auto size = codec_info.channels * codec_info.frameSamples * sizeof(u16); + + for (frame_count = 0; frame_count < decoder_handle->Config.FramesPerSuperframe; frame_count++) { + short pcm_buffer[size]; + int ret = Atrac9Decode(decoder_handle, in_buf, pcm_buffer, &bytes_used); + ASSERT_MSG(ret == At9Status::ERR_SUCCESS, "Atrac9Decode failed"); + in_buf += bytes_used; + in_size -= bytes_used; + std::memcpy(out_buf, pcm_buffer, size); + file.write(reinterpret_cast(pcm_buffer), size); + out_buf += size; + out_size -= size; + decoded_samples += decoder_handle->Config.FrameSamples; + } + + LOG_TRACE(Lib_Ajm, "Decoded {} samples, frame count: {}", decoded_samples, frame_count); + + return std::tuple(in_size, out_size, frame_count); } } // namespace Libraries::Ajm diff --git a/src/core/libraries/ajm/ajm_at9.h b/src/core/libraries/ajm/ajm_at9.h index a7760829b..b96cda6a8 100644 --- a/src/core/libraries/ajm/ajm_at9.h +++ b/src/core/libraries/ajm/ajm_at9.h @@ -4,7 +4,6 @@ #pragma once #include -#include #include "common/types.h" #include "core/libraries/ajm/ajm_instance.h" @@ -16,42 +15,17 @@ namespace Libraries::Ajm { constexpr unsigned int SCE_AT9_CONFIG_DATA_SIZE = 4; -#pragma pack(push, 1) -struct WavHeader { - /* RIFF Chunk Descriptor */ - char RIFF[4]; // RIFF Header Magic header - uint32_t ChunkSize; // RIFF Chunk Size - char WAVE[4]; // WAVE Header - /* "fmt" sub-chunk */ - char fmt[4]; // FMT header - uint32_t Subchunk1Size; // Size of the fmt chunk - uint16_t AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, - // 259=ADPCM - uint16_t NumOfChan; // Number of channels 1=Mono 2=Sterio - uint32_t SamplesPerSec; // Sampling Frequency in Hz - uint32_t bytesPerSec; // bytes per second - uint16_t blockAlign; // 2=16-bit mono, 4=16-bit stereo - uint16_t bitsPerSample; // Number of bits per sample - u16 cbSize; // Extension size - u16 samplesPerBlock; - u32 channelMask; - GUID subFormat; - u32 versionInfo; - u8 configData[SCE_AT9_CONFIG_DATA_SIZE]; // the juicy part +struct SceAjmDecAt9InitializeParameters { + u8 config_data[SCE_AT9_CONFIG_DATA_SIZE]; u32 reserved; - /* "fact" sub-chunk */ - char Subchunk2ID[4]; // "fact" string - uint32_t Subchunk2Size; // Sampled data length }; -#pragma pack(pop) - -static_assert(sizeof(WavHeader) == 80); struct AjmAt9Decoder final : AjmInstance { void* handle; bool decoder_initialized = false; std::fstream file; int length; + u8 config_data[SCE_AT9_CONFIG_DATA_SIZE]; explicit AjmAt9Decoder(); ~AjmAt9Decoder() override; diff --git a/src/core/libraries/ajm/ajm_instance.h b/src/core/libraries/ajm/ajm_instance.h index 5fafeac80..5b5e60419 100644 --- a/src/core/libraries/ajm/ajm_instance.h +++ b/src/core/libraries/ajm/ajm_instance.h @@ -3,6 +3,7 @@ #pragma once +#include "common/enum.h" #include "common/types.h" extern "C" { @@ -19,6 +20,7 @@ enum class AjmCodecType : u32 { M4aacDec = 2, Max = 23, }; +DECLARE_ENUM_FLAG_OPERATORS(AjmCodecType); static constexpr u32 NumAjmCodecs = u32(AjmCodecType::Max); enum class AjmFormatEncoding : u32 { @@ -28,8 +30,8 @@ enum class AjmFormatEncoding : u32 { }; struct AjmSidebandResult { - s32 result; - s32 internal_result; + s32 result; + s32 internal_result; }; struct AjmSidebandMFrame { @@ -64,8 +66,8 @@ struct AjmInstance { virtual void Reset() = 0; - virtual std::tuple Decode(const u8* in_buf, u32 in_size, - u8* out_buf, u32 out_size) = 0; + virtual std::tuple Decode(const u8* in_buf, u32 in_size, u8* out_buf, + u32 out_size) = 0; }; } // namespace Libraries::Ajm diff --git a/src/core/libraries/ajm/ajm_mp3.cpp b/src/core/libraries/ajm/ajm_mp3.cpp index 6dd41de69..5bf164570 100644 --- a/src/core/libraries/ajm/ajm_mp3.cpp +++ b/src/core/libraries/ajm/ajm_mp3.cpp @@ -15,7 +15,9 @@ namespace Libraries::Ajm { // Following tables have been reversed from AJM library static constexpr std::array, 3> SamplerateTable = {{ - {0x5622, 0x5DC0, 0x3E80}, {0xAC44, 0xBB80, 0x7D00}, {0x2B11, 0x2EE0, 0x1F40}, + {0x5622, 0x5DC0, 0x3E80}, + {0xAC44, 0xBB80, 0x7D00}, + {0x2B11, 0x2EE0, 0x1F40}, }}; static constexpr std::array, 2> BitrateTable = {{ @@ -78,14 +80,13 @@ void AjmMp3Decoder::Reset() { file.open(fmt::format("inst{}_{}.raw", index, ++filename), std::ios::out | std::ios::binary); } -std::tuple AjmMp3Decoder::Decode(const u8* buf, u32 in_size, - u8* out_buf, u32 out_size) { +std::tuple AjmMp3Decoder::Decode(const u8* buf, u32 in_size, u8* out_buf, + u32 out_size) { u32 num_frames = 0; AVPacket* pkt = av_packet_alloc(); while (in_size > 0 && out_size > 0) { - int ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, - buf, in_size, - AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + int ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, buf, in_size, AV_NOPTS_VALUE, + AV_NOPTS_VALUE, 0); ASSERT_MSG(ret >= 0, "Error while parsing {}", ret); buf += ret; in_size -= ret; diff --git a/src/core/libraries/ajm/ajm_mp3.h b/src/core/libraries/ajm/ajm_mp3.h index 7a81abae4..58d7e7bab 100644 --- a/src/core/libraries/ajm/ajm_mp3.h +++ b/src/core/libraries/ajm/ajm_mp3.h @@ -15,17 +15,11 @@ struct AVCodecParserContext; namespace Libraries::Ajm { -enum class AjmDecMp3OflType : u32 { - None = 0, - Lame = 1, - Vbri = 2, - Fgh = 3, - VbriAndFgh = 4 -}; +enum class AjmDecMp3OflType : u32 { None = 0, Lame = 1, Vbri = 2, Fgh = 3, VbriAndFgh = 4 }; // 11-bit syncword if MPEG 2.5 extensions are enabled static constexpr u8 SYNCWORDH = 0xff; -static constexpr u8 SYNCWORDL = 0xe0; +static constexpr u8 SYNCWORDL = 0xe0; struct AjmDecMp3ParseFrame { u64 frame_size; @@ -73,8 +67,8 @@ struct AjmMp3Decoder : public AjmInstance { void Reset() override; - std::tuple Decode(const u8* in_buf, u32 in_size, - u8* out_buf, u32 out_size) override; + std::tuple Decode(const u8* in_buf, u32 in_size, u8* out_buf, + u32 out_size) override; static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl, AjmDecMp3ParseFrame* frame); diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index 778d777c2..8057f3e11 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -1,7 +1,10 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include #include +#include #include #include "audio_core/sdl_audio.h" @@ -335,6 +338,10 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, const void* ptr) { int PS4_SYSV_ABI sceAudioOutOutputs(OrbisAudioOutOutputParam* param, u32 num) { for (u32 i = 0; i < num; i++) { + std::fstream file; + file.open(fmt::format("handle{}.raw", param[i].handle), std::ios::out | std::ios::binary); + file.write(static_cast(param[i].ptr), 1024); + file.close(); if (const auto err = sceAudioOutOutput(param[i].handle, param[i].ptr); err != 0) return err; } diff --git a/src/video_core/page_manager.cpp b/src/video_core/page_manager.cpp index a5d065ba5..fb09e70f2 100644 --- a/src/video_core/page_manager.cpp +++ b/src/video_core/page_manager.cpp @@ -10,7 +10,7 @@ #include "core/signals.h" #include "video_core/page_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" -#define ENABLE_USERFAULTFD 1 + #ifndef _WIN64 #include #ifdef ENABLE_USERFAULTFD diff --git a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp index 48c055534..a68ec1e74 100644 --- a/src/video_core/renderer_vulkan/liverpool_to_vk.cpp +++ b/src/video_core/renderer_vulkan/liverpool_to_vk.cpp @@ -212,8 +212,6 @@ vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode) { [[fallthrough]]; case AmdGpu::ClampMode::ClampBorder: return vk::SamplerAddressMode::eClampToBorder; - case AmdGpu::ClampMode::ClampHalfBorder: - return vk::SamplerAddressMode::eClampToBorder; default: UNREACHABLE(); }