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.
This commit is contained in:
30
tools/re-capture/bgm_wave_census.py
Executable file
30
tools/re-capture/bgm_wave_census.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/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")
|
||||
Reference in New Issue
Block a user