mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-31 15:09:42 +08:00
[audio] added sdl audio backend and in-tree atrac9 decoder
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Buffers.Binary;
|
||||
using SharpEmu.HLE;
|
||||
using SharpEmu.Libs.Acm;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpEmu.Libs.Tests.Audio;
|
||||
|
||||
[CollectionDefinition("AcmState", DisableParallelization = true)]
|
||||
public sealed class AcmStateCollection
|
||||
{
|
||||
public const string Name = "AcmState";
|
||||
}
|
||||
|
||||
[Collection(AcmStateCollection.Name)]
|
||||
public sealed class AcmExportsTests : IDisposable
|
||||
{
|
||||
private const ulong MemoryBase = 0x1_1000_0000;
|
||||
private const ulong ContextAddress = MemoryBase + 0x100;
|
||||
private const ulong InfoArrayAddress = MemoryBase + 0x200;
|
||||
private const ulong ErrorAddress = MemoryBase + 0x300;
|
||||
private const ulong BatchAddress = MemoryBase + 0x400;
|
||||
|
||||
private readonly FakeCpuMemory _memory = new(MemoryBase, 0x1000);
|
||||
private readonly CpuContext _ctx;
|
||||
|
||||
public AcmExportsTests()
|
||||
{
|
||||
AcmExports.ResetForTests();
|
||||
_ctx = new CpuContext(_memory, Generation.Gen5);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContextAndBatchLifecycle_UsesFourByteHandlesAndClearsErrors()
|
||||
{
|
||||
Span<byte> contextSentinel = stackalloc byte[8];
|
||||
contextSentinel.Fill(0xCC);
|
||||
Assert.True(_memory.TryWrite(ContextAddress, contextSentinel));
|
||||
|
||||
_ctx[CpuRegister.Rdi] = ContextAddress;
|
||||
Assert.Equal(0, AcmExports.AcmContextCreate(_ctx));
|
||||
var context = ReadUInt32(ContextAddress);
|
||||
Assert.Equal(1u, context);
|
||||
Assert.Equal(0xCCCCCCCCu, ReadUInt32(ContextAddress + 4));
|
||||
|
||||
Span<byte> errorSentinel = stackalloc byte[32];
|
||||
errorSentinel.Fill(0xCC);
|
||||
Assert.True(_memory.TryWrite(ErrorAddress, errorSentinel));
|
||||
WriteUInt64(InfoArrayAddress, MemoryBase + 0x500);
|
||||
|
||||
_ctx[CpuRegister.Rdi] = context;
|
||||
_ctx[CpuRegister.Rsi] = 1;
|
||||
_ctx[CpuRegister.Rdx] = InfoArrayAddress;
|
||||
_ctx[CpuRegister.Rcx] = ErrorAddress;
|
||||
_ctx[CpuRegister.R8] = BatchAddress;
|
||||
Assert.Equal(0, AcmExports.AcmBatchStartBuffers(_ctx));
|
||||
Assert.Equal(1u, ReadUInt32(BatchAddress));
|
||||
Assert.All(ReadBytes(ErrorAddress, 32), value => Assert.Equal(0, value));
|
||||
|
||||
_ctx[CpuRegister.Rdi] = context;
|
||||
_ctx[CpuRegister.Rsi] = 1;
|
||||
_ctx[CpuRegister.Rdx] = 0;
|
||||
Assert.Equal(0, AcmExports.AcmBatchWait(_ctx));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BatchStartBuffers_RejectsUnknownContextAndMissingOutputs()
|
||||
{
|
||||
_ctx[CpuRegister.Rdi] = 99;
|
||||
_ctx[CpuRegister.Rsi] = 1;
|
||||
_ctx[CpuRegister.Rdx] = InfoArrayAddress;
|
||||
_ctx[CpuRegister.R8] = BatchAddress;
|
||||
Assert.Equal(
|
||||
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
|
||||
AcmExports.AcmBatchStartBuffers(_ctx));
|
||||
|
||||
_ctx[CpuRegister.Rdi] = ContextAddress;
|
||||
Assert.Equal(0, AcmExports.AcmContextCreate(_ctx));
|
||||
_ctx[CpuRegister.Rdi] = ReadUInt32(ContextAddress);
|
||||
_ctx[CpuRegister.Rsi] = 1;
|
||||
_ctx[CpuRegister.Rdx] = 0;
|
||||
_ctx[CpuRegister.R8] = BatchAddress;
|
||||
Assert.Equal(
|
||||
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
|
||||
AcmExports.AcmBatchStartBuffers(_ctx));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AcmBatchExports_RegisterForBothGenerations()
|
||||
{
|
||||
foreach (var generation in new[] { Generation.Gen4, Generation.Gen5 })
|
||||
{
|
||||
var manager = new ModuleManager();
|
||||
manager.RegisterExports(SharpEmu.Generated.SysAbiExportRegistry.CreateExports(generation));
|
||||
|
||||
Assert.True(manager.TryGetExport("8fe55ktlNVo", out var start));
|
||||
Assert.Equal("sceAcmBatchStartBuffers", start.Name);
|
||||
Assert.True(manager.TryGetExport("RLN3gRlXJLE", out var wait));
|
||||
Assert.Equal("sceAcmBatchWait", wait.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AcmExports.ResetForTests();
|
||||
}
|
||||
|
||||
private uint ReadUInt32(ulong address)
|
||||
{
|
||||
Span<byte> value = stackalloc byte[sizeof(uint)];
|
||||
Assert.True(_memory.TryRead(address, value));
|
||||
return BinaryPrimitives.ReadUInt32LittleEndian(value);
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(ulong address, int length)
|
||||
{
|
||||
var value = new byte[length];
|
||||
Assert.True(_memory.TryRead(address, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
private void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[sizeof(ulong)];
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
|
||||
Assert.True(_memory.TryWrite(address, bytes));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user