-- | Functions to generate break point data for standard envelope -- types. module Sound.SC3.UGen.Envelope.Construct (env ,envCoord ,envTrapezoid ,envPerc', envPerc ,envTriangle ,envSine ,envLinen', envLinen ,envADSR, envASR) where import Sound.SC3.UGen.UGen import Sound.SC3.UGen.Math import Sound.SC3.UGen.Enum -- | Basic envelope data constructor. The curve argument are cycled -- if required. env :: [UGen] -> [UGen] -> [EnvCurve] -> UGen -> UGen -> [UGen] env [] _ _ _ _ = error "env: illegal specification" env (l:ls) tms crv rls lp = let f l' t c = [l', t, env_curve c, env_value c] n = length tms n' = fromIntegral n crv' = take n (cycle crv) in [l, n', rls, lp] ++ concat (zipWith3 f ls tms crv') -- | Co-ordinate based static envelope generator. envCoord :: [(UGen, UGen)] -> UGen -> UGen -> EnvCurve -> [UGen] envCoord bp dur amp c = let l = map ((* amp) . snd) bp t = map (* dur) (d_dx (map fst bp)) in env l t (repeat c) (-1) (-1) {- | Trapezoidal envelope generator. The arguments are: 1. @shape@ determines the sustain time as a proportion of @dur@, zero is a triangular envelope, one a rectangular envelope; 2. @skew@ determines the attack\/decay ratio, zero is an immediate attack and a slow decay, one a slow attack and an immediate decay; 3. @duration@ in seconds; 4. @amplitude@ as linear gain. -} envTrapezoid :: UGen -> UGen -> UGen -> UGen -> [UGen] envTrapezoid shape skew dur amp = let x1 = skew * (1 - shape) bp = [ (0, skew <=* 0) , (x1, 1) , (shape + x1, 1) , (1, skew >=* 1) ] in envCoord bp dur amp EnvLin envPerc' :: UGen -> UGen -> UGen -> (EnvCurve, EnvCurve) -> [UGen] envPerc' atk rls lvl (c0, c1) = let c = [c0, c1] in env [0.0, lvl, 0.0] [atk, rls] c (-1.0) (-1.0) -- | Percussive envelope, with attack, release, level and curve -- inputs. envPerc :: UGen -> UGen -> [UGen] envPerc atk rls = let cn = EnvNum (-4.0) in envPerc' atk rls 1.0 (cn, cn) -- | Triangular envelope, with duration and level inputs. envTriangle :: UGen -> UGen -> [UGen] envTriangle dur lvl = let c = replicate 2 EnvLin d = replicate 2 (dur / 2.0) in env [0.0, lvl, 0.0] d c (-1.0) (-1.0) -- | Sine envelope, with duration and level inputs. envSine :: UGen -> UGen -> [UGen] envSine dur lvl = let c = replicate 2 EnvSin d = replicate 2 (dur / 2.0) in env [0.0, lvl, 0.0] d c (-1.0) (-1.0) envLinen' :: UGen -> UGen -> UGen -> UGen -> (EnvCurve, EnvCurve, EnvCurve) -> [UGen] envLinen' aT sT rT l (c0, c1, c2) = env [0, l, l, 0] [aT, sT, rT] [c0, c1, c2] (-1) (-1) -- | Linear envelope parameter constructor. envLinen :: UGen -> UGen -> UGen -> UGen -> [UGen] envLinen aT sT rT l = let c = (EnvLin, EnvLin, EnvLin) in envLinen' aT sT rT l c -- aT = attackTime -- dT = decayTime -- sL = sustainLevel -- rT = releaseTime -- pL = peakLevel -- c = curve -- b = bias -- | Attack, decay, sustain, release envelope parameter constructor. envADSR :: UGen -> UGen -> UGen -> UGen -> UGen -> EnvCurve -> UGen -> [UGen] envADSR aT dT sL rT pL c b = let l = map (+ b) [0,pL,pL*sL,0] t = [aT,dT,rT] c' = [c,c,c] in env l t c' 2 (-1) -- | Attack, sustain, release envelope parameter constructor. envASR :: UGen -> UGen -> UGen -> EnvCurve -> [UGen] envASR aT sL rT c = let l = [0,sL,0] t = [aT,rT] c' = [c,c] in env l t c' 1 (-1) d_dx :: (Num a) => [a] -> [a] d_dx xs = zipWith (-) (drop 1 xs) xs env_curve :: EnvCurve -> UGen env_curve EnvStep = Constant 0.0 env_curve EnvLin = Constant 1.0 env_curve EnvExp = Constant 2.0 env_curve EnvSin = Constant 3.0 env_curve EnvCos = Constant 4.0 env_curve (EnvNum _) = Constant 5.0 env_curve EnvSqr = Constant 6.0 env_curve EnvCub = Constant 7.0 env_value :: EnvCurve -> UGen env_value (EnvNum u) = u env_value _ = Constant 0.0