```{- |
Copyright   :  (c) Henning Thielemann 2008

Maintainer  :  synthesizer@henning-thielemann.de
Stability   :  provisional
Portability :  requires multi-parameter type classes

Control curves which can be used
as envelopes, for controlling filter parameters and so on.
-}
module Synthesizer.Dimensional.Rate.Control
({- * Primitives -}
constant, linear, exponential, exponential2, )
where

import qualified Synthesizer.Dimensional.Straight.Signal as SigS

import qualified Synthesizer.State.Control as Ctrl
-- import qualified Synthesizer.State.Signal  as Sig

import qualified Synthesizer.Dimensional.Process as Proc

-- import Synthesizer.Dimensional.Process ((\$#), )

import qualified Number.DimensionTerm        as DN
import qualified Algebra.DimensionTerm       as Dim

-- import Number.DimensionTerm ((&*&))

import qualified Algebra.Transcendental     as Trans
import qualified Algebra.Field              as Field
-- import qualified Algebra.Real               as Real
import qualified Algebra.Ring               as Ring

import NumericPrelude
import PreludeBase
import Prelude ()

{-# INLINE constant #-}
constant :: (Ring.C y, Dim.C u) =>
Proc.T s u t (SigS.R s y)
constant = Proc.pure \$ SigS.fromSamples \$ Ctrl.constant one

{- |
Caution: This control curve can contain samples
with an absolute value greater than 1.
The linear curve starts with zero.
-}
{-# INLINE linear #-}
linear ::
(Field.C q, Dim.C u) =>
DN.T u q {-^ distance until curve reaches one -}
-> Proc.T s u q (SigS.R s q)
linear dist =
fmap
(SigS.fromSamples . Ctrl.linearMultiscaleNeutral . recip)
(Proc.toTimeScalar dist)

{-# INLINE exponential #-}
exponential :: (Trans.C q, Dim.C u) =>
DN.T u q {-^ time where the function reaches 1\/e of the initial value -}
-> Proc.T s u q (SigS.R s q)
exponential time =
fmap
(SigS.fromSamples . Ctrl.exponentialMultiscaleNeutral)
(Proc.toTimeScalar time)

{-
take 1000 \$ show (run (fixSampleRate 100 (exponential 0.1 1)) :: SigDouble)
-}

{-# INLINE exponential2 #-}
exponential2 :: (Trans.C q, Dim.C u) =>
DN.T u q {-^ half life, time where the function reaches 1\/2 of the initial value -}
-> Proc.T s u q (SigS.R s q)
exponential2 time =
fmap
(SigS.fromSamples . Ctrl.exponential2MultiscaleNeutral)
(Proc.toTimeScalar time)
```