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

68 lines
1.7 KiB
Python

"""LSB-first bit reader/writer (Vorbis bit packing order)."""
class BitReader:
def __init__(self, data: bytes, bitpos: int = 0):
self.data = data
self.pos = bitpos
def get(self, n: int) -> int:
v = 0
for i in range(n):
byte = self.data[(self.pos >> 3)] if (self.pos >> 3) < len(self.data) else 0
v |= ((byte >> (self.pos & 7)) & 1) << i
self.pos += 1
return v
def bits_left(self) -> int:
return len(self.data) * 8 - self.pos
class BitWriter:
def __init__(self):
self.buf = bytearray()
self.pos = 0
def put(self, n: int, v: int):
for i in range(n):
if (self.pos >> 3) >= len(self.buf):
self.buf.append(0)
if (v >> i) & 1:
self.buf[self.pos >> 3] |= 1 << (self.pos & 7)
self.pos += 1
def put_bits_from(self, r: BitReader, n: int):
"""Copy n bits from a reader (fast path in 32-bit chunks)."""
while n > 0:
k = 32 if n >= 32 else n
self.put(k, r.get(k))
n -= k
def bytes(self) -> bytes:
return bytes(self.buf)
def ilog(v: int) -> int:
r = 0
while v:
r += 1
v >>= 1
return r
def book_maptype1_quantvals(entries: int, dims: int) -> int:
bits = ilog(entries)
vals = entries >> ((bits - 1) * (dims - 1) // dims)
while True:
acc = 1
acc1 = 1
for _ in range(dims):
acc *= vals
acc1 *= vals + 1
if acc <= entries < acc1:
return vals
if acc > entries:
vals -= 1
else:
vals += 1