-- | Envelopes. **This module is the least mature in vivid and is likely to -- change a lot in the future!** {-# OPTIONS_HADDOCK show-extensions #-} {-# LANGUAGE DataKinds , ExistentialQuantification , KindSignatures , LambdaCase , NoIncoherentInstances , NoMonomorphismRestriction , NoUndecidableInstances , FlexibleContexts #-} module Vivid.Envelopes ( EnvLiterally(..) , envLiterallyToSignals , env , EnvCurve(..) , EnvSegment(..) , shapeNumber , curveNumber ) where import Vivid.SynthDef.ToSig (ToSig(..)) -- , SDBody) import Vivid.SynthDef.Types -- import Vivid.SynthDef.FromUA (fromUA, Args) -- import Data.Int import Data.Monoid import GHC.TypeLits import Prelude -- BBP data EnvLiterally (args :: [Symbol]) = forall initial. (ToSig initial args) => EnvLiterally { _envLiterally_initialVal :: initial -- ,_envLiterally_numSegments :: Int -- i know this is a 'Literally' but it's so computable... , _envLiterally_releaseNode :: Maybe Int , _envLiterally_offset :: Float -- ?? -- only used for 'IEnvGen', which i dont have -- invariant: releasenode must be larger (or equal?) to/than loopnode -- also, if one is Just, i think the other must be -- so if that's true, use -- a different data structure -- at least for the non-'Literally' one , _envLiterally_loopNode :: Maybe Int , _envLiterally_curveSegments :: [EnvSegment] } -- deriving (Show, Eq) {- InputSpec_UGen {_inputSpec_uGen_index = 2, _inputSpec_uGen_outputIndex = 0} Constant: 2.0 (index 2) -- length segments Constant: 1.0 (index 1) -- release node Constant: -99.0 (index 3) -- loop node signals?: Constant: 1.0 (index 1) Constant: 1.0 (index 1) Constant: 3.0 (index 4) Constant: 0.0 (index 0) Constant: 0.0 (index 0) Constant: 1.0 (index 1) Constant: 3.0 (index 4) Constant: 0.0 (index 0) -} -- i think this is (only) for the arguments to EnvGen: envLiterallyToSignals :: EnvLiterally (b::[Symbol]) -> SDBody' b [Signal] envLiterallyToSignals envLiterally@(EnvLiterally a _ _ _ _) = do {- foo <- case _envLiterally_initialVal envLiterally of x -> toSigM $ x -} foo <- toSig a return $ [ foo , Constant . toEnum . (length::[a]->Int) $ _envLiterally_curveSegments envLiterally , Constant $ case _envLiterally_releaseNode envLiterally of Just x -> toEnum x Nothing -> (-99) , Constant $ case _envLiterally_loopNode envLiterally of Just x -> toEnum x Nothing -> (-99) ] <> concatMap envSegmentToSignals (_envLiterally_curveSegments envLiterally) where envSegmentToSignals :: EnvSegment -> [Signal] envSegmentToSignals envSegment = [ _envSegment_targetVal envSegment , _envSegment_timeToGetThere envSegment , Constant $ envCurveNumber $ _envSegment_curve envSegment , Constant $ envCurveFloatNumber $ _envSegment_curve envSegment ] data EnvSegment = EnvSegment { _envSegment_targetVal :: Signal , _envSegment_timeToGetThere :: Signal , _envSegment_curve :: EnvCurve } deriving (Show, Eq) data EnvCurve = Curve_Step | Curve_Linear | Curve_Lin | Curve_Exponential | Curve_Exp | Curve_Sine | Curve_Sin | Curve_Welch | Curve_Wel | Curve_Squared | Curve_Sqr | Curve_Cubed | Curve_Cub | Curve_Curve Float -- ^ 0 is linear, positive curves up, negative curves down deriving (Show, Eq) -- | Same as \"Env.shapeNumber\" in SC. -- -- This is useful if you want to set a the env shape of a running synth shapeNumber :: EnvCurve -> Float shapeNumber = envCurveNumber -- | "shapeNumber" with a name I like better curveNumber :: EnvCurve -> Float curveNumber = shapeNumber envCurveNumber :: EnvCurve -> Float envCurveNumber = \case Curve_Step -> 0 Curve_Linear -> 1 Curve_Lin -> 1 Curve_Exponential -> 2 Curve_Exp -> 2 Curve_Sine -> 3 Curve_Sin -> 3 Curve_Welch -> 4 Curve_Wel -> 4 Curve_Squared -> 6 Curve_Sqr -> 6 Curve_Cubed -> 7 Curve_Cub -> 7 Curve_Curve _ -> 5 envCurveFloatNumber :: EnvCurve -> Float envCurveFloatNumber = \case Curve_Curve f -> f _ -> 0 env :: Float -> [(Float, Float)] -> EnvCurve -> EnvLiterally a env firstPoint pointsAndLengths curve = EnvLiterally { _envLiterally_initialVal = firstPoint , _envLiterally_releaseNode = Nothing , _envLiterally_offset = 0 , _envLiterally_loopNode = Nothing , _envLiterally_curveSegments = map foo pointsAndLengths } where foo :: (Float, Float) -> EnvSegment foo (point, dur) = EnvSegment { _envSegment_targetVal = Constant point , _envSegment_timeToGetThere = Constant dur -- this is, of course, limiting: , _envSegment_curve = curve }