module Synthesizer.Generic.Control where
import qualified Synthesizer.Generic.Signal as SigG
import qualified Synthesizer.Generic.SampledValue as Sample
import Synthesizer.Generic.Displacement (raise)
import qualified Algebra.Module as Module
import qualified Algebra.Transcendental as Trans
import qualified Algebra.RealField as RealField
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import Algebra.Module((*>))
import Number.Complex (cis,real)
import qualified Prelude as P
import PreludeBase
import NumericPrelude
constant :: (Sample.C y, SigG.C sig) => y -> sig y
constant = SigG.repeat
linear :: (Additive.C y, Sample.C y, SigG.C sig) =>
y
-> y
-> sig y
linear d y0 = SigG.iterate (d+) y0
linearMultiscale :: (Additive.C y, Sample.C y, SigG.C sig) =>
y
-> y
-> sig y
linearMultiscale = curveMultiscale (+)
linearMultiscaleNeutral :: (Additive.C y, Sample.C y, SigG.C sig) =>
y
-> sig y
linearMultiscaleNeutral slope =
curveMultiscaleNeutral (+) slope zero
exponential, exponentialMultiscale :: (Trans.C y, Sample.C y, SigG.C sig) =>
y
-> y
-> sig y
exponential time = SigG.iterate (* exp ( recip time))
exponentialMultiscale time = curveMultiscale (*) (exp ( recip time))
exponentialMultiscaleNeutral :: (Trans.C y, Sample.C y, SigG.C sig) =>
y
-> sig y
exponentialMultiscaleNeutral time =
curveMultiscaleNeutral (*) (exp ( recip time)) one
exponential2, exponential2Multiscale :: (Trans.C y, Sample.C y, SigG.C sig) =>
y
-> y
-> sig y
exponential2 halfLife = SigG.iterate (* 0.5 ** recip halfLife)
exponential2Multiscale halfLife = curveMultiscale (*) (0.5 ** recip halfLife)
exponential2MultiscaleNeutral :: (Trans.C y, Sample.C y, SigG.C sig) =>
y
-> sig y
exponential2MultiscaleNeutral halfLife =
curveMultiscaleNeutral (*) (0.5 ** recip halfLife) one
vectorExponential ::
(Trans.C y, Module.C y v, Sample.C v, SigG.C sig) =>
y
-> v
-> sig v
vectorExponential time y0 = SigG.iterate (exp (1/time) *>) y0
vectorExponential2 ::
(Trans.C y, Module.C y v, Sample.C v, SigG.C sig) =>
y
-> v
-> sig v
vectorExponential2 halfLife y0 = SigG.iterate (0.5**(1/halfLife) *>) y0
cosine, cosineMultiscale :: (Trans.C y, Sample.C y, SigG.C sig) =>
y
-> y
-> sig y
cosine = cosineWithSlope $
\d x -> SigG.map cos (linear d x)
cosineMultiscale = cosineWithSlope $
\d x -> SigG.map real (curveMultiscale (*) (cis d) (cis x))
cosineWithSlope :: (Trans.C y) =>
(y -> y -> signal)
-> y
-> y
-> signal
cosineWithSlope c t0 t1 =
let inc = pi/(t1t0)
in c inc (t0*inc)
cubicHermite :: (Field.C y, Sample.C y, SigG.C sig) =>
(y, (y,y)) -> (y, (y,y)) -> sig y
cubicHermite node0 node1 =
SigG.map (cubicFunc node0 node1) (linear 1 0)
cubicFunc :: (Field.C y) =>
(y, (y,y)) -> (y, (y,y)) -> y -> y
cubicFunc (t0, (y0,dy0)) (t1, (y1,dy1)) t =
let dt = t0t1
dt0 = tt0
dt1 = tt1
x0 = dt1^2
x1 = dt0^2
in ((dy0*dt0 + y0 * (12/dt*dt0)) * x0 +
(dy1*dt1 + y1 * (1+2/dt*dt1)) * x1) / dt^2
data Control y =
CtrlStep
| CtrlLin
| CtrlExp {ctrlExpSaturation :: y}
| CtrlCos
| CtrlCubic {ctrlCubicGradient0 :: y,
ctrlCubicGradient1 :: y}
deriving (Eq, Show)
data ControlPiece y =
ControlPiece {pieceType :: Control y,
pieceY0 :: y,
pieceY1 :: y,
pieceDur :: y}
deriving (Eq, Show)
newtype PieceRightSingle y = PRS y
newtype PieceRightDouble y = PRD y
type ControlDist y = (y, Control y, y)
infixr 5 -|#, #|-, =|#, #|=, |#, #|
( #|-) :: (y, Control y) -> (PieceRightSingle y, [ControlPiece y]) ->
(ControlDist y, [ControlPiece y])
(d,c) #|- (PRS y1, xs) = ((d,c,y1), xs)
(-|#) :: y -> (ControlDist y, [ControlPiece y]) ->
(PieceRightSingle y, [ControlPiece y])
y0 -|# ((d,c,y1), xs) = (PRS y0, ControlPiece c y0 y1 d : xs)
( #|=) :: (y, Control y) -> (PieceRightDouble y, [ControlPiece y]) ->
(ControlDist y, [ControlPiece y])
(d,c) #|= (PRD y1, xs) = ((d,c,y1), xs)
(=|#) :: (y,y) -> (ControlDist y, [ControlPiece y]) ->
(PieceRightDouble y, [ControlPiece y])
(y01,y10) =|# ((d,c,y11), xs) = (PRD y01, ControlPiece c y10 y11 d : xs)
( #|) :: (y, Control y) -> y ->
(ControlDist y, [ControlPiece y])
(d,c) #| y1 = ((d,c,y1), [])
(|#) :: y -> (ControlDist y, [ControlPiece y]) ->
[ControlPiece y]
y0 |# ((d,c,y1), xs) = ControlPiece c y0 y1 d : xs
piecewise :: (Trans.C y, RealField.C y, Sample.C y, SigG.C sig) =>
[ControlPiece y] -> sig y
piecewise xs =
let ts = scanl (\(_,fr) d -> splitFraction (fr+d))
(0,1) (map pieceDur xs)
in SigG.concat (zipWith3
(\n t (ControlPiece c yi0 yi1 d) ->
piecewisePart yi0 yi1 t d n c)
(map fst (tail ts)) (map (subtract 1 . snd) ts)
xs)
piecewisePart :: (Trans.C y, Sample.C y, SigG.C sig) =>
y -> y -> y -> y -> Int -> Control y -> sig y
piecewisePart y0 y1 t0 d n ctrl =
SigG.take n
(case ctrl of
CtrlStep -> constant y0
CtrlLin -> let s = (y1y0)/d in linearMultiscale s (y0t0*s)
CtrlExp s -> let y0' = y0s; y1' = y1s; yd = y0'/y1'
in raise s (exponentialMultiscale (d / log yd)
(y0' * yd**(t0/d)))
CtrlCos -> SigG.map
(\y -> (1+y)*(y0/2)+(1y)*(y1/2))
(cosineMultiscale t0 (t0+d))
CtrlCubic yd0 yd1 ->
cubicHermite (t0,(y0,yd0)) (t0+d,(y1,yd1)))
curveMultiscale :: (Sample.C y, SigG.C sig) =>
(y -> y -> y) -> y -> y -> sig y
curveMultiscale op d y0 =
SigG.cons y0 (SigG.map (op y0) (SigG.iterateAssoc op d))
curveMultiscaleNeutral :: (Sample.C y, SigG.C sig) =>
(y -> y -> y) -> y -> y -> sig y
curveMultiscaleNeutral op d neutral =
SigG.cons neutral (SigG.iterateAssoc op d)