Files
Sylpheed/tools/re-capture/bgm_wave_census.py
Sylpheed RE agent b3c8632006 re: a music bank is two stems that play together -- not intro+loop, and
not something to concatenate

Q10, and it starts by withdrawing the question's own premise. BGM_001 is
not three sub-waves of 10 KB / 4.47 MB / 4.67 MB: the 10 KB is the bank
header. A bank is exactly TWO waves, and across all 32 BGM banks on the
disc the two always have the SAME duration -- equal to 0.01 s over
lengths from 37 s to 277 s. That alone kills intro+loop and kills two
halves of one piece, both of which require unequal lengths.

Four banks appear to break the rule and do not: BGM_106-109 are the known
leading-region straddle, and the giveaway is that the entry named
BGM_107.slb contains BANK id=1108. The seek packet counts pin each join
exactly, so they realign to the same two-equal-waves shape rather than
being dropped as noise. That trap goes in METHOD.

Then the roles, by decoding both waves to PCM. They are
sample-synchronous: transient-envelope correlation searched over +/-5 s
peaks at lag +0.00 s, and both waves stop at the same millisecond,
167.663 s. Two stems of one performance, meant to sound at once. Wave 1
is quieter, has almost no bass and is far more L/R-decorrelated, which
reads as a surround-rear pair or a second intensity layer -- I cannot
separate those two from the file, and say so: ChannelMask is 0x0002 on
both, and this game's channel metadata is already documented as
meaningless.

Two things the port needs that are NOT on the disc, both marked as
authored: the track is not a seamless loop (BGM_001 fades out and is
followed by 6.15 s of silence, no loop-point field found), and nothing
names which bank the menu plays -- all 32 BGM cues are numeric.
2026-08-28 18:13:10 +00:00

31 lines
1.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Every BGM bank's sub-wave structure: count, bytes, PsuedoBytesPerSec, seconds.
Static, disc-only. See docs/re/structures/bgm-two-stems.md."""
import sys, struct
sys.path.insert(0,"/work/Syplheed-Reborn/tools/re-capture")
exec(open("/work/Syplheed-Reborn/tools/re-capture/slb_segment_phase.py").read().split("def cmd_phases")[0])
pak=Pak("/work/sylph_extract/dat/sound.pak")
def bps(b, riff_at):
# PsuedoBytesPerSec at RIFF+0x20 (u32 LE), SampleRate at +0x24
return struct.unpack_from("<I", b, riff_at+0x20)[0], struct.unpack_from("<I", b, riff_at+0x24)[0]
rows=[]
for n in list(range(1,60))+list(range(101,120)):
name=f"BGM_{n:03d}.slb"
i=pak.find(name)
if i is None: continue
b=pak.read(i); ws=waves(b)
ds=[]
for w in ws:
pb,sr=bps(b,w["at"])
ds.append((w["data_size"], pb, sr, w["data_size"]/pb if pb else 0))
rows.append((name,len(ws),ds))
print(f"{'bank':14s} {'waves':>5s} per-wave (bytes, bytes/s, Hz, seconds)")
same=0
for name,k,ds in rows:
txt=" | ".join(f"{d:8d} {pb:6d} {sr:5d} {sec:7.2f}s" for d,pb,sr,sec in ds)
eq = len(ds)==2 and abs(ds[0][3]-ds[1][3])<0.05
same += eq
print(f"{name:14s} {k:5d} {txt} {'EQUAL-LENGTH' if eq else ''}")
print(f"\n{len(rows)} BGM banks; {same} are exactly two waves of equal duration")