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.
31 lines
1.3 KiB
Python
Executable File
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")
|