///|
/// Deterministic white-noise source with explicit RNG state.
pub struct Noise {
  priv mut state : UInt
}

///|
/// Create a new white-noise generator from an explicit seed.
#alias(new)
pub fn Noise::Noise(seed : UInt) -> Noise {
  { state: normalize_seed(seed) }
}

///|
/// Expose the current RNG state for testing and diagnostics.
pub fn Noise::seed(self : Noise) -> UInt {
  self.state
}

///|
/// Reset the generator to a new explicit seed.
pub fn Noise::reset(self : Noise, seed : UInt) -> Unit {
  self.state = normalize_seed(seed)
}

///|
/// Generate one white-noise sample in the range `[-1.0, 1.0]`.
pub fn Noise::tick(self : Noise) -> Double {
  self.state = next_state(self.state)
  sample_from_state(self.state)
}

///|
/// Fill an output buffer with white-noise samples.
pub fn Noise::process(
  self : Noise,
  context : DspContext,
  output : AudioBuffer,
) -> Unit {
  let sample_rate = context.sample_rate()
  let sample_count = effective_sample_count(context, output)

  if !is_finite_positive(sample_rate) || sample_count <= 0 {
    output.fill(0.0)
    return
  }

  for index = 0; index < sample_count; index = index + 1 {
    output.set(index, self.tick())
  }

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

///|
fn normalize_seed(seed : UInt) -> UInt {
  if seed == 0U {
    0x6D2B79F5U
  } else {
    seed
  }
}

///|
fn next_state(state : UInt) -> UInt {
  normalize_seed(state * 1664525U + 1013904223U)
}

///|
fn sample_from_state(state : UInt) -> Double {
  state.to_double() / 2147483648.0 - 1.0
}