diff --git a/Help/Graphs/analog-bubbles.lhs b/Help/Graphs/analog-bubbles.lhs
--- a/Help/Graphs/analog-bubbles.lhs
+++ b/Help/Graphs/analog-bubbles.lhs
@@ -4,9 +4,10 @@
 > import Sound.DF
 
 > let { dpl f a b = liftM2 (,) (f a) (f b)
->     ; mk_o f = liftM (\o -> o * 3.0 + 80.0) (lf_saw f 0.0)
->     ; mk_f a = liftM (\o -> o * 24.0 + a) (lf_saw 0.4 0.0)
->     ; mk_s f = liftM (\o -> o * 0.04) (sin_osc (midi_cps f) 0.0) }
+>     ; madd m a = fmap ((+ a) . (* m))
+>     ; mk_o f = madd 3.0 80.0 (lf_saw f 0.0)
+>     ; mk_f a = madd 24.0 a (lf_saw 0.4 0.0)
+>     ; mk_s f = fmap (* 0.04) (sin_osc (midi_cps f) 0.0) }
 > in do { (o1, o2) <- dpl mk_o 8.0 7.23
 >       ; (f1, f2) <- dpl mk_f o1 o2
 >       ; (s1, s2) <- dpl mk_s f1 f2
diff --git a/Help/Graphs/lfo-modulation.lhs b/Help/Graphs/lfo-modulation.lhs
--- a/Help/Graphs/lfo-modulation.lhs
+++ b/Help/Graphs/lfo-modulation.lhs
@@ -4,10 +4,11 @@
 > import Sound.DF
 
 > let { dpl f p q = liftM2 (,) (f p) (f q)
->     ; mk_p f = liftM (\o -> o * 3600.0 + 4000.0) (sin_osc f 0.0) }
-> in do { s <- liftM (\o -> o * 80.0 + 160.0) (sin_osc 0.05 0.0)
+>     ; madd m a = fmap ((+ a) . (* m))
+>     ; mk_p f = madd 3600.0 4000.0 (sin_osc f 0.0) }
+> in do { s <- madd 80.0 160.0 (sin_osc 0.05 0.0)
 >       ; (p1, p2) <- dpl mk_p 0.6 0.7
->       ; l <- liftM (\o -> o * 0.05) (lf_pulse s 0 0.4)
+>       ; l <- fmap (* 0.05) (lf_pulse s 0 0.4)
 >       ; (r1, r2) <- dpl (\x -> rlpf l x 0.2) p1 p2
 >       ; c1 <- buf_comb_n 0 r1 0.20 2.0
 >       ; c2 <- buf_comb_n 1 r2 0.25 2.0
diff --git a/Help/Graphs/moto-rev.lhs b/Help/Graphs/moto-rev.lhs
--- a/Help/Graphs/moto-rev.lhs
+++ b/Help/Graphs/moto-rev.lhs
@@ -4,8 +4,9 @@
 > import Sound.DF
 
 > let { dpl f a b = (,) (f a) (f b)
+>     ; madd m a = fmap ((+ a) . (* m))
 >     ; dplm f a b = liftM2 (,) (f a) (f b) }
-> in do { f <- liftM (\o -> o * 10.0 + 21.0) (sin_osc 0.2 0.0)
+> in do { f <- madd 10.0 21.0 (sin_osc 0.2 0.0)
 >       ; (s1, s2) <- dplm (\x -> lf_pulse f x 0.1) 0.0 0.1
 >       ; (o1, o2) <- dplm (\x -> rlpf x 100.0 0.1) s1 s2
 >       ; let (c1, c2) = dpl (\x -> clip2 x 0.4) o1 o2
diff --git a/Help/Graphs/sprinkler.lhs b/Help/Graphs/sprinkler.lhs
--- a/Help/Graphs/sprinkler.lhs
+++ b/Help/Graphs/sprinkler.lhs
@@ -2,11 +2,12 @@
 
 > import Sound.DF
 
-> do { n <- white_noise_m
->    ; f <- fmap (\x -> x * 10.0 + 7.0) (lf_pulse 0.09 0.0 0.16)
->    ; t <- fmap (\x -> x * 0.1) (lf_pulse f 0.0 0.25)
->    ; o <- bpz2 (n * t)
->    ; audition [] (out1 o) }
+> let madd m a = fmap ((+ a) . (* m))
+> in do { n <- white_noise_m
+>       ; f <- madd 10.0 7.0 (lf_pulse 0.09 0.0 0.16)
+>       ; t <- fmap (* 0.1) (lf_pulse f 0.0 0.25)
+>       ; o <- bpz2 (n * t)
+>       ; audition [] (out1 o) }
 
 do { n <- M.whiteNoise ar
    ; let { f = lfPulse kr 0.09 0 0.16 * 10 + 7
diff --git a/Help/UGen/Filter/buf_comb_n.help.lhs b/Help/UGen/Filter/buf_comb_n.help.lhs
--- a/Help/UGen/Filter/buf_comb_n.help.lhs
+++ b/Help/UGen/Filter/buf_comb_n.help.lhs
@@ -1,24 +1,8 @@
-buf_comb_n b i dl dc
-
-   b - buffer index
-   i - input signal
-  dl - delay time
-  dc - decay time
-
-Comb delay line. CombN uses no interpolation, CombL uses linear
-interpolation, CombC uses all pass interpolation.  All times are in
-seconds.  The decay time is the time for the echoes to decay by 60
-decibels. If this time is negative then the feedback coefficient
-will be negative, thus emphasizing only odd harmonics at an octave
-lower.
-
-Comb used as a resonator. The resonant fundamental is equal to
-reciprocal of the delay time.
-
 > import Sound.DF
 
 > do { n <- white_noise_m
->    ; dt <- fmap (\x -> lin_exp (x + 2.0) 1.0 2.0 0.0001 0.01) (lf_saw 0.1 0.0)
+>    ; dt <- let f x = lin_exp (x + 2.0) 1.0 2.0 0.0001 0.01
+>            in fmap f (lf_saw 0.1 0.0)
 >    ; c <- buf_comb_n 0 (n * 0.1) dt 0.2
 >    ; audition [b_alloc 0 44100] (out1 c) }
 
diff --git a/Help/UGen/Filter/decay.help.lhs b/Help/UGen/Filter/decay.help.lhs
--- a/Help/UGen/Filter/decay.help.lhs
+++ b/Help/UGen/Filter/decay.help.lhs
@@ -1,15 +1,4 @@
-decay i t
-
-   i - input signal
-   t - decay time
-
-Exponential decay.  This is essentially the same as Integrator
-except that instead of supplying the coefficient directly, it is
-caculated from a 60 dB decay time. This is the time required for
-the integrator to lose 99.9 % of its value or -60dB. This is useful
-for exponential decaying envelopes triggered by impulses.
-
-Used as an envelope.
+> import Sound.DF
 
 > do { n <- brown_noise_m
 >    ; f <- lf_saw 0.1 0.0
diff --git a/Help/UGen/Filter/iir2.help.lhs b/Help/UGen/Filter/iir2.help.lhs
--- a/Help/UGen/Filter/iir2.help.lhs
+++ b/Help/UGen/Filter/iir2.help.lhs
@@ -1,8 +1,3 @@
-iir2 f i
-
-  f - function (\x0 y1 y2 -> y0)
-  i - input signal
-
 > import Sound.DF
 
 > do { c1 <- iir2 (\x y1 _ -> x + y1) 0.001
diff --git a/Help/UGen/Filter/lag.help.lhs b/Help/UGen/Filter/lag.help.lhs
--- a/Help/UGen/Filter/lag.help.lhs
+++ b/Help/UGen/Filter/lag.help.lhs
@@ -1,10 +1,3 @@
-lag i t
-
-  i - input signal
-  t - lag time
-
-A simple averaging filter.
-
 > import Sound.DF
 
 > do { s <- sin_osc 0.05 0.0
diff --git a/Help/UGen/Filter/latch.help.lhs b/Help/UGen/Filter/latch.help.lhs
--- a/Help/UGen/Filter/latch.help.lhs
+++ b/Help/UGen/Filter/latch.help.lhs
@@ -1,10 +1,3 @@
-latch i t
-
-Sample and hold. Holds input signal value when triggered.
-
-   i - input signal.
-   t - trigger (non-positive to positive)
-
 > import Sound.DF
 
 > do { n <- white_noise_m
diff --git a/Help/UGen/Filter/resonz.help.lhs b/Help/UGen/Filter/resonz.help.lhs
--- a/Help/UGen/Filter/resonz.help.lhs
+++ b/Help/UGen/Filter/resonz.help.lhs
@@ -1,23 +1,8 @@
-resonz i f rq
-
-A two pole resonant filter with zeroes at z = +/- 1. Based on
-K. Steiglitz, "A Note on Constant-Gain Digital Resonators,"
-Computer Music Journal, vol 18, no. 4, pp. 8-10, Winter 1994.  The
-reciprocal of Q is used rather than Q because it saves a divide
-operation inside the unit generator.
-
-     i - input signal
-     f - resonant frequency (in hertz)
-    rq - bandwidth ratio (reciprocal of Q). 
-         rq = bandwidth / centerFreq
-
 > import Sound.DF
 
 > do { n <- white_noise_m
 >    ; r <- resonz (n * 0.5) 440.0 0.1
 >    ; audition [] (out1 r) }
-
-Modulate frequency
 
 > do { n <- white_noise_m
 >    ; f <- fmap (\x -> x * 3500.0 + 4500.0) (lf_saw 0.1 0.0)
diff --git a/Help/UGen/Filter/rlpf.help.lhs b/Help/UGen/Filter/rlpf.help.lhs
--- a/Help/UGen/Filter/rlpf.help.lhs
+++ b/Help/UGen/Filter/rlpf.help.lhs
@@ -1,11 +1,3 @@
-rlpf in freq rq
-
-   i - input signal
-   f - frequency (hertz)
-  rq - reciprocal of Q
-
-A resonant low pass filter.
-
 > import Sound.DF
 
 > do { n <- white_noise_m
diff --git a/Help/UGen/Noise/brown_noise.help.lhs b/Help/UGen/Noise/brown_noise.help.lhs
--- a/Help/UGen/Noise/brown_noise.help.lhs
+++ b/Help/UGen/Noise/brown_noise.help.lhs
@@ -1,8 +1,3 @@
-brown_noise
-
-Generates noise whose spectrum falls off in power by 6 dB per
-octave.
-
 > import Sound.DF
 
 > do { n <- brown_noise_m
diff --git a/Help/UGen/Noise/white_noise.help.lhs b/Help/UGen/Noise/white_noise.help.lhs
--- a/Help/UGen/Noise/white_noise.help.lhs
+++ b/Help/UGen/Noise/white_noise.help.lhs
@@ -1,7 +1,3 @@
-white_noise
-
-Generates noise whose spectrum has equal power at all frequencies.
-
 > import Sound.DF
 
 > do { n <- white_noise_m
diff --git a/Help/UGen/Oscillator/impulse.help.lhs b/Help/UGen/Oscillator/impulse.help.lhs
--- a/Help/UGen/Oscillator/impulse.help.lhs
+++ b/Help/UGen/Oscillator/impulse.help.lhs
@@ -1,10 +1,3 @@
-impulse f ip
-
-Impulse oscillator.  Outputs non band limited single sample impulses.
-
-   f - frequency (in hertz)
-  ip - phase offset (0..1)
-
 > import Sound.DF
 
 > do { o <- impulse 800.0 0.0
diff --git a/Help/UGen/Oscillator/lf_pulse.help.lhs b/Help/UGen/Oscillator/lf_pulse.help.lhs
--- a/Help/UGen/Oscillator/lf_pulse.help.lhs
+++ b/Help/UGen/Oscillator/lf_pulse.help.lhs
@@ -1,12 +1,3 @@
-lf_pulse f ip w
-
-A non-band-limited pulse oscillator. Outputs a high value of one
-and a low value of zero.
-
-   f - frequency (in hertz)
-  ip - initial phase (0, 1)
-   w - pulse width duty cycle (0, 1)
-
 > import Sound.DF
 
 > do { o1 <- fmap (\x -> x * 200.0 + 200.0) (lf_pulse 3.0 0.0 0.3)
diff --git a/Help/UGen/Oscillator/lf_saw.help.lhs b/Help/UGen/Oscillator/lf_saw.help.lhs
--- a/Help/UGen/Oscillator/lf_saw.help.lhs
+++ b/Help/UGen/Oscillator/lf_saw.help.lhs
@@ -1,17 +1,7 @@
-lf_saw f ip
-
-Sawtooth oscillator.  A non-band-limited sawtooth
-oscillator. Output ranges from -1 to +1.
-
-    f - frequency (in hertz)
-   ip - initial phase (0,2)
-
 > import Sound.DF
 
 > do { o <- lf_saw 500.0 1.0
 >    ; audition [] (out1 (o * 0.1)) }
-
-Used as both Oscillator and LFO.
 
 > do { f <- lf_saw 4.0 0.0
 >    ; o <- lf_saw (f * 400.0 + 400.0) 0.0
diff --git a/Help/UGen/Oscillator/sin_osc.help.lhs b/Help/UGen/Oscillator/sin_osc.help.lhs
--- a/Help/UGen/Oscillator/sin_osc.help.lhs
+++ b/Help/UGen/Oscillator/sin_osc.help.lhs
@@ -1,20 +1,11 @@
-sin_osc f ip
-
-   f - frequency 
-  ip - initial phase
-
 > import Sound.DF
 
 > do { o <- sin_osc 440.0 0.0
 >    ; audition [] (out1 (o * 0.1)) }
 
-Used as both Oscillator and LFO.
-
 > do { f <- sin_osc 4.0 0.0
 >    ; o <- sin_osc (f * 400.0 + 400.0) 0.0
 >    ; audition [] (out1 (o * 0.1)) }
-
-Cancellation.
 
 > do { o1 <- sin_osc 440.0 0.0
 >    ; o2 <- sin_osc 440.0 pi
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,8 +1,8 @@
 hdf - haskell data flow library for audio processing
 
-requires jack.dl from jack.*.
+requires jack-dl from rju.
 
-  http://slavepianos.org/rd/f/207983/
+  http://slavepianos.org/rd/?t=rju
 
-(c) rohan drape, 2006-2009
+(c) rohan drape, 2006-2011
     gpl, http://gnu.org/copyleft/
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMain
diff --git a/Setup.lhs b/Setup.lhs
deleted file mode 100644
--- a/Setup.lhs
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env runhaskell
-> import Distribution.Simple
-> main = defaultMain
diff --git a/Sound/DF.hs b/Sound/DF.hs
--- a/Sound/DF.hs
+++ b/Sound/DF.hs
@@ -1,9 +1,12 @@
-module Sound.DF ( module Sound.DF.Audition
-                , module Sound.DF.CGen
-                , module Sound.DF.Draw
-                , module Sound.DF.Graph
-                , module Sound.DF.Node
-                , module Sound.DF.UGen ) where
+-- | Top level module for @hdf@.
+--
+-- > view (lf_pulse 0.09 0.0 0.16)
+module Sound.DF (module Sound.DF.Audition
+                ,module Sound.DF.CGen
+                ,module Sound.DF.Draw
+                ,module Sound.DF.Graph
+                ,module Sound.DF.Node
+                ,module Sound.DF.UGen) where
 
 import Sound.DF.Audition
 import Sound.DF.CGen
diff --git a/Sound/DF/Audition.hs b/Sound/DF/Audition.hs
--- a/Sound/DF/Audition.hs
+++ b/Sound/DF/Audition.hs
@@ -1,3 +1,4 @@
+-- | Interaction with @jack-dl@ server
 module Sound.DF.Audition where
 
 import Sound.DF.CGen
@@ -6,8 +7,6 @@
 import System.Directory
 import System.FilePath
 
--- * Interaction with jack.dl server
-
 -- | Allocate buffer.
 b_alloc :: Int -> Int -> OSC
 b_alloc b n = Message "/b_alloc" [Int b, Int n]
@@ -16,20 +15,20 @@
 g_load :: Int -> String -> OSC
 g_load i s = Message "/g_load" [Int i, String s]
 
--- | Load graph.
+-- | Unload graph.
 g_unload :: Int -> OSC
 g_unload i = Message "/g_unload" [Int i]
 
--- | Run action with UDP link to jack.dl.
+-- | Run action with @UDP@ link to @jack-dl@.
 with_jack_dl :: (UDP -> IO a) -> IO a
 with_jack_dl = withTransport (openUDP "127.0.0.1" 57190)
 
--- | Audition graph 'n' after sending initialisation messages 'is'.
+-- | Audition graph after sending initialisation messages.
 audition :: [OSC] -> Node -> IO ()
-audition is n = 
+audition is n =
     do t <- getTemporaryDirectory
        k <- generateID
        let fn = t </> ("audition" ++ show k)
        dl_gen fn n
-       with_jack_dl (\fd -> mapM (send fd) is)
+       _ <- with_jack_dl (\fd -> mapM (send fd) is)
        with_jack_dl (\fd -> send fd (g_load 0 (fn <.> "so")))
diff --git a/Sound/DF/CGen.hs b/Sound/DF/CGen.hs
--- a/Sound/DF/CGen.hs
+++ b/Sound/DF/CGen.hs
@@ -1,5 +1,5 @@
-module Sound.DF.CGen ( -- * C code generator
-                       code_gen, dl_gen ) where
+-- | C code generator
+module Sound.DF.CGen (code_gen,dl_gen) where
 
 import Data.List
 import Sound.DF.Node
@@ -9,7 +9,7 @@
 
 -- | Generate C code for graph.
 code_gen :: Node -> String
-code_gen n = 
+code_gen n =
     let as = analyse (tsort n)
         ns = map fst as
         hd = [ "#include <stdio.h>"
@@ -20,16 +20,16 @@
         c = [hd, cdef, cstate ns, dsp_init ns, dsp_step as ns]
     in (unlines . concat) c
 
--- | Generate C code, write file disk and call GNU C compiler to build
---   shared library.
+-- | Generate C code, write file to disk and call the GNU C compiler
+--   to build shared library.
 dl_gen :: FilePath -> Node -> IO ()
-dl_gen fn n = 
+dl_gen fn n =
     do let c = fn <.> "c"
            so = fn <.> "so"
            gcc = "gcc -g --std=c99 -O2 -shared -I ~/include "
            cmd = gcc ++ c ++ " -o " ++ so
        writeFile c (code_gen n)
-       system cmd
+       _ <- system cmd
        return ()
 
 -- | Construct an identifier.
@@ -53,26 +53,26 @@
 type CVar = (String, String, Maybe Double, Bool)
 
 cvar_from_constant :: NodeID -> String -> Constant -> Bool -> CVar
-cvar_from_constant k c (Real_Constant i) st = 
+cvar_from_constant k c (Real_Constant i) st =
     (ctype Real_Type, clabel c (k, 0), Just i, st)
-cvar_from_constant k c (Integer_Constant i) st = 
+cvar_from_constant k c (Integer_Constant i) st =
     (ctype Integer_Type, clabel c (k, 0), Just (fromIntegral i), st)
 
 -- | List of required variable declarations.
 cvars_n :: (NodeID, Node) -> [CVar]
-cvars_n (k, S i) = 
+cvars_n (k, S i) =
     [cvar_from_constant k "n" i False]
 cvars_n (k, R (R_ID j) (Left i)) =
     [cvar_from_constant j "r" i True
     ,cvar_from_constant k "n" i False]
 cvars_n (k, R (R_ID _) (Right _)) =
     [("float", clabel "n" (k, 0), Nothing, False)]
-cvars_n (k, (A _ _ o)) = 
-    let f (p, t) = let t' = port_data_type t
-                   in (ctype t', clabel "n" (k, p), Nothing, False)
-    in map f (zip [0 .. length o - 1] o)
-cvars_n (_, (M _ _)) = undefined
-cvars_n (_, (P _ _)) = undefined
+cvars_n (k, A _ _ o) =
+    let f p t = let t' = port_data_type t
+                in (ctype t', clabel "n" (k, p), Nothing, False)
+    in zipWith f [0 .. length o - 1] o
+cvars_n (_, M _ _) = undefined
+cvars_n (_, P _ _) = undefined
 
 cvars :: [(NodeID, Node)] -> [CVar]
 cvars = concatMap cvars_n
@@ -87,26 +87,26 @@
 non_stateful_cvars = filter (not . is_stateful) . cvars
 
 cstate :: [(NodeID, Node)] -> [String]
-cstate ns = 
+cstate ns =
     let f (t, n, _, _) = t ++ " " ++ n ++ ";"
     in "struct df_state {" : map f (stateful_cvars ns) ++ ["};"]
 
 cstate_init :: String -> [(NodeID, Node)] -> [String]
-cstate_init s ns =  
+cstate_init s ns =
     let f (_, n, Just i, _) = s ++ "->" ++ n ++ " = " ++ show i ++ ";"
         f (_, _, Nothing, _) = error "cstate_init"
     in map f (stateful_cvars ns)
 
--- | Non-statefule variable declarations.  Unintialised, the node 
+-- | Non-statefule variable declarations.  Unintialised, the node
 --   writes the constant value.
 non_state_decl :: [(NodeID, Node)] -> [String]
-non_state_decl ns =  
+non_state_decl ns =
     let f (ty, n, _, _) = ty ++ " " ++ n ++ ";"
     in map f (non_stateful_cvars ns)
 
 -- | Generate dsp_init function.
 dsp_init :: [(NodeID, Node)] -> [String]
-dsp_init ns = 
+dsp_init ns =
     let a = [ "void *dsp_init(struct world *w, int g)"
             , "{"
             , "struct df_state *s = malloc(sizeof(struct df_state));" ]
@@ -116,7 +116,7 @@
 
 -- | Generate dsp_step function.
 dsp_step :: [((NodeID, Node), [Edge])] -> [(NodeID, Node)] -> [String]
-dsp_step as ns = 
+dsp_step as ns =
     let s = "void dsp_step(struct world *w, int g, void *ptr, int nf)"
         f (t, n, _, _) = t ++ " " ++ n ++ " = s->" ++ n ++ ";"
         g (_, n, _, _) = "s->" ++ n ++ " = " ++ n ++ ";"
@@ -126,8 +126,8 @@
                , "/* load state */" ]
              , map f (stateful_cvars ns)
              , [ "/* non-stateful variables */" ]
-             , non_state_decl ns                   
-             , [ "/* algorithm */" 
+             , non_state_decl ns
+             , [ "/* algorithm */"
                , "for(int i = 0; i < nf; i++) {" ]
              , concatMap cgen as
              , [ "}"
@@ -138,25 +138,25 @@
 
 -- | List of code statements.
 cgen :: ((NodeID, Node), [Edge]) -> [String]
-cgen ((k, n@(S (Real_Constant x))), []) = 
+cgen ((k, n@(S (Real_Constant x))), []) =
     d_ccall "df_real_constant" n [clabel "n" (k, 0), show x]
-cgen ((k, n@(S (Integer_Constant x))), []) = 
+cgen ((k, n@(S (Integer_Constant x))), []) =
     d_ccall "df_integer_constant" n [clabel "n" (k, 0), show x]
-cgen ((k, n@(R (R_ID j) (Left _))), []) = 
+cgen ((k, n@(R (R_ID j) (Left _))), []) =
     d_ccall "df_rec_r" n [clabel "n" (k, 0), clabel "r" (j, 0)]
-cgen ((_, n@(R (R_ID j) (Right _))), [(s, _)]) = 
+cgen ((_, n@(R (R_ID j) (Right _))), [(s, _)]) =
     d_ccall "df_rec_w" n [clabel "r" (j, 0), clabel "n" s]
-cgen ((k, n@(A a _ o)), es) = 
+cgen ((k, n@(A a _ o)), es) =
     let o_l = map (clabel "n") (zip (repeat k) [0 .. length o - 1])
         i_l = map (clabel "n". fst) es
     in d_ccall a n (o_l ++ i_l)
-cgen ((_, (P _ _)), _) =
+cgen ((_, P _ _), _) =
     []
 cgen c = error ("cgen: " ++ show c)
 
 -- | Macro definitions
 cdef :: [String]
-cdef = 
+cdef =
     ["/* reader */"
     ,"#define df_integer_constant(o_0,i_0) { o_0 = i_0; }"
     ,"#define df_real_constant(o_0,i_0) { o_0 = i_0; }"
@@ -191,14 +191,14 @@
     ,"/* instance Eq */"
     ,"#define df_eq(o_0,i_0,i_1) { o_0 = i_0 == i_1 ? true : false; }"
     ,"/* instance RealFrac */"
-    ,"#define df_floor(o_0,i_0) { o_0 = floorf(i_0); }"     
-    ,"#define df_lrint(o_0,i_0) { o_0 = lrintf(i_0); }"     
+    ,"#define df_floor(o_0,i_0) { o_0 = floorf(i_0); }"
+    ,"#define df_lrint(o_0,i_0) { o_0 = lrintf(i_0); }"
     ,"/* Control */"
     ,"#define df_and(o_0,i_0,i_1) { o_0 = i_0 && i_1 ? true : false; }"
     ,"#define df_or(o_0,i_0,i_1) { o_0 = i_0 || i_1 ? true : false; }"
     ,"#define df_select2(o_0,i_0,i_1,i_2) { o_0 = i_0 ? i_1 : i_2; }"
     ,"/* World|Environment */"
-    ,"#define df_sample_rate(o_0) { o_0 = w_sr(w); }"    
+    ,"#define df_sample_rate(o_0) { o_0 = w_sr(w); }"
     ,"#define df_b_read(o_0,i_0,i_1) { o_0=w_b_read1(w,i_0,i_1); }"
     ,"#define df_b_write(i_0,i_1,i_2) { w_b_write1(w,i_0,i_1,i_2); }"
     ,"#define df_random(o_0,i_0) { o_0 = ((float)rand() / (float)RAND_MAX); }"
diff --git a/Sound/DF/Draw.hs b/Sound/DF/Draw.hs
--- a/Sound/DF/Draw.hs
+++ b/Sound/DF/Draw.hs
@@ -1,12 +1,10 @@
-module Sound.DF.Draw ( -- * Graph drawing
-                       view ) where
+-- | Graph drawing
+module Sound.DF.Draw (view) where
 
 import Sound.DF.Node
 import Sound.DF.Graph
 
-import Control.Monad
 import qualified Data.Graph.Inductive as G
-import qualified Data.Graph.Inductive.Graphviz as G
 import Data.Maybe
 import Data.List
 import System.Cmd
@@ -15,8 +13,8 @@
 
 -- | Implicit edge from wR to rW.
 r_edge :: [(NodeID, Node)] -> (NodeID, Node) -> Maybe Edge
-r_edge ns (i, R (R_ID d) (Left _)) = 
-    let f x (_, (R (R_ID y) (Right _))) = x == y
+r_edge ns (i, R (R_ID d) (Left _)) =
+    let f x (_, R (R_ID y) (Right _)) = x == y
         f _ _ = False
         (j, _) = fromMaybe (error "r_edge") (find (f d) ns)
     in Just ((j,0),(i,0))
@@ -26,7 +24,7 @@
 vgraph :: G.Gr Node (PortID, PortID) -> G.Gr Node (PortID, PortID)
 vgraph g = let ns = G.labNodes g
                es = G.labEdges g
-               es' = map mod_e (catMaybes (map (r_edge ns) ns))
+               es' = map mod_e (mapMaybe (r_edge ns) ns)
            in G.mkGraph ns (es ++ es')
 
 draw :: Node -> String
@@ -38,5 +36,5 @@
             let s = draw n
                 fn = t </> "df_view" <.> "dot"
             writeFile fn s
-            rawSystem "dotty" [fn]
+            _ <- rawSystem "dotty" [fn]
             return ()
diff --git a/Sound/DF/Graph.hs b/Sound/DF/Graph.hs
--- a/Sound/DF/Graph.hs
+++ b/Sound/DF/Graph.hs
@@ -1,41 +1,44 @@
+-- | Graph analysis
 module Sound.DF.Graph where
 
 import qualified Data.Graph.Inductive as G
-import qualified Data.Graph.Inductive.Query.DFS as G
 import Data.List
 import Data.Maybe
 import Sound.DF.Node
 
--- * Graph analysis
-
 -- | List of nodes, in left biased order.
 nodes :: Node -> [Node]
-nodes n@(S _) = [n]
-nodes n@(A _ i _) = n : concatMap nodes i
-nodes n@(R _ (Left _)) = [n]
-nodes n@(R _ (Right (l, r))) = n : (nodes l ++ nodes r)
-nodes n@(P i _) = n : nodes i
-nodes n@(M l r) = n : (nodes l ++ nodes r)
+nodes n =
+    case n of
+      S _ -> [n]
+      A _ i _ -> n : concatMap nodes i
+      R _ (Left _) -> [n]
+      R _ (Right (l, r)) -> n : (nodes l ++ nodes r)
+      P i _ -> n : nodes i
+      M l r -> n : (nodes l ++ nodes r)
 
 -- | Read label of node.
 label :: [(NodeID, Node)] -> Node -> NodeID
-label ns n = let r = find ((== n) . snd) ns
-                  in maybe (error ("label: " ++ show n)) fst r
+label ns n =
+    let r = find ((== n) . snd) ns
+    in maybe (error ("label: " ++ show n)) fst r
 
 -- | Transform node to source, see through rec_r and proxy and mrg.
 source :: [(NodeID, Node)] -> Node -> (NodeID, PortID)
-source ns n@(S _) = (label ns n, 0)
-source ns n@(A _ _ [_]) = (label ns n, 0)
-source _ (A _ _ _) = error "non unary A"
-source ns n@(R _ (Left _)) = (label ns n, 0)
-source ns (R _ (Right (n, _))) = source ns n
-source ns (P n i) = (label ns n, i)
-source ns (M l _) = source ns l
+source ns n =
+    case n of
+      S _ -> (label ns n, 0)
+      A _ _ [_] -> (label ns n, 0)
+      A _ _ _ -> error "non unary A"
+      R _ (Left _) -> (label ns n, 0)
+      R _ (Right (n', _)) -> source ns n'
+      P n' i -> (label ns n', i)
+      M l _ -> source ns l
 
 -- | Edge between ports.
 type Edge = ((NodeID, PortID), (NodeID, PortID))
 
--- | List incoming node edges, 
+-- | List incoming node edges,
 edges :: [(NodeID, Node)] -> Node -> [Edge]
 edges ns r@(A _ is _) = let f i k = (source ns i, (label ns r, k))
                         in zipWith f is [0..]
@@ -48,9 +51,9 @@
 analyse :: [Node] -> [((NodeID, Node), [Edge])]
 analyse ns = let l_ns = zip [1..] ns
                  w_es (k, n) = ((k, n), edges l_ns n)
-                 rem_p ((_, (P _ _)), _) = False
+                 rem_p ((_, P _ _), _) = False
                  rem_p _ = True
-                 rem_m ((_, (M _ _)), _) = False
+                 rem_m ((_, M _ _), _) = False
                  rem_m _ = True
             in filter rem_m (filter rem_p (map w_es l_ns))
 
@@ -60,12 +63,14 @@
 
 -- | Generate graph.
 graph :: Node -> G.Gr Node (PortID, PortID)
-graph n = let a = analyse (nub (nodes n))
-              ns = map fst a
-              es = concatMap (map mod_e . snd) a
-          in G.mkGraph ns es
+graph n =
+    let a = analyse (nub (nodes n))
+        ns = map fst a
+        es = concatMap (map mod_e . snd) a
+    in G.mkGraph ns es
 
 -- | Topological sort of nodes (via graph).
 tsort :: Node -> [Node]
-tsort s = let g = graph s
-          in map (fromMaybe (error "tsort") . G.lab g) (G.topsort g) 
+tsort s =
+    let g = graph s
+    in map (fromMaybe (error "tsort") . G.lab g) (G.topsort g)
diff --git a/Sound/DF/Node.hs b/Sound/DF/Node.hs
--- a/Sound/DF/Node.hs
+++ b/Sound/DF/Node.hs
@@ -1,3 +1,4 @@
+-- | Data flow nodes.
 module Sound.DF.Node where
 
 import Control.Monad
@@ -10,7 +11,7 @@
             deriving (Eq)
 
 -- | Enumeration of types of data on ports.
-data Type = Real_Type 
+data Type = Real_Type
           | Integer_Type
           | Boolean_Type
             deriving (Eq, Show)
@@ -71,13 +72,15 @@
 
 -- | Type of a node.
 node_type :: Node -> Type
-node_type (S c) = constant_type c
-node_type (A _ _ [Port t _]) = t
-node_type (A _ _ _) = error "node_type: A: non unary output"
-node_type (R _ (Left c)) = constant_type c
-node_type (R _ (Right (n, _))) = node_type n
-node_type (P n i) = port_data_type (outputs n !! i)
-node_type (M l _) = node_type l
+node_type n =
+    case n of
+      S c -> constant_type c
+      A _ _ [Port t _] -> t
+      A _ _ _ -> error "node_type: A: non unary output"
+      R _ (Left c) -> constant_type c
+      R _ (Right (n',_)) -> node_type n'
+      P n' i -> port_data_type (outputs n' !! i)
+      M l _ -> node_type l
 
 -- * Numeric primitives for class instances
 
@@ -115,7 +118,7 @@
     if node_type p == Real_Type && node_type q == Real_Type
     then A s [p, q] [Port Real_Type 1]
     else error (show ("real binary operator", s, p, q))
-    
+
 -- | Addition.
 n_add :: Node -> Node -> Node
 n_add = numerical_binary_operator "df_add"
@@ -134,9 +137,11 @@
 
 -- | Absolute value.
 n_abs :: Node -> Node
-n_abs p | node_type p == Real_Type = A "df_fabs" [p] [Port Real_Type 1]
-        | node_type p == Integer_Type = A "df_iabs" [p] [Port Integer_Type 1]
-        | otherwise = error "n_abs" {- quieten compiler -}
+n_abs p =
+    case node_type p of
+      Real_Type -> A "df_fabs" [p] [Port Real_Type 1]
+      Integer_Type -> A "df_iabs" [p] [Port Integer_Type 1]
+      _ -> error "n_abs" {- quieten compiler -}
 
 -- | Sign of.
 n_signum :: Node -> Node
@@ -254,13 +259,13 @@
   max = n_max
   min = n_min
 
--- | Real valued floor. 
+-- | Real valued floor.
 n_floor :: Node -> Node
 n_floor = real_unary_operator "df_floor"
 
 -- | Integer valued floor.
 n_lrint :: Node -> Node
-n_lrint p 
+n_lrint p
     | node_type p == Real_Type = A "df_lrint" [p] [Port Integer_Type 1]
     | otherwise = error "n_lrint"
 
@@ -273,8 +278,7 @@
   floor :: (Integral b) => a -> b
 -}
 
--- * Class of monads generating identifers
-
+-- | Class of monads generating identifers
 class (Monad m) => ID m where
    generateID :: m Int
 
@@ -294,7 +298,7 @@
 
 -- | Variant or rec with monadic action in backward arc.
 recm :: ID m => Constant -> (Node -> m (Node, Node)) -> m Node
-recm i f = 
+recm i f =
     do n <- generateID
        let r_r = R (R_ID n) (Left i)
        r <- f r_r
diff --git a/Sound/DF/UGen.hs b/Sound/DF/UGen.hs
--- a/Sound/DF/UGen.hs
+++ b/Sound/DF/UGen.hs
@@ -1,3 +1,4 @@
+-- | Data flow node functions, or unit generators.
 module Sound.DF.UGen where
 
 import Control.Monad
@@ -9,7 +10,7 @@
 uniform_operator :: Type -> Int -> String -> [Node] -> Node
 uniform_operator t n s ps =
     if all (\p -> node_type p == t) ps
-    then A s ps (replicate n (Port t 1)) 
+    then A s ps (replicate n (Port t 1))
     else error (show ("output operator", ps))
 
 -- | Single channel output.
@@ -34,8 +35,8 @@
 
 -- | If 'p' then 'q' else 'r'.
 select2 :: Node -> Node -> Node -> Node
-select2 p q r = 
-    if node_type p == Boolean_Type && 
+select2 p q r =
+    if node_type p == Boolean_Type &&
        node_type q == node_type r
     then A "df_select2" [p, q, r] [Port (node_type q) 1]
     else error (show ("select2", p, q, r))
@@ -46,7 +47,7 @@
     if node_type p == Boolean_Type && node_type q == Boolean_Type
     then A s [p, q] [Port Boolean_Type 1]
     else error (show ("logical operator", s, p, q))
-    
+
 -- | Logical and.
 n_and :: Node -> Node -> Node
 n_and = logical_operator "df_and"
@@ -65,12 +66,12 @@
 -- | Buffer write.
 b_write :: Node -> Node -> Node -> Node
 b_write p q r =
-    if node_type p == Integer_Type && 
-       node_type q == Integer_Type && 
+    if node_type p == Integer_Type &&
+       node_type q == Integer_Type &&
        node_type r == Real_Type
     then A "df_b_write" [p, q, r] []
     else error (show ("b_write", p, q, r))
- 
+
 -- | White noise (0, 1).
 white_noise_u :: Node -> Node
 white_noise_u p = A "df_random" [p] [Port Real_Type 1]
@@ -97,23 +98,32 @@
 iir1 :: ID m => Constant -> (Node -> Node -> Node) -> Node -> m Node
 iir1 y0 f i = rec y0 (split . f i)
 
--- | Two place infinte impulse response filter.
+-- | Two place infinte impulse response filter.  Inputs are: /f/=
+-- function @(\x0 y1 y2 -> y0)@, /i/ = input signal.
+--
+-- > do { c1 <- iir2 (\x y1 _ -> x + y1) 0.001
+-- >    ; o1 <- sin_osc (c1 + 220.0) 0
+-- >    ; c2 <- iir2 (\x _ y2 -> x + y2) 0.001
+-- >    ; o2 <- sin_osc (c2 + 220.0) 0
+-- >    ; audition [] (out2 (o1 * 0.1, o2 * 0.1)) }
 iir2 :: ID m => (Node -> Node -> Node -> Node) -> Node -> m Node
-iir2 f i = recm 
+iir2 f i = recm
              (Real_Constant 0)
              (liftM split . (\y1 -> do y2 <- unit_delay (Real_Constant 0) y1
                                        return (f i y1 y2)))
 
 -- | Single place finte impulse response filter.
 fir1 :: ID m => (Node -> Node -> Node) -> Node -> m Node
-fir1 f i = do x1 <- unit_delay (Real_Constant 0) i
-              return (f i x1)
+fir1 f i = do
+  x1 <- unit_delay (Real_Constant 0) i
+  return (f i x1)
 
 -- | Two place finte impulse response filter.
 fir2 :: ID m => (Node -> Node -> Node -> Node) -> Node -> m Node
-fir2 f i = do x1 <- unit_delay (Real_Constant 0) i
-              x2 <- unit_delay (Real_Constant 0) x1
-              return (f i x1 x2)
+fir2 f i = do
+  x1 <- unit_delay (Real_Constant 0) i
+  x2 <- unit_delay (Real_Constant 0) x1
+  return (f i x1 x2)
 
 -- | Ordinary biquad filter section.
 biquad :: ID m => (Node -> Node -> Node -> Node -> Node -> Node) -> Node -> m Node
@@ -148,20 +158,53 @@
 phasor :: ID m => Constant -> Node -> Node -> m Node
 phasor ip r = iir1 ip (\x y1 -> clipr r (x + y1))
 
--- | Sine oscillator, f = frequency in hz.
+-- | Sine oscillator.  Inputs are: /f/ = frequency (in hz), /ip/ =
+-- initial phase.
+--
+-- > do { o <- sin_osc 440.0 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
+--
+-- Used as both Oscillator and LFO.
+--
+-- > do { f <- sin_osc 4.0 0.0
+-- >    ; o <- sin_osc (f * 400.0 + 400.0) 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
+--
+-- Cancellation.
+--
+-- > do { o1 <- sin_osc 440.0 0.0
+-- >    ; o2 <- sin_osc 440.0 pi
+-- >    ; audition [] (out1 (o1 + o2)) }
 sin_osc :: ID m => Node -> Double -> m Node
-sin_osc f ip = 
-    do p <- phasor (Real_Constant ip) two_pi (hz_to_incr two_pi f sample_rate)
-       return (sin p)
+sin_osc f ip = do
+  p <- phasor (Real_Constant ip) two_pi (hz_to_incr two_pi f sample_rate)
+  return (sin p)
 
--- | Non-band limited sawtooth oscillator.
+-- | Non-band limited sawtooth oscillator.  Output ranges from -1 to +1.
+-- Inputs are: /f/ = frequency (in hertz), /ip/ = initial phase (0,2).
+--
+-- > do { o <- lf_saw 500.0 1.0
+-- >    ; audition [] (out1 (o * 0.1)) }
+--
+-- Used as both Oscillator and LFO.
+--
+-- > do { f <- lf_saw 4.0 0.0
+-- >    ; o <- lf_saw (f * 400.0 + 400.0) 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
 lf_saw :: ID m => Node -> Double -> m Node
-lf_saw f ip = do p <- phasor (Real_Constant ip) 2.0 (hz_to_incr 2.0 f sample_rate)
-                 return (p - 1.0)
+lf_saw f ip = do
+  p <- phasor (Real_Constant ip) 2.0 (hz_to_incr 2.0 f sample_rate)
+  return (p - 1.0)
 
--- | Non-band limited pulse oscillator, w = width (0,1).
+-- | Non-band-limited pulse oscillator. Outputs a high value of one
+-- and a low value of zero. Inputs are: /f/ = frequency (in hertz),
+-- /ip/ = initial phase (0, 1), /w/ = pulse width duty cycle (0, 1).
+--
+-- > do { o1 <- fmap (\x -> x * 200.0 + 200.0) (lf_pulse 3.0 0.0 0.3)
+-- >    ; o2 <- fmap (\x -> x * 0.1) (lf_pulse o1 0.0 0.2)
+-- >    ; audition [] (out1 o2) }
 lf_pulse :: ID m => Node -> Double -> Node -> m Node
-lf_pulse f ip w = 
+lf_pulse f ip w =
     do p <- phasor (Real_Constant ip) 1.0 (hz_to_incr 1.0 f sample_rate)
        return (select2 (p `n_gte` w) 0.0 1.0)
 
@@ -173,28 +216,58 @@
 mul_add :: Num a => a -> a -> a -> a
 mul_add i m a = (i * m) + a
 
+-- | Calculate feedback multipler given /delay/ and /decay/ times.
 calc_fb :: Floating a => a -> a -> a
 calc_fb delayt decayt = exp ((log 0.001 * delayt) / decayt)
 
 -- | Delay.
 delay :: ID m => Node -> Node -> Node -> m Node
-delay b s n =
-    do wi <- phasor (Integer_Constant 0) n 1
-       let ri = clipr n (wi + 1)
-       return (mrg (b_read b ri) (b_write b wi s))
+delay b s n = do
+  wi <- phasor (Integer_Constant 0) n 1
+  let ri = clipr n (wi + 1)
+  return (mrg (b_read b ri) (b_write b wi s))
 
--- | Comb filter.
+-- | Non-interpolating comb filter.  Inputs are: /b/ = buffer index,
+-- /i/ = input signal, /dl/ = delay time, /dc/ = decay time.
+--
+-- All times are in seconds.  The decay time is the time for the
+-- echoes to decay by @60@ decibels. If this time is negative then the
+-- feedback coefficient will be negative, thus emphasizing only odd
+-- harmonics at an octave lower.
+--
+-- Comb used as a resonator. The resonant fundamental is equal to
+-- reciprocal of the delay time.
+--
+-- > do { n <- white_noise_m
+-- >    ; dt <- let f x = lin_exp (x + 2.0) 1.0 2.0 0.0001 0.01
+-- >            in fmap f (lf_saw 0.1 0.0)
+-- >    ; c <- buf_comb_n 0 (n * 0.1) dt 0.2
+-- >    ; audition [b_alloc 0 44100] (out1 c) }
+--
+-- Comb used as an echo.
+--
+-- > do { i <- impulse 0.5 0.0
+-- >    ; n <- white_noise_m
+-- >    ; e <- decay (i * 0.5) 0.2
+-- >    ; c <- buf_comb_n 0 (e * n) 0.2 3.0
+-- >    ; audition [b_alloc 0 44100] (out1 c) }
 buf_comb_n :: ID m => Node -> Node -> Node -> Node -> m Node
-buf_comb_n b s dlt dct =
-    do let n = n_lrint (dlt * sample_rate)
-           fb = calc_fb dlt dct
-           c i = do x <- delay b i n
-                    return (split (s + (fb * x)))
-       recm (Real_Constant 0) c
+buf_comb_n b s dlt dct = do
+  let n = n_lrint (dlt * sample_rate)
+      fb = calc_fb dlt dct
+      c i = do x <- delay b i n
+               return (split (s + (fb * x)))
+  recm (Real_Constant 0) c
 
--- | Resonant low pass filter, f = frequency, r = resonance.
+-- | Resonant low pass filter. Inputs are: /i/ = input signal, /f/ =
+-- frequency (hertz), /rq/ = reciprocal of Q (resonance).
+--
+-- > do { n <- white_noise_m
+-- >    ; f <- fmap (\x -> x * 40.0 + 220.0) (sin_osc 0.5 0.0)
+-- >    ; r <- rlpf n f 0.1
+-- >    ; audition [] (out1 r) }
 rlpf :: ID m => Node -> Node -> Node -> m Node
-rlpf i f r = 
+rlpf i f r =
     let qr = max 0.001 r
         pf = f * radians_per_sample
         d = tan (pf * qr * 0.5)
@@ -207,30 +280,43 @@
 -- | Constrain p in (-q, q).
 clip2 :: Node -> Node -> Node
 clip2 p q =
-    let nq = negate q 
+    let nq = negate q
     in min q (max p nq)
 
 -- | White noise (-1, 1).
 white_noise :: Node -> Node
 white_noise p = white_noise_u p * 2.0 - 1.0
 
--- | White noise (-1, 1).
+-- | White noise (-1, 1).  Generates noise whose spectrum has equal
+-- power at all frequencies.
+--
+-- > do { n <- white_noise_m
+-- >    ; audition [] (out1 (n * 0.1)) }
 white_noise_m :: ID m => m Node
-white_noise_m = 
-    do i <- generateID
-       return (white_noise (n_integer_constant i))
+white_noise_m = do
+  i <- generateID
+  return (white_noise (n_integer_constant i))
 
--- | Brown noise (-1, 1).
+-- | Brown noise (-1, 1).  Generates noise whose spectrum falls off in
+-- power by 6 dB per octave.
+--
+-- > do { n <- brown_noise_m
+-- >    ; audition [] (out1 (n * 0.1)) }
+--
+-- > do { n <- brown_noise_m
+-- >    ; let f = lin_exp n (-1.0) 1.0 64.0 9600.0
+-- >      in do { o <- sin_osc f 0
+-- >            ; audition [] (out1 (o * 0.1)) } }
 brown_noise_m :: ID m => m Node
-brown_noise_m = 
-    do w <- white_noise_m
-       let w8 = w / 8.0
-       iir1 
-         (Real_Constant 0) 
-         (\x y1 -> let z = x + y1 
-                       r = select2 (z `n_lt` (-1.0)) ((-2.0) - z) z
-                   in select2 (z `n_gt` 1.0) (2.0 - z) r)
-         w8
+brown_noise_m = do
+  w <- white_noise_m
+  let w8 = w / 8.0
+  iir1
+   (Real_Constant 0)
+   (\x y1 -> let z = x + y1
+                 r = select2 (z `n_lt` (-1.0)) ((-2.0) - z) z
+             in select2 (z `n_gt` 1.0) (2.0 - z) r)
+   w8
 
 -- | Two zero fixed midpass filter.
 bpz2 :: ID m => Node -> m Node
@@ -250,9 +336,9 @@
 
 -- | One pole filter.
 one_pole :: ID m => Node -> Node -> m Node
-one_pole i cf = iir1 
-                  (Real_Constant 0) 
-                  (\x y1 -> ((1.0 - abs cf) * x) + (cf * y1)) 
+one_pole i cf = iir1
+                  (Real_Constant 0)
+                  (\x y1 -> ((1.0 - abs cf) * x) + (cf * y1))
                   i
 
 -- | One zero filter.
@@ -261,22 +347,50 @@
 
 -- | Second order filter section.
 sos :: ID m => Node -> Node -> Node -> Node -> Node -> Node -> m Node
-sos i a0 a1 a2 b1 b2 = 
+sos i a0 a1 a2 b1 b2 =
     let f x x1 x2 y1 y2 = a0*x + a1*x1 + a2*x2 + b1*y1 + b2*y2
     in biquad f i
 
 -- | Impulse oscillator (non band limited).
+-- Outputs non band limited single sample impulses.
+-- Inputs are: /f/ = frequency (in hertz), /ip/ = phase offset (0..1)
+--
+-- > do { o <- impulse 800.0 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
+--
+-- > do { f <- fmap (\x -> x * 2500.0 + 2505.0) (sin_osc 0.25 0.0)
+-- >    ; o <- impulse f 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
 impulse :: ID m => Node -> Double -> m Node
-impulse f ip =
-    do let i = hz_to_incr 1.0 f sample_rate
-       p <- phasor (Real_Constant ip) 1.0 i
-       x1 <- unit_delay (Real_Constant 0) p
-       let s = (x1 `n_lt` 0.5) `n_and` (p `n_gte` 0.5)
-       return (select2 s 1.0 0.0)
+impulse f ip = do
+  let i = hz_to_incr 1.0 f sample_rate
+  p <- phasor (Real_Constant ip) 1.0 i
+  x1 <- unit_delay (Real_Constant 0) p
+  let s = (x1 `n_lt` 0.5) `n_and` (p `n_gte` 0.5)
+  return (select2 s 1.0 0.0)
 
--- | Two pole resonant filter.
+-- | A two pole resonant filter with zeroes at z = +/- 1. Based on
+-- K. Steiglitz, \"A Note on Constant-Gain Digital Resonators\",
+-- /Computer Music Journal/, vol 18, no. 4, pp. 8-10, Winter 1994.
+-- The reciprocal of Q is used rather than Q because it saves a divide
+-- operation inside the unit generator.
+--
+-- Inputs are: /i/ = input signal, /f/ = resonant frequency (in
+-- hertz), /rq/ = bandwidth ratio (reciprocal of Q); where /rq/ =
+-- bandwidth / centerFreq.
+--
+-- > do { n <- white_noise_m
+-- >    ; r <- resonz (n * 0.5) 440.0 0.1
+-- >    ; audition [] (out1 r) }
+--
+-- Modulate frequency
+--
+-- > do { n <- white_noise_m
+-- >    ; f <- fmap (\x -> x * 3500.0 + 4500.0) (lf_saw 0.1 0.0)
+-- >    ; r <- resonz (n * 0.5) f 0.05
+-- >    ; audition [] (out1 r) }
 resonz :: ID m => Node -> Node -> Node -> m Node
-resonz i f rq = 
+resonz i f rq =
     let ff = f * radians_per_sample
         b = ff * rq
         r = 1.0 - b * 0.5
@@ -289,14 +403,27 @@
     in iir2 (\x y1 y2 -> let y0 = x + b1 * y1 + b2 * y2
                          in a0 * (y0 - y2)) i
 
--- | Sample and hold.
+-- | Sample and hold. Holds input signal value when triggered.  Inputs
+-- are: /i/ = input signal, /t/ = trigger (non-positive to positive).
+--
+-- > do { n <- white_noise_m
+-- >    ; i <- impulse 9.0 0.0
+-- >    ; l <- latch n i
+-- >    ; o <- sin_osc (l * 400.0 + 500.0) 0.0
+-- >    ; audition [] (out1 (o * 0.2)) }
 latch :: ID m => Node -> Node -> m Node
-latch i t = iir1 
-              (Real_Constant 0) 
-              (\x y1 -> select2 (t `n_gt` 0.0) x y1) 
+latch i t = iir1
+              (Real_Constant 0)
+              (select2 (t `n_gt` 0.0))
               i
 
 -- | Linear range conversion.
+--
+-- > map (\i -> lin_lin i (-1) 1 0 1) [-1, -0.9 .. 1.0]
+--
+-- > do { s <- lf_saw 1.0 0.0
+-- >    ; o <- sin_osc (lin_lin s (-1.0) 1.0 220.0 440.0) 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
 lin_lin :: Fractional a => a -> a -> a -> a -> a -> a
 lin_lin i in_l in_r out_l out_r =
     let s = (out_r - out_l) / (in_r - in_l)
@@ -304,6 +431,12 @@
     in (i * s) + o
 
 -- | Exponential range conversion.
+--
+-- > map (\i -> lin_exp i 1 2 1 3) [1, 1.1 .. 2]
+--
+-- > do { s <- lf_saw 0.25 0.0
+-- >    ; o <- sin_osc (lin_exp (s + 1.0) 0.0 2.0 220.0 440.0) 0.0
+-- >    ; audition [] (out1 (o * 0.1)) }
 lin_exp :: Floating a => a -> a -> a -> a -> a -> a
 lin_exp i in_l in_r out_l out_r =
     let rt = out_r / out_l
@@ -311,7 +444,20 @@
         rr = rn * negate in_l
     in out_l * (rt ** (i * rn + rr))
 
--- | Exponential decay.
+-- | Exponential decay. Inputs are: /i/ = input signal, /t/ = decay
+-- time.  This is essentially the same as Integrator except that
+-- instead of supplying the coefficient directly, it is caculated from
+-- a 60 dB decay time. This is the time required for the integrator to
+-- lose 99.9 % of its value or -60dB. This is useful for exponential
+-- decaying envelopes triggered by impulses.
+--
+-- Used as an envelope.
+--
+-- > do { n <- brown_noise_m
+-- >    ; f <- lf_saw 0.1 0.0
+-- >    ; i <- impulse (lin_lin f (-1.0) 1.0 2.0 5.0) 0.25
+-- >    ; e <- decay i 0.2
+-- >    ; audition [] (out1 (e * n)) }
 decay :: ID m => Node -> Node -> m Node
 decay i dt =
     let b1 = exp (log 0.001 / (dt * sample_rate))
@@ -329,18 +475,28 @@
 delay2 :: ID m => Node -> m Node
 delay2 = iir2 (\_ _ y2 -> y2)
 
--- | Simple averaging filter.
+-- | Simple averaging filter.  Inputs are: /i/ = input signal, /t/ =
+-- lag time.
+--
+-- > do { s <- sin_osc 0.05 0.0
+-- >    ; let f = lin_lin s (-1.0) 1.0 220.0 440.0
+-- >      in do { o <- sin_osc f 0.0
+-- >            ; f' <- lag f 1.0
+-- >            ; o' <- sin_osc f' 0.0
+-- >            ; audition [] (out2 (o * 0.2, o' * 0.2)) } }
 lag :: ID m => Node -> Node -> m Node
 lag i t = let b1 = exp (log (0.001 / (t * sample_rate)))
           in iir1 (Real_Constant 0) (\x y1 -> x + b1 * (y1 - x)) i
 
 -- | Nested lag filter.
 lag2 :: ID m => Node -> Node -> m Node
-lag2 i t = do a <- lag i t
-              lag a t
+lag2 i t = do
+  a <- lag i t
+  lag a t
 
 -- | Twice nested lag filter.
 lag3 :: ID m => Node -> Node -> m Node
-lag3 i t = do a <- lag i t
-              b <- lag a t
-              lag b t
+lag3 i t = do
+  a <- lag i t
+  b <- lag a t
+  lag b t
diff --git a/hdf.cabal b/hdf.cabal
--- a/hdf.cabal
+++ b/hdf.cabal
@@ -1,17 +1,19 @@
 Name:              hdf
-Version:           0.7
+Version:           0.11
 Synopsis:          Haskell data flow library for audio processing
-Description:       Haskell data flow library for audio processing
+Description:       Haskell data flow library for audio processing.
+                   Requires the @jack-dl@ host from @rju@,
+                   see <http://slavepianos.org/rd/?t=rju>.
 License:           GPL
 Category:          Sound
-Copyright:         (c) Rohan Drape, 2006-2009
+Copyright:         (c) Rohan Drape, 2006-2011
 Author:            Rohan Drape
 Maintainer:        rd@slavepianos.org
 Stability:         Experimental
-Homepage:          http://www.slavepianos.org/rd/f/740981/
-Tested-With:       GHC == 6.8.2
+Homepage:          http://slavepianos.org/rd/?t=hdf
+Tested-With:       GHC == 7.2.2
 Build-Type:        Simple
-Cabal-Version:     >= 1.6
+Cabal-Version:     >= 1.8
 
 Data-files:        README
                    -- The below is appended by:
@@ -38,17 +40,21 @@
                    Help/UGen/Oscillator/sin_osc.help.lhs
 
 Library
-  Build-Depends:   base == 3.*,
+  Build-Depends:   base == 4.*,
                    directory,
                    fgl,
                    filepath,
-                   hosc == 0.7,
+                   hosc == 0.11.*,
                    process
   GHC-Options:     -Wall -fwarn-tabs
   Exposed-modules: Sound.DF
-  Other-modules:   Sound.DF.Audition
+                   Sound.DF.Audition
                    Sound.DF.CGen
                    Sound.DF.Draw
                    Sound.DF.Graph
                    Sound.DF.Node
                    Sound.DF.UGen
+
+Source-Repository  head
+  Type:            darcs
+  Location:        http://slavepianos.org/rd/sw/hdf/
