105 lines
3.4 KiB
C#
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;
|
|
}
|
|
}
|