// residual.mbt
//
// 子帧残差:分区 Rice 编码。以下全部约定经 ffmpeg 编码器真实输出 + 手造帧
// 双向交叉验证:
// - 熵编码方法 2 位:0 = Rice(参数 4 位),1 = Rice2(参数 5 位);
// - 分区序 4 位;每个分区先写参数、再写该分区残差(交错布局);
// - 首分区样本数 = (块长 >> 分区序) - 预测阶,其余 = 块长 >> 分区序;
// - 商的 unary 是「q 个 0 + 终止 1」,余数参数位宽,值按 zigzag 映射;
// - 转义:参数达上限(15/31)时跟 5 位原码位宽,该分区残差按二补码原样存储。
///|
/// zigzag 逆映射:偶数 u -> u/2,奇数 u -> -(u+1)/2。
fn zigzag_decode(u : Int64) -> Int64 {
if (u & 1L) != 0L {
0L - ((u >> 1) + 1L)
} else {
u >> 1
}
}
///|
/// 解码 `size` 个 Rice 残差写入 `xs[idx ..]`(商为 unary「q 个 0 + 1」)。
fn decode_rice_partition(
br : BitReader,
xs : Array[Int64],
idx : Int32,
size : Int32,
param : Int32,
) -> Unit {
let mut j = 0
while j < size {
let mut q = 0L
while br.read_bit() == 0 {
q += 1L
if br.truncated {
break
}
}
let mut rem = 0L
if param > 0 {
rem = br.read_bits64(param)
}
xs[idx + j] = zigzag_decode((q << param) | rem)
j += 1
}
}
///|
/// 解码子帧残差区,就地写入 `xs[order .. block_size]`;
/// 调用前 `xs[0 .. order]` 已填好 warmup 样本(均为 eff 位宽)。
fn decode_residuals(
br : BitReader,
xs : Array[Int64],
block_size : Int32,
order : Int32,
) -> Unit raise FlacError {
if order > block_size {
raise BadResidual(reason="预测阶超过块长")
}
let entropy_method = br.read_bits64(2).to_int()
br.check()
if entropy_method > 1 {
raise BadResidual(reason="熵编码方法 2/3 为保留值")
}
let porder = br.read_bits64(4).to_int()
br.check()
let parts = 1 << porder
if block_size % parts != 0 {
raise BadResidual(reason="块长不能被分区数整除")
}
let psize = block_size >> porder
if psize < order {
raise BadResidual(reason="每分区样本数小于预测阶")
}
let param_len = if entropy_method == 0 { 4 } else { 5 }
let escape = (1 << param_len) - 1
let mut idx = order
let mut p = 0
while p < parts {
let size = if p == 0 { psize - order } else { psize }
let param = br.read_bits64(param_len).to_int()
if param == escape {
// 转义:再读 5 位原码位宽,残差按二补码原样存储
let raw_bits = br.read_bits64(5).to_int()
let mut j = 0
while j < size {
xs[idx + j] = br.read_sample64(raw_bits)
j += 1
}
} else {
decode_rice_partition(br, xs, idx, size, param)
}
br.check()
idx += size
p += 1
}
if idx != block_size {
raise BadResidual(reason="分区覆盖样本数与块长不符")
}
}
///|
/// FIXED 预测重建(阶 0..4),在 eff 位宽域内就地进行。
fn reconstruct_fixed(
xs : Array[Int64],
block_size : Int32,
order : Int32,
) -> Unit {
let mut i = order
while i < block_size {
let pred = if order == 1 {
xs[i - 1]
} else if order == 2 {
xs[i - 1] * 2L - xs[i - 2]
} else if order == 3 {
xs[i - 1] * 3L - xs[i - 2] * 3L + xs[i - 3]
} else if order == 4 {
xs[i - 1] * 4L - xs[i - 2] * 6L + xs[i - 3] * 4L - xs[i - 4]
} else {
0L
}
xs[i] = xs[i] + pred
i += 1
}
}
///|
/// LPC 预测重建:`x[i] = r[i] + (Σ coeff[j] * x[i-1-j]) >> shift`。
/// `shift` 已按规范解释为 s(5):非负为算术右移,负值为左移。
fn reconstruct_lpc(
xs : Array[Int64],
block_size : Int32,
order : Int32,
coeffs : Array[Int64],
shift : Int32,
) -> Unit {
let mut i = order
while i < block_size {
let mut acc = 0L
for j in 0..= 0 { acc >> shift } else { acc << -shift }
xs[i] = xs[i] + pred
i += 1
}
}