Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions core/libs/prx/libSceAjm.native/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,6 @@ static void AjmStub(const char* name) {

extern "C" {

int APS5_VABI sceAjmBatchJobDecodeSplit(AjmBatchInfo* info, uint32_t instance, const AjmBuffer* input_buffers, size_t input_buffers_num, const AjmBuffer* output_buffers, size_t output_buffers_num, void* result) {
(void)info;
(void)instance;
(void)input_buffers;
(void)input_buffers_num;
(void)output_buffers;
(void)output_buffers_num;
(void)result;
AjmStub(__func__);
return 0;
}

int APS5_VABI sceAjmBatchJobEncode(AjmBatchInfo* info, uint32_t instance, const void* pcm_input, size_t pcm_input_size, void* bitstream_output, size_t bitstream_output_size, void* result) {
(void)info;
(void)instance;
Expand All @@ -38,23 +26,6 @@ int APS5_VABI sceAjmBatchJobEncode(AjmBatchInfo* info, uint32_t instance, const
return 0;
}

int APS5_VABI sceAjmBatchJobSetResampleParametersEx(AjmBatchInfo* info, uint32_t instance, float ratio_start, float ratio_change_per_sample, uint32_t flags, void* result) {
(void)info;
(void)instance;
(void)ratio_start;
(void)ratio_change_per_sample;
(void)flags;
(void)result;
AjmStub(__func__);
return 0;
}

const char* APS5_VABI sceAjmStrError(int error) {
(void)error;
AjmStub(__func__);
return nullptr;
}

int APS5_VABI sceAjmDecWVorbisCreateHeaderPacket(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
Expand Down
77 changes: 70 additions & 7 deletions core/libs/prx/libSceAjm.native/src/Ajm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,33 @@ constexpr std::int32_t AJM_RESULT_PARTIAL_INPUT = 0x00000008;
constexpr std::int32_t AJM_RESULT_NOT_ENOUGH_ROOM = 0x00000010;
constexpr std::int32_t AJM_RESULT_CODEC_ERROR = 0x40000000;

constexpr std::uint32_t AJM_ERROR_FIRST = 0x80930001u;
constexpr const char* AJM_ERROR_NAMES[] = {
"SCE_AJM_ERROR_UNKNOWN",
"SCE_AJM_ERROR_INVALID_CONTEXT",
"SCE_AJM_ERROR_INVALID_INSTANCE",
"SCE_AJM_ERROR_INVALID_BATCH",
"SCE_AJM_ERROR_INVALID_PARAMETER",
"SCE_AJM_ERROR_OUT_OF_MEMORY",
"SCE_AJM_ERROR_OUT_OF_RESOURCES",
"SCE_AJM_ERROR_CODEC_NOT_SUPPORTED",
"SCE_AJM_ERROR_CODEC_ALREADY_REGISTERED",
"SCE_AJM_ERROR_CODEC_NOT_REGISTERED",
"SCE_AJM_ERROR_WRONG_REVISION_FLAG",
"SCE_AJM_ERROR_FLAG_NOT_SUPPORTED",
"SCE_AJM_ERROR_BUSY",
"SCE_AJM_ERROR_BAD_PRIORITY",
"SCE_AJM_ERROR_IN_PROGRESS",
"SCE_AJM_ERROR_RETRY",
"SCE_AJM_ERROR_MALFORMED_BATCH",
"SCE_AJM_ERROR_JOB_CREATION",
"SCE_AJM_ERROR_INVALID_OPCODE",
"SCE_AJM_ERROR_PRIORITY_VIOLATION",
"SCE_AJM_ERROR_BUFFER_TOO_BIG",
"SCE_AJM_ERROR_INVALID_ADDRESS",
"SCE_AJM_ERROR_CANCELLED",
};

constexpr std::uint32_t CODEC_MP3 = 0;
constexpr std::uint32_t CODEC_AT9 = 1;
constexpr std::uint32_t CODEC_OPUS = 24;
Expand All @@ -58,6 +85,7 @@ constexpr std::uint64_t RUN_GET_CODEC_INFO = 1ull << 11;
constexpr std::uint64_t RUN_MULTIPLE_FRAMES = 1ull << 12;
constexpr std::uint64_t CONTROL_RESET = 1ull << 13;
constexpr std::uint64_t CONTROL_INITIALIZE = 1ull << 14;
constexpr std::uint64_t CONTROL_RESAMPLE = 1ull << 15;
constexpr std::uint64_t SIDEBAND_GAPLESS_DECODE = 1ull << 45;
constexpr std::uint64_t SIDEBAND_FORMAT = 1ull << 46;
constexpr std::uint64_t SIDEBAND_STREAM = 1ull << 47;
Expand Down Expand Up @@ -106,6 +134,11 @@ struct SidebandResampleInfo {
std::uint32_t reserved[8];
};

struct SidebandResampleParameters {
float ratio;
std::uint32_t flags;
};

struct Resampler {
float ratio = 1.0f;
std::vector<double> frames;
Expand Down Expand Up @@ -1080,11 +1113,18 @@ void Control(Instance& instance, const JobHeader& job, const AjmBuffer* inputs)
const auto* input = job.inputCount ? static_cast<const std::uint8_t*>(inputs[0].ptr) : nullptr;
const std::size_t inputSize = job.inputCount ? inputs[0].size : 0;
const std::size_t gaplessSize = (job.flags & SIDEBAND_GAPLESS_DECODE) ? sizeof(SidebandGaplessDecode) : 0;
const std::size_t resampleSize = (job.flags & CONTROL_RESAMPLE) ? sizeof(SidebandResampleParameters) : 0;
const std::size_t initializeSize = (job.flags & CONTROL_INITIALIZE) ? ControlInitializeSize(instance.codec) : 0;
if (inputSize != gaplessSize + initializeSize) NotImplemented_nid_no_patch("sceAjmBatchJobControl (sideband input size other than the gapless decode and the codec's initialize parameters)");
if (inputSize != gaplessSize + resampleSize + initializeSize) NotImplemented_nid_no_patch("sceAjmBatchJobControl (sideband input size other than the gapless decode, the resample parameters and the codec's initialize parameters)");
SidebandResampleParameters resample{};
if (resampleSize) {
std::memcpy(&resample, input + gaplessSize, sizeof(resample));
if (!std::isfinite(resample.ratio) || resample.ratio <= 0.0f) throw std::runtime_error("AJM: control job resample ratio " + std::to_string(resample.ratio) + " is not a positive finite number");
}
std::int32_t result = 0;
if (job.flags & CONTROL_RESET) ClearContext(instance);
if (job.flags & CONTROL_INITIALIZE) result = InitializeInstance(instance, input + gaplessSize, initializeSize);
if (job.flags & CONTROL_INITIALIZE) result = InitializeInstance(instance, input + gaplessSize + resampleSize, initializeSize);
if (resampleSize) instance.resampler.ratio = resample.ratio;
if (gaplessSize) {
SidebandGaplessDecode gapless{};
std::memcpy(&gapless, input, sizeof(gapless));
Expand All @@ -1093,6 +1133,7 @@ void Control(Instance& instance, const JobHeader& job, const AjmBuffer* inputs)
}
AJM_TRACE("[ajm] instance %u control flags 0x%llx: %zu sideband input bytes -> result 0x%x, gapless total %u skip %u skipped %u\n", job.instance, static_cast<unsigned long long>(job.flags), inputSize, static_cast<unsigned>(result), instance.gapless.totalSamples, instance.gapless.skipSamples, instance.gapless.skippedSamples);
WriteResult(job.sideband, job.sidebandSize, result);
if (gaplessSize && job.sideband && job.sidebandSize >= sizeof(SidebandResult) + sizeof(SidebandGaplessDecode)) std::memcpy(static_cast<std::uint8_t*>(job.sideband) + sizeof(SidebandResult), &instance.gapless, sizeof(instance.gapless));
}

std::size_t HeldSamples(const Instance& instance) {
Expand Down Expand Up @@ -1266,6 +1307,16 @@ int APS5_VABI sceAjmDecMp3ParseFrame(const uint8_t* stream, uint32_t streamSize,
return ParseMp3Header(stream, streamSize, parseOfl, frame);
}

const char* APS5_VABI sceAjmStrError(int error) {
const std::uint32_t index = static_cast<std::uint32_t>(error) - AJM_ERROR_FIRST;
if (index >= std::size(AJM_ERROR_NAMES)) {
char code[16];
std::snprintf(code, sizeof(code), "0x%08X", static_cast<unsigned>(error));
throw std::runtime_error(std::string(__func__) + ": " + code + " is not an AJM error code");
}
return AJM_ERROR_NAMES[index];
}

int APS5_VABI sceAjmBatchInitialize(void* buffer, size_t size, AjmBatchInfo* info) {
if (!buffer || !info) return SCE_AJM_ERROR_INVALID_PARAMETER;
info->p_buffer = buffer;
Expand Down Expand Up @@ -1294,11 +1345,11 @@ int APS5_VABI sceAjmBatchJobSetGaplessDecode(AjmBatchInfo* info, uint32_t instan
}

int APS5_VABI sceAjmBatchJobControl(AjmBatchInfo* info, uint32_t instance, uint64_t flags, const void* sideband_input, size_t sideband_input_size, void* sideband_output, size_t sideband_output_size) {
constexpr std::uint64_t supported = CONTROL_RESET | CONTROL_INITIALIZE | SIDEBAND_GAPLESS_DECODE;
if (flags == 0 || (flags & ~supported) != 0) NotImplemented_nid_no_patch("sceAjmBatchJobControl (flags other than a combination of RESET, INITIALIZE and SIDEBAND_GAPLESS_DECODE)");
if ((flags & SIDEBAND_GAPLESS_DECODE) != 0 && (flags & CONTROL_RESET) == 0) NotImplemented_nid_no_patch("sceAjmBatchJobControl (SIDEBAND_GAPLESS_DECODE without RESET)");
if (sideband_output_size != sizeof(SidebandResult)) NotImplemented_nid_no_patch("sceAjmBatchJobControl (sideband output other than the 8-byte result)");
if (sideband_input_size != 0 && !sideband_input) NotImplemented_nid_no_patch("sceAjmBatchJobControl (null sideband input)");
constexpr std::uint64_t supported = CONTROL_RESET | CONTROL_INITIALIZE | CONTROL_RESAMPLE | SIDEBAND_GAPLESS_DECODE;
if ((flags & ~supported) != 0) throw std::runtime_error(std::string(__func__) + ": flags other than a combination of RESET, INITIALIZE, RESAMPLE and SIDEBAND_GAPLESS_DECODE");
if ((flags & SIDEBAND_GAPLESS_DECODE) != 0 && (flags & CONTROL_RESET) == 0) throw std::runtime_error(std::string(__func__) + ": SIDEBAND_GAPLESS_DECODE without RESET");
if (sideband_output_size < sizeof(SidebandResult)) throw std::runtime_error(std::string(__func__) + ": a sideband output smaller than the 8-byte result");
if (sideband_input_size != 0 && !sideband_input) throw std::runtime_error(std::string(__func__) + ": null sideband input");
auto header = MakeHeader(JobKind::Control, instance, sideband_output, sideband_output_size);
header.flags = flags;
header.inputCount = sideband_input_size != 0 ? 1 : 0;
Expand All @@ -1307,6 +1358,8 @@ int APS5_VABI sceAjmBatchJobControl(AjmBatchInfo* info, uint32_t instance, uint6
}

int APS5_VABI sceAjmBatchJobRunSplit(AjmBatchInfo* info, uint32_t instance, uint64_t flags, const AjmBuffer* input_buffers, size_t input_buffers_num, const AjmBuffer* output_buffers, size_t output_buffers_num, void* sideband_output, size_t sideband_output_size) {
if ((input_buffers_num != 0 && !input_buffers) || (output_buffers_num != 0 && !output_buffers)) throw std::runtime_error(std::string(__func__) + ": a null buffer array with a nonzero count");
if (input_buffers_num > 0xffu || output_buffers_num > 0xffu) return SCE_AJM_ERROR_INVALID_PARAMETER;
auto header = MakeHeader(JobKind::Run, instance, sideband_output, sideband_output_size);
header.flags = flags;
header.inputCount = static_cast<std::uint32_t>(input_buffers_num);
Expand All @@ -1329,6 +1382,12 @@ int APS5_VABI sceAjmBatchJobSetResampleParameters(AjmBatchInfo* info, uint32_t i
return Append(info, header, nullptr, nullptr);
}

int APS5_VABI sceAjmBatchJobSetResampleParametersEx(AjmBatchInfo* info, uint32_t instance, float ratio_start, float ratio_change_per_sample, uint32_t flags, void* result) {
if (!std::isfinite(ratio_start) || ratio_start <= 0.0f) return SCE_AJM_ERROR_INVALID_PARAMETER;
if (ratio_change_per_sample != 0.0f) throw std::runtime_error(std::string(__func__) + ": the effect of a nonzero ratio change per sample is unknown");
return sceAjmBatchJobSetResampleParameters(info, instance, ratio_start, flags, result);
}

int APS5_VABI sceAjmBatchJobGetResampleInfo(AjmBatchInfo* info, uint32_t instance, void* result) {
return Append(info, MakeHeader(JobKind::GetResampleInfo, instance, result, sizeof(SidebandResult) + sizeof(SidebandResampleInfo)), nullptr, nullptr);
}
Expand All @@ -1341,6 +1400,10 @@ int APS5_VABI sceAjmBatchJobDecodeSingle(AjmBatchInfo* info, uint32_t instance,
return sceAjmBatchJobRun(info, instance, SIDEBAND_STREAM, bitstream_input, bitstream_input_size, pcm_output, pcm_output_size, result, sizeof(SidebandResult) + sizeof(SidebandStream));
}

int APS5_VABI sceAjmBatchJobDecodeSplit(AjmBatchInfo* info, uint32_t instance, const AjmBuffer* input_buffers, size_t input_buffers_num, const AjmBuffer* output_buffers, size_t output_buffers_num, void* result) {
return sceAjmBatchJobRunSplit(info, instance, SIDEBAND_STREAM | RUN_MULTIPLE_FRAMES, input_buffers, input_buffers_num, output_buffers, output_buffers_num, result, sizeof(SidebandResult) + sizeof(SidebandStream) + sizeof(SidebandMultipleFrames));
}

int APS5_VABI sceAjmBatchJobGetGaplessDecode(AjmBatchInfo* info, uint32_t instance, void* result) {
return sceAjmBatchJobRunSplit(info, instance, SIDEBAND_GAPLESS_DECODE, nullptr, 0, nullptr, 0, result, sizeof(SidebandResult) + sizeof(SidebandGaplessDecode));
}
Expand Down
6 changes: 4 additions & 2 deletions core/libs/prx/libSceAudioOut/src/AudioOut2Mastering.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <cstdint>
#include <stdexcept>
#include <string>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"

extern "C" {

int APS5_VABI sceAudioOut2MasteringInit(uint32_t flags) {
if (flags != 0) NotImplemented_nid_no_patch(__func__);
if (flags != 0) throw std::runtime_error(std::string(__func__) + ": the meaning of flags " + std::to_string(flags) + " is unknown");
return 0;
}

Expand All @@ -24,7 +26,7 @@ int APS5_VABI sceAudioOut2MasteringGetState(AudioOut2MasteringStatesHeader* stat
int APS5_VABI sceAudioOut2MasteringSetParam(const AudioOut2MasteringParamsHeader* param, uint32_t output, uint32_t flags) {
(void)output;
(void)flags;
if (param == nullptr) NotImplemented_nid_no_patch(__func__);
if (param == nullptr) throw std::runtime_error(std::string(__func__) + ": the result for a null param is unknown");
return 0;
}

Expand Down
4 changes: 3 additions & 1 deletion core/libs/prx/libSceAudioOut/src/AudioOut2System.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <cstdint>
#include <stdexcept>
#include <string>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"

Expand All @@ -13,7 +15,7 @@ int APS5_VABI sceAudioOut2Initialize(void) {
}

int APS5_VABI sceAudioOut2Set3DLatency(int userId, std::uint32_t latency) {
if (userId != USER_ID_SYSTEM || latency < MIN_SUPPORTED_3D_LATENCY || latency > MAX_SUPPORTED_3D_LATENCY) NotImplemented_nid_no_patch(__func__);
if (userId != USER_ID_SYSTEM || latency < MIN_SUPPORTED_3D_LATENCY || latency > MAX_SUPPORTED_3D_LATENCY) throw std::runtime_error(std::string(__func__) + ": the effect of latency " + std::to_string(latency) + " for user " + std::to_string(userId) + " is unknown");
return 0;
}

Expand Down
Loading
Loading