///|
const DEMO_NOISE_SEED : UInt = 0x6D2B79F5U

///|
/// Encapsulates the mutable oscillator + noise state used by the browser
/// demo tick functions.  Each WASM entry point (root, browser/, browser_test/)
/// creates its own instance so module-level mutable globals stay per-package.
pub struct DemoSource {
  priv oscillator : Oscillator
  priv noise : Noise
}

///|
#alias(new)
pub fn DemoSource::DemoSource() -> DemoSource {
  { oscillator: Oscillator::new(), noise: Noise::new(DEMO_NOISE_SEED) }
}

///|
/// Reset oscillator and noise state to the start of the waveform.
pub fn DemoSource::reset(self : DemoSource) -> Unit {
  self.oscillator.reset()
  self.noise.reset(DEMO_NOISE_SEED)
}

///|
/// Generate one sample from the selected source.
///
/// Source ids:
/// - `0`: sine (default)
/// - `1`: saw
/// - `2`: square
/// - `3`: triangle
/// - `4`: noise
pub fn DemoSource::tick_source(
  self : DemoSource,
  source_id~ : Int,
  freq_hz~ : Double,
  sample_rate~ : Double,
) -> Double {
  match source_id {
    1 =>
      self.oscillator.tick_waveform(
        waveform=Waveform::Saw,
        freq_hz~,
        sample_rate~,
      )
    2 =>
      self.oscillator.tick_waveform(
        waveform=Waveform::Square,
        freq_hz~,
        sample_rate~,
      )
    3 =>
      self.oscillator.tick_waveform(
        waveform=Waveform::Triangle,
        freq_hz~,
        sample_rate~,
      )
    4 =>
      if !is_finite(sample_rate) || sample_rate <= 0.0 {
        0.0
      } else {
        self.noise.tick()
      }
    _ =>
      self.oscillator.tick_waveform(
        waveform=Waveform::Sine,
        freq_hz~,
        sample_rate~,
      )
  }
}