diff --git a/Vivid/SynthDef/Types.hs b/Vivid/SynthDef/Types.hs
--- a/Vivid/SynthDef/Types.hs
+++ b/Vivid/SynthDef/Types.hs
@@ -59,7 +59,7 @@
    ,_sdUGens :: Map Int UGen
    -- ignoring variants
    }
- deriving (Show)
+ deriving (Show, Eq)
 
 data SDName
    = SDName_Named ByteString
diff --git a/Vivid/UGens/Maths.hs b/Vivid/UGens/Maths.hs
--- a/Vivid/UGens/Maths.hs
+++ b/Vivid/UGens/Maths.hs
@@ -16,7 +16,7 @@
    -- , integrator
    , leastChange
    , linExp
----   , linLin
+   , linLin
 ---   , modDif
    , mostChange
    , mulAdd
@@ -34,6 +34,7 @@
 import Vivid.SynthDef.FromUA
 -- import Vivid.UGens.Algebraic
 import Vivid.UGens.Args
+import Vivid.UGens.Algebraic
 
 import qualified Data.ByteString.UTF8 as UTF8 (fromString)
 import Data.Proxy
@@ -112,8 +113,36 @@
       (Vs::Vs '["in", "srclo", "srchi", "dstlo", "dsthi"])
       (srclo_ (0::Float), srchi_ (1::Float), dstlo_ (1::Float), dsthi_ (2::Float))
 
--- linLin ::
--- linLin =
+
+-- | "Converts a linear range of values to an another linear 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.
+-- 
+--   This will have the same calculation rate as its \"in\" argument
+linLin :: Args '["in"] '["srclo", "srchi", "dstlo", "dsthi"] a => a -> SDBody a Signal
+linLin as = do
+   srclo <- uaArgValWDefault (-1::Float) as (Proxy::Proxy "srclo")
+   srchi <- uaArgValWDefault (1::Float) as (Proxy::Proxy "srchi")
+   dstlo <- uaArgValWDefault (0::Float) as (Proxy::Proxy "dstlo")
+   dsthi <- uaArgValWDefault (1::Float) as (Proxy::Proxy "dsthi")
+   in' <- as `uaArgVal` (Proxy::Proxy "in")
+   let 
+      scale  = (dsthi ~- dstlo) ~/ (srchi ~- srclo)
+      offset = dstlo ~- (scale ~* srclo)
+   getCalcRate in' >>= \case
+         AR -> mulAdd (in_ in',  mul_ scale, add_ offset) 
+         KR -> (in' ~* scale) ~+ offset
+         _ -> error "linExp: 'in' value must be at AR/KR"
 
 --- modDif ::
 --- modDif =
diff --git a/vivid.cabal b/vivid.cabal
--- a/vivid.cabal
+++ b/vivid.cabal
@@ -1,5 +1,5 @@
 name:                vivid
-version:             0.5.1.0
+version:             0.5.2.0
 synopsis:            Sound synthesis with SuperCollider
 description:         
   Music and sound synthesis with SuperCollider.
