-- | **Note:** The argument format for these is a little -- rough, and is likely to change in the future {-# LANGUAGE DataKinds , LambdaCase , OverloadedStrings , ScopedTypeVariables , TypeFamilies, NoMonoLocalBinds , ViewPatterns , FlexibleContexts , NoIncoherentInstances , NoMonomorphismRestriction , NoUndecidableInstances #-} module Vivid.UGens.Envelopes ( -- In UGens.Filters.Linear: -- decay -- In UGens.Filters.Linear: -- , decay2 -- In Vivid.UGens.Demand: -- , demandEnvGen adsrGen --- , dadsrGen , envGate , envGen , envGen_wGate --- , iEnvGen , line , linen , percGen , xLine ) where import Vivid.Envelopes import Vivid.SC.SynthDef.Types (CalculationRate(..)) import Vivid.SynthDef import Vivid.SynthDef.FromUA -- import Vivid.SynthDef.TypesafeArgs import Vivid.UGens.Args import Vivid.UGens.Algebraic import GHC.TypeLits -- import qualified Data.Map as Map import Data.Monoid import Data.Proxy -- | Defaults to 'AR' adsrGen :: (Args '[] '["peakLevel", {- "curve", -} "bias", "gate", "doneAction"] as, ToSig attackTime (SDBodyArgs as), ToSig decayTime (SDBodyArgs as), ToSig sustainLevel (SDBodyArgs as), ToSig releaseTime (SDBodyArgs as)) => attackTime -> decayTime -> sustainLevel -> releaseTime -> EnvCurve -> as -> SDBody as Signal adsrGen attackTime decayTime sustainLevel releaseTime curve userArgs = do attackTime' <- toSig attackTime decayTime' <- toSig decayTime sustainLevel' <- toSig sustainLevel releaseTime' <- toSig releaseTime peakLevel <- uaArgValWDefault (1::Float) userArgs (Proxy::Proxy "peakLevel") bias <- uaArgValWDefault (0::Float) userArgs (Proxy::Proxy "bias") doneAction <- uaArgValWDefault (0::Float) userArgs (Proxy::Proxy "doneAction") gate <- uaArgValWDefault (1::Float) userArgs (Proxy::Proxy "gate") peakXSustain <- peakLevel ~* sustainLevel' let plusBias :: (Signal, Signal) -> SDBody' a (Signal, Signal) plusBias (a, b) = do a' <- bias ~+ a return (a', b) biasPlusCurveSegs <- mapM plusBias [ (peakLevel, attackTime') , (peakXSustain, decayTime') , (Constant 0, releaseTime') ] -- maybe write in terms of 'dadsr' ^^ signals <- envLiterallyToSignals $ EnvLiterally { _envLiterally_initialVal = bias , _envLiterally_releaseNode = Just 2 , _envLiterally_offset = 0 , _envLiterally_loopNode = Nothing , _envLiterally_curveSegments = map (\(a,b)->EnvSegment a b curve) biasPlusCurveSegs } addUGen $ UGen (UGName_S "EnvGen") AR ([ gate , Constant 1 -- levelScale , Constant 0 -- levelBias , Constant 1 -- timeScale , doneAction -- doneActionNum doneAction ] <> signals) 1 --- dadsrGen :: --- dadsrGen = -- TODO: do we need 'fadeSecs' anymore? maybe we should just use 'releaseIn'... envGate :: Subset '["gate","fadeSecs"] a => SDBody' a Signal envGate = do -- Le -- less than or equal gate <- biOp Le (V::V "fadeSecs") (0::Float) let theEnv = EnvLiterally { _envLiterally_initialVal = gate , _envLiterally_releaseNode = Just 1 , _envLiterally_offset = 0 , _envLiterally_loopNode = Nothing , _envLiterally_curveSegments = [ EnvSegment (Constant 1) (Constant 1) Curve_Sin , EnvSegment (Constant 0) (Constant 1) Curve_Sin ] } envGen_wGate (V::V "gate") (V::V "fadeSecs") theEnv FreeEnclosing -- | Defaults to 'AR' envGen :: EnvLiterally a -> DoneAction -> SDBody' a Signal envGen theEnv doneAction = do curveSignals <- envLiterallyToSignals theEnv addUGen $ UGen (UGName_S "EnvGen") AR ([ Constant 1 -- gate , Constant 1 -- levelScale , Constant 0 -- levelBias , Constant 1 -- timeScale , Constant $ doneActionNum doneAction ] <> curveSignals) 1 envGen_wGate :: (ToSig gate a, ToSig timeScale a) => gate -> timeScale -> EnvLiterally a -> DoneAction -> SDBody' a Signal envGen_wGate gate timeScale theEnv doneAction = do gate' <- toSig gate timeScale' <- toSig timeScale curveSignals <- envLiterallyToSignals theEnv addUGen $ UGen (UGName_S "EnvGen") AR ([ gate' -- Constant 1 -- gate , Constant 1 -- levelScale , Constant 0 -- levelBias , timeScale' -- , Constant 1 -- timeScale , Constant $ doneActionNum doneAction ] <> curveSignals) 1 --- iEnvGen :: --- iEnvGen = -- | \"Generates a line from the start value to the end value.\" -- -- Note this won't change after it's created, so if you'd like -- to e.g. be able to change the \"freq\" in -- -- > line (start_ 0, end_ (V::V "freq")) -- -- you should write -- -- > (V::V "freq") ~* line (start_ 0, end_ 1) -- -- instead. -- -- Defaults to KR line :: (Args '[] '["start","end","duration","doneAction"] a) => a -> SDBody a Signal line = makeUGen "Line" AR (Vs::Vs '["start","end","duration","doneAction"]) (start_ (0::Float), end_ (0::Float), duration_ (1::Float), doneAction_ (0::Float)) -- | "Simple linear envelope generator" -- -- Can't change after it's created -- see the note about 'line' if you want it to -- -- Only computes at "KR" linen :: (Args '[] '["gate", "attackSecs", "susLevel", "releaseSecs", "doneAction"] a) => a -> SDBody a Signal linen = makeUGen "Linen" KR (Vs::Vs '["gate", "attackSecs", "susLevel", "releaseSecs", "doneAction"]) (gate_ (1::Float), attackTime_ (0.01::Float), susLevel_ (1::Float), releaseTime_ (1::Float), doneAction_ (0::Float)) -- | Percussive hit -- -- 'doneAction' is currently 2 but may either be 0 or 2 in future versions percGen :: (Args '[] '["attackSecs", "releaseSecs", "level", "curve", "doneAction", "gate", "fadeSecs"] a) => a -> SDBody a Signal percGen userArgs = do level <- uaArgWDef_onlyConst (1::Float) userArgs (V::V "level") attackTime <- uaArgWDef_onlyConst (0.01::Float) userArgs (V::V "attackSecs") releaseTime <- uaArgWDef_onlyConst (1::Float) userArgs (V::V "releaseSecs") curve <- uaArgWDef_onlyConst (-4::Float) userArgs (V::V "curve") doneAction <- fromEnum <$> uaArgWDef_onlyConst (2::Float) userArgs (V::V "doneAction") gate <- uaArgValWDefault 1 userArgs (V::V "gate") timeScale <- uaArgValWDefault 1 userArgs (V::V "fadeSecs") envGen_wGate gate timeScale (env 0 [(level, attackTime), (0, releaseTime)] (Curve_Curve curve)) (DoneAction_AsNum doneAction) where uaArgWDef_onlyConst defaultVal args argName = uaArgValWDefault defaultVal args argName >>= \case Constant x -> return x _ -> error $ "bad argument type: "<>show (symbolVal argName)<>" wasn't a Constant" -- | \"Generates an exponential curve from the start value to the end value. Both the start and end values must be non-zero and have the same sign.\" -- -- Defaults to KR xLine :: (Args '[] '["start","end","duration","doneAction"] a) => a -> SDBody a Signal xLine = makeUGen "XLine" KR (Vs::Vs '["start","end","duration","doneAction"]) (start_ (1::Float), end_ (2::Float), duration_ (1::Float), doneAction_ (0::Float))