Files
UnheardCity/ackit/convert.py
2026-10-09 02:48:24 +02:00

57 lines
1.8 KiB
Python

"""WEM <-> Ogg Vorbis conversion using the game's codebook library."""
from .codebooks import CodebookLibrary
from .ogg import OggWriter
from .wem import Wem
from .wwvorbis import (W2V, transcode_setup, build_id_header, build_comment_header,
ww_packet_to_vorbis)
_LIB = None
def library() -> CodebookLibrary:
global _LIB
if _LIB is None:
_LIB = CodebookLibrary()
return _LIB
def packet_samples(blockflags, bs0, bs1):
"""Samples produced by each packet (Vorbis overlap-add rule)."""
out = []
prev = None
for bf in blockflags:
cur = bs1 if bf else bs0
out.append(0 if prev is None else (prev // 4 + cur // 4))
prev = cur
return out
def wem_to_ogg(wem: Wem):
"""Returns (ogg_bytes, details dict)."""
lib = library()
v = wem.vorb
setup, info = transcode_setup(wem.setup_packet(), W2V, wem.channels, lib)
pkts, end = wem.audio_packets()
out_pkts = []
flags = []
prev_bf = 0
for i, (_, p) in enumerate(pkts):
nxt = pkts[i + 1][1][0] if i + 1 < len(pkts) else None
op, bf = ww_packet_to_vorbis(p, nxt, info, prev_bf, v["bs0_exp"] != v["bs1_exp"])
out_pkts.append(op)
flags.append(bf)
prev_bf = bf
bs0, bs1 = 1 << v["bs0_exp"], 1 << v["bs1_exp"]
samples = packet_samples(flags, bs0, bs1)
ow = OggWriter()
ow.page([build_id_header(wem.channels, wem.rate, v["bs0_exp"], v["bs1_exp"])], 0, bos=True)
ow.page([build_comment_header(), setup], 0)
g = 0
total = v["total_frames"]
for i, op in enumerate(out_pkts):
g += samples[i]
last = i == len(out_pkts) - 1
ow.page([op], min(g, total) if last else g, eos=last)
return ow.bytes(), dict(info=info, flags=flags, samples=samples, packets=pkts, data_end=end,
sum_samples=sum(samples))