sharpemu/src/SharpEmu.Libs/Audio/AjmExports.cs

105 lines
3.4 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE;
using System.Buffers.Binary;
using System.Collections.Concurrent;
using System.Threading;
namespace SharpEmu.Libs.Audio;
public static class AjmExports
{
private static readonly ConcurrentDictionary<uint, byte> Contexts = new();
private static int _nextContextId;
public static int AjmInitialize(CpuContext ctx)
{
var reserved = ctx[CpuRegister.Rdi];
var outputAddress = ctx[CpuRegister.Rsi];
if (reserved != 0 || outputAddress == 0)
{
return unchecked((int)0x806A0001);
}
var contextId = unchecked((uint)Interlocked.Increment(ref _nextContextId));
Span<byte> value = stackalloc byte[sizeof(uint)];
BinaryPrimitives.WriteUInt32LittleEndian(value, contextId);
if (!ctx.Memory.TryWrite(outputAddress, value))
{
return unchecked((int)0x806A0001);
}
Contexts[contextId] = 0;
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_AJM"), "1", StringComparison.Ordinal))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] ajm.initialize reserved={reserved} out=0x{outputAddress:X16} context={contextId}");
}
ctx[CpuRegister.Rax] = 0;
return 0;
}
[SysAbiExport(
Nid = "MHur6qCsUus",
ExportName = "sceAjmFinalize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceAjm")]
public static int AjmFinalize(CpuContext ctx)
{
Contexts.TryRemove(unchecked((uint)ctx[CpuRegister.Rdi]), out _);
ctx[CpuRegister.Rax] = 0;
return 0;
}
[SysAbiExport(
Nid = "Q3dyFuwGn64",
ExportName = "sceAjmModuleRegister",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceAjm")]
public static int AjmModuleRegister(CpuContext ctx)
{
var contextId = unchecked((uint)ctx[CpuRegister.Rdi]);
var codecType = unchecked((uint)ctx[CpuRegister.Rsi]);
var reserved = ctx[CpuRegister.Rdx];
if (reserved != 0 || !Contexts.ContainsKey(contextId))
{
return unchecked((int)0x806A0001);
}
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_AJM"), "1", StringComparison.Ordinal))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] ajm.module_register context={contextId} codec={codecType} reserved={reserved}");
}
ctx[CpuRegister.Rax] = 0;
return 0;
}
[SysAbiExport(
Nid = "Wi7DtlLV+KI",
ExportName = "sceAjmModuleUnregister",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceAjm")]
public static int AjmModuleUnregister(CpuContext ctx)
{
ctx[CpuRegister.Rax] = 0;
return 0;
}
[SysAbiExport(
Nid = "MmpF1XsQiHw",
ExportName = "sceAjmBatchInitialize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceAjm")]
public static int AjmBatchInitialize(CpuContext ctx)
{
// The caller owns and initializes the batch storage. This API resets
// its submission cursor on hardware; FMOD does not consume a return
// value or an additional output object here.
ctx[CpuRegister.Rax] = 0;
return 0;
}
}