"""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))