// moonmp3-encoder — pure MoonBit MP3 encoder.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.
///|
/// MSB-first bit writer. An MP3 frame's side information and main data form a
/// continuous bit stream, so every field (including the ones that are not byte
/// aligned) goes through here. Bits accumulate MSB-first into bytes, matching
/// the bit order the Layer III spec requires.
pub struct BitWriter {
buffer : @buffer.Buffer
mut current : Int32
mut filled : Int32
}
///|
/// A fresh writer with an empty buffer.
pub fn BitWriter::new() -> BitWriter {
BitWriter::{
buffer: @buffer.Buffer::Buffer(size_hint=8192),
current: 0,
filled: 0,
}
}
///|
/// Append a single bit.
pub fn BitWriter::write_bit(self : BitWriter, bit : Int32) -> Unit {
self.current = (self.current << 1) | (bit & 1)
self.filled = self.filled + 1
if self.filled == 8 {
self.buffer.write_byte(self.current.to_byte())
self.current = 0
self.filled = 0
}
}
///|
/// Append the low `count` bits of `value`, most significant first.
pub fn BitWriter::write_bits(
self : BitWriter,
value : Int64,
count : Int32,
) -> Unit {
// Whole bytes go straight to the buffer when the writer is aligned; the
// per-bit path costs a method call each and main data is mostly bytes.
let mut remaining = count
let mut shift = count
while remaining >= 8 && self.filled == 0 {
shift = shift - 8
self.buffer.write_byte(((value >> shift) & 0xFFL).to_byte())
remaining = remaining - 8
}
let mut index = remaining - 1
while index >= 0 {
self.write_bit(((value >> index) & 1L).to_int())
index = index - 1
}
}
///|
/// Number of bits written so far.
pub fn BitWriter::bit_length(self : BitWriter) -> Int32 {
self.buffer.length() * 8 + self.filled
}
///|
/// Pad with zero bits until the stream is byte aligned.
pub fn BitWriter::align(self : BitWriter) -> Unit {
while self.filled != 0 {
self.write_bit(0)
}
}
///|
/// Finish the stream and return the bytes written. The writer is unusable
/// afterwards; make a new one for the next frame.
pub fn BitWriter::finish(self : BitWriter) -> Bytes {
self.align()
self.buffer.to_bytes()
}