{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} -- {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE NoIncoherentInstances #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE NoUndecidableInstances #-} module Vivid.UGens.Maths ( clip --- , fold -- rename cuz of haskell clashes! , inRange -- , inRect -- In Vivid.UGens.Filters: -- , integrator , leastChange , linExp --- , linLin --- , modDif , mostChange , mulAdd --- , runningMax --- , runningMin --- , runningSum --- , schmidt -- In Vivid.UGens.Analysis: -- , slope --- , wrap ) where import Vivid.SynthDef import Vivid.SynthDef.FromUA -- import Vivid.UGens.Algebraic import Vivid.UGens.Args import qualified Data.ByteString.Char8 as BS8 (pack) import Data.Proxy -- | -- **Note this has different behavior than 0.1!** -- \"lo\" is not implied by -- \"hi\". -- -- If you know you always want \"lo\" to be negative \"hi\" (like -1 to 1) -- you can use @'biOp' 'Clip2'@ clip :: (Args '["in"] '["lo", "hi"] a) => a -> SDBody a Signal clip = makeUGen "Clip" AR (Vs::Vs '["in","lo","hi"]) (lo_ (0::Float), hi_ (1::Float)) --- fold :: --- fold = -- | Returns 1.0 if \"in\" is between \"lo\" and \"hi\" (including -- equalling "lo" or "hi"). Else 0.0. -- -- Can be audio rate (AR), control rate (KR), or fixed (IR) -- -- Lo and hi default to 0 and 1 inRange :: (Args '["in"] '["lo", "hi"] a) => a -> SDBody a Signal inRange = makeUGen "InRange" AR (Vs::Vs '["in", "lo", "hi"]) (lo_ (0::Float), hi_ (1::Float)) --- -- inRect = -- | Returns the value of whichever of the 2 signals is changing -- least -- -- Its default calculation rate is the highest of its 2 inputs leastChange :: (ToSig s0 as, ToSig s1 as) => s0 -> s1 -> SDBody' as Signal leastChange = leastOrMostChange "LeastChange" leastOrMostChange :: (ToSig s0 as, ToSig s1 as) => String -> s0 -> s1 -> SDBody' as Signal leastOrMostChange sdName s0 s1 = do s0' <- toSig s0 s1' <- toSig s1 calcRate <- (maximum::Ord a=>[a]->a) <$> sequence (map getCalcRate [s0', s1']) addUGen $ UGen (UGName_S . BS8.pack $ sdName) calcRate [s0',s1'] 1 -- | "Converts a linear range of values to an exponential range of values." -- -- Args: -- -- * *in* - The input signal to convert. -- -- * *srclo* - Lower limit of input range. -- -- * *srchi* - Upper limit of input range. -- -- * *dstlo* - Lower limit of output range. -- -- * *dsthi* - Upper limit of output range. -- -- **"The dstlo and dsthi arguments must be nonzero and have the same sign."** -- -- This will have the same calculation rate as its \"in\" argument linExp :: Args '["in"] '["srclo", "srchi", "dstlo", "dsthi"] a => a -> SDBody a Signal linExp as = do in' <- as `uaArgVal` (Proxy::Proxy "in") getCalcRate in' >>= \case AR -> successGraph AR KR -> successGraph KR _ -> error "linExp: 'in' value must be at AR/KR" where successGraph calcRate = (flip ($)) as $ makeUGen "LinExp" calcRate (Vs::Vs '["in", "srclo", "srchi", "dstlo", "dsthi"]) (srclo_ (0::Float), srchi_ (1::Float), dstlo_ (1::Float), dsthi_ (2::Float)) -- linLin :: -- linLin = --- modDif :: --- modDif = -- | Opposite of 'leastChange' mostChange :: (ToSig s0 as, ToSig s1 as) => s0 -> s1 -> SDBody' as Signal mostChange = leastOrMostChange "MostChange" mulAdd :: (Args '["in"] '["mul", "add"] a) => a -> SDBody a Signal mulAdd = makeUGen "MulAdd" AR (Vs::Vs '["in", "mul", "add"]) (mul_ (1::Float), add_ (0::Float)) --- runningMax :: --- runningMax = --- runningMin :: --- runningMin = --- runningSum :: --- runningSum = --- schmidt :: --- schmidt = --- wrap :: --- wrap =