// celt_tf_change.mbt
//
// 带内时间-频率分辨率调整(RFC 6716 §4.3.4.5)。
//
// 每带的 TF 选择(§4.3.1 已解出的 tf_res,取值 −3..+3)要落实到该带的解码
// 向量上:正数提高频率分辨率,负数提高时间分辨率,两者都用 Hadamard 变换
// 实现。参考实现把它放在 quant_band() 里、量化前后各一段,本文件的两条链
// 就分别对应那两段:
//
//   - 前向:解码前作用于折叠源 lowband(编码端作用于待量化的向量);
//   - 反向:解码后作用于量化域的已解码向量,把它还原到频序。
//
// RFC 对这两段只给了意图("N levels of the Hadamard transform"),没给步长
// 与次序,所以结构参数一律从参考实现的代码推出,并由两条链共用同一份推导
// ——两处各写一遍才是真正的分叉风险。

///|
/// Haar 归一常数。参考实现 celt/bands.c 写的是 QCONST32(.70710678f,31),
/// 在 float 构建下退化为字面量 0.70710678f;它只是 1/sqrt(2) 的十进制近似
/// (真值 0.7071067811865475…),故一次 Haar 往返的合成增益是
/// 2*0.70710678² ≈ 1 − 3.36e-9(三级约 1 − 1.01e-8)而非严格的 1,
/// 互逆测试的容差据此放宽。
const CEL_HAAR_C : Double = 0.70710678

///|
/// TF 链的结构参数,由 (n, b, tf_change) 唯一确定,正反两条链共用。
priv struct CelTfLayout {
  // 频率分辨率上调的 Haar 级数(tf_change > 0)
  recombine : Int
  // 时间分辨率上调的 Haar 级数(tf_change < 0)
  time_divide : Int
  // 时间分辨率循环的起点(前向从这里往下走)
  b_start : Int
  nb_start : Int
  // 时间分辨率循环的终点(反向从这里往回退)
  b_end : Int
  nb_end : Int
  // 重排的 (N0, stride);参考实现 `if (B0>1)` 不成立时置 0 表示跳过
  deint_n0 : Int
  deint_stride : Int
  // §4.3.4.5:提高时间分辨率时解码器按 sequency 序重排(长块帧才走这支)
  long_blocks : Bool
}

///|
/// 推导 TF 链结构。逐行对应参考实现 quant_band() 里 recombine、时间分辨率
/// 循环、以及重排参数的三处赋值。
///
/// `n` 是带的维数,`b` 是时间块数(长块帧为 1,瞬态帧为 M=2^LM)。
fn celt_tf_layout(n : Int, b : Int, tf_change : Int) -> CelTfLayout {
  let long_blocks = b == 1
  let recombine = if tf_change > 0 { tf_change } else { 0 }
  let b_start = b / (1 << recombine)
  let nb_start = n / b * (1 << recombine)
  // 只有块内样本数为偶数才能再对折一级;tf_change 每级 +1,到 0 即停,
  // 故级数不超过 −tf_change ≤ 3——这一上界同时保证下面 hadamard 路径的
  // stride ≤ 8,不会越过 ordery 表覆盖的 16。
  let mut bb = b_start
  let mut nb = nb_start
  let mut tc = tf_change
  let mut time_divide = 0
  while (nb & 1) == 0 && tc < 0 {
    bb = bb * 2
    nb = nb / 2
    time_divide = time_divide + 1
    tc = tc + 1
  }
  let b_end = bb
  let nb_end = nb
  let do_deint = b_end > 1
  CelTfLayout::{
    recombine,
    time_divide,
    b_start,
    nb_start,
    b_end,
    nb_end,
    deint_n0: if do_deint {
      nb_end / (1 << recombine)
    } else {
      0
    },
    deint_stride: if do_deint {
      b_end * (1 << recombine)
    } else {
      0
    },
    long_blocks,
  }
}

///|
/// haar1(X, N0, stride):把向量看成 stride 条链(链内步长 stride),每条链
/// 两两做一次 Haar 并原地写回。链 j 的第 i 对是
/// (X[stride*2j+i], X[stride*(2j+1)+i]),覆盖 stride*2*(N0/2) 个元素。
fn celt_haar1(x : Array[Double], n0 : Int, stride : Int) -> Unit {
  let half = n0 / 2
  for i in 0.. Unit {
  let n = n0 * stride
  let tmp = Array::make(n, 0.0)
  for i in 0.. Unit {
  let n = n0 * stride
  let tmp = Array::make(n, 0.0)
  for i in 0.. Unit {
  let lay = celt_tf_layout(n, b, tf_change)
  for k in 0..> k, 1 << k)
  }
  let mut bb = lay.b_start
  let mut nb = lay.nb_start
  let mut td = 0
  while td < lay.time_divide {
    celt_haar1(x, nb, bb)
    bb = bb * 2
    nb = nb / 2
    td = td + 1
  }
  if lay.deint_stride > 0 {
    celt_deinterleave(x, lay.deint_n0, lay.deint_stride, lay.long_blocks)
  }
}

///|
/// 反向 TF 变换:解码后作用于量化域的已解码向量,还原到频序。
pub fn celt_tf_inverse(
  x : Array[Double],
  n : Int,
  b : Int,
  tf_change : Int,
) -> Unit {
  let lay = celt_tf_layout(n, b, tf_change)
  if lay.deint_stride > 0 {
    celt_interleave(x, lay.deint_n0, lay.deint_stride, lay.long_blocks)
  }
  let mut bb = lay.b_end
  let mut nb = lay.nb_end
  let mut td = 0
  while td < lay.time_divide {
    bb = bb / 2
    nb = nb * 2
    celt_haar1(x, nb, bb)
    td = td + 1
  }
  for k in 0..> k, 1 << k)
  }
}