{-# OPTIONS -fno-implicit-prelude #-}
{- | Noise and random processes. -}
module Synthesizer.Generic.Noise where

import qualified Synthesizer.Generic.Signal as SigG
import qualified Synthesizer.Generic.SampledValue as Sample

import qualified Algebra.Real                  as Real
import qualified Algebra.Ring                  as Ring

import System.Random (Random, RandomGen, randomR, mkStdGen, )
import qualified System.Random as Rnd

import qualified Prelude as P
import PreludeBase
import NumericPrelude


{-|
Deterministic white noise, uniformly distributed between -1 and 1.
That is, variance is 1\/3.
-}
white ::
   (Ring.C y, Random y, Sample.C y, SigG.C sig) =>
   sig y
white = whiteGen (mkStdGen 12354)

whiteGen ::
   (Ring.C y, Random y, RandomGen g, Sample.C y, SigG.C sig) =>
   g -> sig y
whiteGen =
   SigG.unfoldR (Just . randomR (-1,1))


{- |
Approximates normal distribution with variance 1
by a quadratic B-spline distribution.
-}
whiteQuadraticBSplineGen ::
   (Ring.C y, Random y, RandomGen g, Sample.C y, SigG.C sig) =>
   g -> sig y
whiteQuadraticBSplineGen g =
   let (g0,gr) = Rnd.split g
       (g1,g2) = Rnd.split gr
   in  whiteGen g0 `SigG.mix`
       whiteGen g1 `SigG.mix`
       whiteGen g2


randomPeeks ::
   (Real.C y, Random y, Sample.C y, SigG.C sig) =>
      sig y    {- ^ momentary densities, @p@ means that there is about one peak
                      in the time range of @1\/p@ samples -}
   -> sig Bool {- ^ Every occurence of 'True' represents a peak. -}
randomPeeks =
   randomPeeksGen (mkStdGen 876)

randomPeeksGen ::
   (Real.C y, Random y, RandomGen g, Sample.C y, SigG.C sig) =>
      g
   -> sig y
   -> sig Bool
randomPeeksGen =
   SigG.zipWith (<) . SigG.unfoldR (Just . randomR (0,1))