///|
/// Stateless hard-clipping processor for explicit range limiting.
pub struct Clip {}

///|
/// Create a clip processor.
#alias(new)
pub fn Clip::Clip() -> Clip {
  Clip::{  }
}

///|
/// Apply hard clipping in place using a symmetric threshold.
pub fn Clip::process(
  self : Clip,
  context~ : DspContext,
  buffer~ : AudioBuffer,
  threshold~ : Double,
) -> Unit {
  ignore(self)
  let sample_rate = context.sample_rate()
  let sample_count = effective_sample_count(context, buffer)
  if sample_rate <= 0.0 ||
    sample_count <= 0 ||
    threshold <= 0.0 ||
    !is_finite(threshold) {
    buffer.fill(0.0)
    return
  }

  for index = 0; index < sample_count; index = index + 1 {
    let sample = buffer.get(index)
    buffer.set(index, clip_sample(sample, threshold))
  }

  for index = sample_count; index < buffer.length(); index = index + 1 {
    buffer.set(index, 0.0)
  }
}

///|
fn clip_sample(sample : Double, threshold : Double) -> Double {
  if sample > threshold {
    threshold
  } else if sample < -threshold {
    -threshold
  } else {
    sample
  }
}