///|
fn number(value : Double?) -> String {
  match value {
    Some(x) => x.to_string()
    None => "null"
  }
}

///|
// Each asset gets fresh filter/window/gate state. The PCM block repeats every
// 100 ms, so reusing it is exact for the periodic 1 kHz input and bounds memory.
fn program(
  id : String,
  amplitude : Double,
  layout : @moonloudness.ChannelLayout,
  aggregator : @moonloudness.LoudnessAggregator,
) -> Unit {
  let config = match @moonloudness.MeterConfig::new(48000, layout) {
    Ok(value) => value
    Err(_) => panic()
  }
  let analyzer = @moonloudness.Analyzer::new(config)
  let block : Array[Double] = []
  for frame in 0..<4800 {
    let x = amplitude *
      @math.sin(2.0 * 3.141592653589793 * (frame % 48).to_double() / 48.0)
    for _ in 0.. ()
      Err(_) => panic()
    }
  }
  let report = analyzer.finish()
  // Illustrative delivery policy, not a broadcasting-standard acceptance test:
  // integrated target -23 +/-2 LU and maximum true peak -1 dBTP.
  let loudness_ok = match report.integrated_lufs() {
    Some(value) => value >= -25.0 && value <= -21.0
    None => false
  }
  let peak_ok = match report.true_peak_dbtp() {
    Some(value) => value <= -1.0
    None => false
  }
  match aggregator.add(report) {
    Ok(_) => ()
    Err(_) => panic()
  }
  println(
    "{\"kind\":\"program\",\"id\":\"" +
    id +
    "\",\"frames\":" +
    report.frame_count().to_string() +
    ",\"channels\":" +
    layout.channels().to_string() +
    ",\"integrated\":" +
    number(report.integrated_lufs()) +
    ",\"lra\":" +
    number(report.loudness_range_lu()) +
    ",\"sp\":" +
    number(report.sample_peak_dbfs()) +
    ",\"tp\":" +
    number(report.true_peak_dbtp()) +
    ",\"loudness_ok\":" +
    loudness_ok.to_string() +
    ",\"peak_ok\":" +
    peak_ok.to_string() +
    "}",
  )
}

///|
fn main {
  let aggregator = match @moonloudness.LoudnessAggregator::new(48000) {
    Ok(value) => value
    Err(_) => panic()
  }
  program("on_target", 0.1, @moonloudness.ChannelLayout::mono(), aggregator)
  program(
    "quiet_stereo",
    0.05,
    @moonloudness.ChannelLayout::stereo(),
    aggregator,
  )
  program("hot", 0.95, @moonloudness.ChannelLayout::mono(), aggregator)
  program("silence", 0.0, @moonloudness.ChannelLayout::mono(), aggregator)
  let batch = aggregator.finish()
  if batch.asset_count() != 4 || batch.frame_count() != 4 * 8 * 48000 {
    panic()
  }
  // Pooled distributions and maximum peaks of independent programs. This is
  // not concatenated PCM, does not invent cross-program windows, and must not
  // replace per-program QC with a single pooled normalization recommendation.
  println(
    "{\"kind\":\"aggregate\",\"assets\":" +
    batch.asset_count().to_string() +
    ",\"frames\":" +
    batch.frame_count().to_string() +
    ",\"duration\":" +
    batch.duration_seconds().to_string() +
    ",\"integrated\":" +
    number(batch.integrated_lufs()) +
    ",\"lra\":" +
    number(batch.loudness_range_lu()) +
    ",\"sp\":" +
    number(batch.sample_peak_dbfs()) +
    ",\"tp\":" +
    number(batch.true_peak_dbtp()) +
    "}",
  )
}