///|
/// Result of finalizing one analyzer stream.
pub struct MeasurementReport {
  priv integrated_lufs : Double?
  priv loudness_range_lu : Double?
  priv integrated_gate : IntegratedGateReport?
  priv lra_gate : LraGateReport?
  priv momentary_lufs : Double?
  priv short_term_lufs : Double?
  priv sample_peak_linear : Double
  priv channel_sample_peaks_linear : Array[Double]
  priv true_peak_linear : Double
  priv frame_count : Int32
  priv sample_rate : Int32
  priv integrated_distribution : LoudnessHistogram
  priv short_distribution : LoudnessHistogram
}

///|
/// Returns integrated loudness after absolute and relative gating.
pub fn MeasurementReport::integrated_lufs(self : MeasurementReport) -> Double? {
  self.integrated_lufs
}

///|
/// Returns gated short-term loudness range, if enough signal passed the gates.
pub fn MeasurementReport::loudness_range_lu(
  self : MeasurementReport,
) -> Double? {
  self.loudness_range_lu
}

///|
/// Returns the latest complete 400 ms measurement.
pub fn MeasurementReport::momentary_lufs(self : MeasurementReport) -> Double? {
  self.momentary_lufs
}

///|
/// Returns the latest complete 3 s measurement.
pub fn MeasurementReport::short_term_lufs(self : MeasurementReport) -> Double? {
  self.short_term_lufs
}

///|
/// Returns the largest absolute submitted PCM sample.
pub fn MeasurementReport::sample_peak_linear(
  self : MeasurementReport,
) -> Double {
  self.sample_peak_linear
}

///|
/// Returns an independent array of the largest submitted sample magnitude per channel.
pub fn MeasurementReport::channel_sample_peaks_linear(
  self : MeasurementReport,
) -> Array[Double] {
  let result : Array[Double] = []
  for peak in self.channel_sample_peaks_linear {
    result.push(peak)
  }
  result
}

///|
/// Returns one channel's peak or None when the channel index is invalid.
pub fn MeasurementReport::channel_sample_peak_linear(
  self : MeasurementReport,
  channel : Int32,
) -> Double? {
  if channel < 0 || channel >= self.channel_sample_peaks_linear.length() {
    None
  } else {
    Some(self.channel_sample_peaks_linear[channel])
  }
}

///|
/// Returns the overall four-phase FIR estimate after flushing the interpolation tail.
pub fn MeasurementReport::true_peak_linear(self : MeasurementReport) -> Double {
  self.true_peak_linear
}

///|
/// Returns the count of complete input frames accepted by the analyzer.
pub fn MeasurementReport::frame_count(self : MeasurementReport) -> Int32 {
  self.frame_count
}

///|
pub fn MeasurementReport::sample_rate(self : MeasurementReport) -> Int32 {
  self.sample_rate
}

///|
pub fn MeasurementReport::duration_seconds(self : MeasurementReport) -> Double {
  self.frame_count.to_double() / self.sample_rate.to_double()
}

///|
/// Converts positive linear amplitude to decibels relative to full scale.
fn amplitude_to_db(amplitude : Double) -> Double? {
  if amplitude <= 0.0 {
    None
  } else {
    Some(20.0 * @math.log10(amplitude))
  }
}

///|
/// Returns sample peak in dBFS; silence has no finite logarithmic value.
pub fn MeasurementReport::sample_peak_dbfs(self : MeasurementReport) -> Double? {
  amplitude_to_db(self.sample_peak_linear)
}

///|
/// Returns true peak in dBTP; silence has no finite logarithmic value.
pub fn MeasurementReport::true_peak_dbtp(self : MeasurementReport) -> Double? {
  amplitude_to_db(self.true_peak_linear)
}

///|
/// Finalizes the input and flushes the Annex 2 interpolation FIR tail.
pub fn Analyzer::finish(self : Analyzer) -> MeasurementReport {
  match self.cached_report {
    Some(report) => report
    None => {
      for _ in 0..<11 {
        self.push_true_peak_frame([][:], 0, false)
      }
      if self.sample_peak > self.true_peak_max {
        self.true_peak_max = self.sample_peak
      }
      if self.frame_count > 0 {
        if self.history.last_frame_count() == Some(self.frame_count) {
          self.history.replace_last(self.snapshot())
        } else {
          self.record_snapshot()
        }
      }
      let integrated_gate = self.calculate_integrated_gate()
      let lra_gate = self.calculate_lra_gate()
      let integrated_lufs = match integrated_gate {
        Some(gate) => Some(gate.integrated_lufs())
        None => None
      }
      let loudness_range_lu = match lra_gate {
        Some(gate) => Some(gate.loudness_range_lu())
        None => None
      }
      let report = {
        integrated_lufs,
        loudness_range_lu,
        integrated_gate,
        lra_gate,
        momentary_lufs: self.momentary_lufs(),
        short_term_lufs: self.short_term_lufs(),
        sample_peak_linear: self.sample_peak,
        channel_sample_peaks_linear: self.channel_sample_peaks_linear(),
        true_peak_linear: self.true_peak_max,
        frame_count: self.frame_count,
        sample_rate: self.config.sample_rate,
        integrated_distribution: self.integrated_distribution.clone(),
        short_distribution: self.short_distribution.clone(),
      }
      self.finished = true
      self.cached_report = Some(report)
      report
    }
  }
}

///|
/// Restarts the analyzer with the same immutable stream configuration.
pub fn Analyzer::reset(self : Analyzer) -> Unit {
  self.filters = new_filter_states(self.config.layout)
  self.sample_peak = 0.0
  for channel in 0..