57 lines
1.8 KiB
Python
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))
|