// floor0.mbt
//
// Vorbis floor 0:用 LSP(线谱对)系数描述频谱包络。
//
// floor 1 用一组关键点插值出包络,floor 0 则每帧给出 order 个 LSP 系数和一个
// 幅度,再按 Bark 刻度把系数映射到线性频点上求值,得到逐样本的增益曲线。
// 两者都只是「给出一条曲线,由 residue 乘上去」,区别在曲线的表示方式。

///|
/// floor0 的配置。
pub struct Floor0 {
  order : Int
  rate : Int
  bark_map_size : Int
  amplitude_bits : Int
  amplitude_offset : Int
  books : Array[Int]
}

///|
/// 线性频率到 Bark 频带的换算。
///
/// 常数按单精度取值再提升为双精度:参考实现里这些字面量都是 `f` 后缀的
/// float,参与运算时被提升到 double,用双精度的字面量会引入偏差。
fn to_bark(x : Double) -> Double {
  let a : Float = 0.00074
  let b : Float = 0.0000000185
  let c : Float = 0.0001
  let scale1 : Float = 13.1
  let scale2 : Float = 2.24
  scale1.to_double() * @math.atan(a.to_double() * x) +
  scale2.to_double() * @math.atan(x * x * b.to_double()) +
  c.to_double() * x
}

///|
/// 解析 floor0 配置。
///
/// `codebooks` 用于校验 book 编号,并要求被引用的码本带 lookup table
/// (maptype != 0)且维度大于 0——否则取不出 LSP 系数。
pub fn Floor0::parse(
  br : BitReader,
  codebooks : Array[Codebook],
) -> Result[Floor0, String] {
  let order = br.read_bits(8)
  let rate = br.read_bits(16)
  let bark_map_size = br.read_bits(16)
  let amplitude_bits = br.read_bits(6)
  let amplitude_offset = br.read_bits(8)
  let book_count = br.read_bits(4) + 1

  if order < 1 {
    return Err("floor0 order is zero")
  }
  if rate < 1 {
    return Err("floor0 rate is zero")
  }
  if bark_map_size < 1 {
    return Err("floor0 bark map size is zero")
  }

  let books : Array[Int] = []
  for _ in 0..= codebooks.length() {
      return Err("floor0 book index out of range")
    }
    if codebooks[number].lookup_type == 0 {
      return Err("floor0 book has no lookup table")
    }
    if codebooks[number].dimensions < 1 {
      return Err("floor0 book dimensions is zero")
    }
    books.push(number)
  }

  Ok({ order, rate, bark_map_size, amplitude_bits, amplitude_offset, books, })
}

///|
/// 解析一帧的 floor0 数据,返回 `order` 个 LSP 系数外加末尾的幅度。
///
/// 幅度为 0、book 号越界或比特流耗尽时返回 `None`——这几种情况在参考实现里
/// 都表示「本帧无 floor 数据」,对应声道按静音处理,而不是解码失败。
pub fn Floor0::decode(
  self : Floor0,
  br : BitReader,
  codebooks : Array[Codebook],
) -> Result[Array[Float]?, String] {
  if br.remaining_bits() < self.amplitude_bits {
    return Ok(None)
  }
  let amplitude_raw = br.read_bits(self.amplitude_bits)
  if amplitude_raw <= 0 {
    return Ok(None)
  }
  let max_value = (1 << self.amplitude_bits) - 1
  let amplitude = Float::from_int(amplitude_raw) /
    Float::from_int(max_value) *
    Float::from_int(self.amplitude_offset)

  let book_bits = ilog(self.books.length())
  if br.remaining_bits() < book_bits {
    return Ok(None)
  }
  let book_number = br.read_bits(book_bits)
  if book_number < 0 || book_number >= self.books.length() {
    return Ok(None)
  }
  let book = codebooks[self.books[book_number]]

  let lsp : Array[Float] = []
  for _ in 0.. ()
    // 码字读尽同样按「本帧无 floor 数据」处理
    Err(_) => return Ok(None)
  }

  // 码本按维度分块给出系数:每一块都加上前一块最后一个值,累加量逐块传递。
  let mut j = 0
  let mut last : Float = 0.0
  while j < self.order {
    let mut k = 0
    while j < self.order && k < book.dimensions {
      lsp[j] = lsp[j] + last
      j += 1
      k += 1
    }
    last = lsp[j - 1]
  }

  lsp.push(amplitude)
  Ok(Some(lsp))
}

///|
/// 第二阶段:把 LSP 系数还原成完整增益曲线(长度 `n2`)。
///
/// 先按 Bark 刻度算出每个线性频点落在哪个频带,再对每个频带求一次
/// 分母多项式的值,同一频带内的样本共用这个结果。
///
/// 参考实现里多项式在单精度下计算,而取整频带、取余弦、最后取指数这几步
/// 都走了双精度——频带下标是取整来的,差一点就换一个频带,所以这里逐处
/// 按同样的精度处理,不统一成一种。
pub fn Floor0::synthesize(
  self : Floor0,
  memo : Array[Float],
  n2 : Int,
) -> Array[Float] {
  let order = self.order
  let bark_map_size = self.bark_map_size
  let pi : Double = 3.141592653589793
  let half_rate : Float = Float::from_int(self.rate) / 2.0

  // 频带映射:线性频点 j 对应的 Bark 频带下标。取值非负,截断即向下取整。
  let scale : Float = Float::from_double(
    Double::from_int(bark_map_size) / to_bark(half_rate.to_double()),
  )
  let band_map : Array[Int] = []
  for j in 0..= bark_map_size {
      band = bark_map_size - 1
    }
    band_map.push(band)
  }

  let lsp : Array[Float] = []
  for i in 0..