feat(a2b): audio — wire play-bgm/play-voice, fix BGM addressing
Wire audio end-to-end (OGG plays natively in Godot; no Frida, no decode):
- IHost.PlayBgm/PlayVoice + VM dispatch for play-bgm(0xbf)/play-voice(0xc4).
Non-Godot hosts no-op them so --selftest + engine 8/8 stay byte-identical.
- GodotAdvHost resolves id->OGG; Main plays via two AudioStreamPlayer nodes
(BGM looping; voice interrupt-on-new).
Key finding (by-ear, systematic-debugging): the two audio ops use DIFFERENT
addressing — the earlier "unified manifest" assumption was wrong for BGM.
- play-voice -> per-scene manifest files[base+id] (offset 0, same as textures).
Confirmed by ear; upgraded med->HIGH.
- play-bgm -> DIRECT LITERAL NAME BGM{id:03d}.OGG, NOT the manifest.
Real game: play-bgm 5->BGM005, 8->BGM008 (manifest gave +1). Proven by
play-bgm 0x23->BGM035 (real standalone track; BGM set skips 030-034) that the
manifest mis-resolved to a graphics entry. Fix is BGM-only:
ResourceMap.BgmPathById; voices/textures unchanged.
Also: Lily's silence root-caused as correct form-gating (G[0xa57/0xa58/0xa59]),
left unseeded by choice (no dummy state). Added diagnostic
`Age.Cli audio <SCENE.BIN> [0xADDR=VAL ...]`. Corrected opcodes.toml (play-bgm
direct-name, play-voice HIGH) + docs/memory (dropped the bogus unified-manifest
/ Frida-BGM006 claims).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,30 @@ if (args[0] == "run")
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args[0] == "audio")
|
||||
{
|
||||
// audio <SCENE.BIN> — run the scene and dump executed play-bgm/play-voice ops in order,
|
||||
// each resolved via ResourceMap (same rule as the Godot host). Diagnostic only.
|
||||
var sceneName = args[1];
|
||||
var sceneKey = Path.GetFileNameWithoutExtension(sceneName).ToUpperInvariant();
|
||||
var res = ResourceMap.Load();
|
||||
var host = new AudioTraceHost(res, sceneKey);
|
||||
var vm = new VirtualMachine(Sys4Loader.Load(Paths.Scripts()[sceneName.ToUpperInvariant()], table), table, host);
|
||||
// optional: seed globals, e.g. `audio SC0000.BIN 0xa57=1` to set Lily's form-A flag
|
||||
foreach (var s in args.Skip(2))
|
||||
{
|
||||
var kv = s.Split('=');
|
||||
int k = kv[0].StartsWith("0x") ? Convert.ToInt32(kv[0], 16) : int.Parse(kv[0]);
|
||||
long v = kv[1].StartsWith("0x") ? Convert.ToInt64(kv[1], 16) : long.Parse(kv[1]);
|
||||
vm.Globals[k] = v;
|
||||
}
|
||||
vm.Run();
|
||||
Console.WriteLine($"{sceneName}: {host.Events.Count} audio ops (halt: {vm.HaltReason})");
|
||||
foreach (var (kind, id, resolved) in host.Events)
|
||||
Console.WriteLine($" {kind,-10} 0x{id:x2} -> {resolved}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args[0] == "trace")
|
||||
{
|
||||
var scene = new Regex(@"^S[CP]\d{4}\.BIN$");
|
||||
@@ -35,3 +59,29 @@ if (args[0] == "trace")
|
||||
return 0;
|
||||
}
|
||||
Console.WriteLine("unknown command"); return 1;
|
||||
|
||||
sealed class AudioTraceHost : IHost
|
||||
{
|
||||
private readonly ResourceMap _res;
|
||||
private readonly string _scene;
|
||||
public List<(string Kind, long Id, string Resolved)> Events { get; } = new();
|
||||
public AudioTraceHost(ResourceMap res, string scene) { _res = res; _scene = scene; }
|
||||
public void PlayBgm(long id) // BGM: direct name, not the manifest
|
||||
{
|
||||
var path = _res.BgmPathById(id);
|
||||
Events.Add(("play-bgm", id, path != null ? $"DATA3 {System.IO.Path.GetFileName(path)}" : $"BGM{id:D3}.OGG <missing>"));
|
||||
}
|
||||
public void PlayVoice(long id) // voice: per-scene manifest
|
||||
{
|
||||
var e = _res.Resolve(_scene, id);
|
||||
Events.Add(("play-voice", id, e == null ? "<unresolved>"
|
||||
: $"{e.Archive} {e.Name}" + (ResourceMap.AudioPath(e) == null ? " [NO FILE]" : "")));
|
||||
}
|
||||
public void ShowText(int offset, string text) { }
|
||||
public void CallScript(long id) { }
|
||||
public void OnStub(int opcode) { }
|
||||
public void WaitForInput() { }
|
||||
public void CreateTexture(int slot, int width, int height) { }
|
||||
public void SetTexture(long resourceId, int slot) { }
|
||||
public void DrawTexture(int slot, int srcX, int srcY, int width, int height, int dstX, int dstY) { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user