diff --git a/Help/Graphs/adso.lhs b/Help/Graphs/adso.lhs
--- a/Help/Graphs/adso.lhs
+++ b/Help/Graphs/adso.lhs
@@ -29,5 +29,5 @@
 >                         ; pauseThread t } }
 > in withSC3 (\fd -> do { mapM_ (\i -> async fd (b_alloc i n 1)) [0..6]
 >                       ; play fd adso
->                       ; mapM_ (pattern fd) =<< rrand_l 32 0.025 0.75 
+>                       ; mapM_ (pattern fd) =<< rrand_l 32 0.025 0.75
 >                       ; reset fd })
diff --git a/Help/Graphs/aleatoric-quartet.lhs b/Help/Graphs/aleatoric-quartet.lhs
--- a/Help/Graphs/aleatoric-quartet.lhs
+++ b/Help/Graphs/aleatoric-quartet.lhs
@@ -2,7 +2,8 @@
 
 > import Sound.SC3
 
-> let { amp = 0.07
+> let { base_mn = Control KR "note" 66
+>     ; amp = Control KR "ampl" 0.07
 >     ; density = mouseX kr 0.01 1 Linear 0.1
 >     ; dmul = recip density * 0.5 * amp
 >     ; dadd = amp - dmul
@@ -14,7 +15,7 @@
 >                 ; let r0 = select i0 (mce [1, 0.5, 0.25])
 >                   in do { r1 <- rand (-30) 30
 >                         ; n0 <- lfNoise0 kr r0
->                         ; let m = lag (roundE (n0 * 7 + 66 + r1) 1) 0.2
+>                         ; let m = lag (roundE (n0 * 7 + base_mn + r1) 1) 0.2
 >                           in return (midiCPS m) } }
 >     ; mk_s = do { f <- fmap recip mk_f
 >                 ; r <- rand (-1) 1
diff --git a/Help/Graphs/bowed-string.lhs b/Help/Graphs/bowed-string.lhs
--- a/Help/Graphs/bowed-string.lhs
+++ b/Help/Graphs/bowed-string.lhs
@@ -5,23 +5,28 @@
 > import qualified Sound.SC3.UGen.Monadic as M
 > import System.Random
 
-> let { rrand l r = getStdRandom (randomR (l, r)) 
->     ; choose l = fmap (l !!) (rrand 0 (length l - 1))
->     ; root = 5
->     ; scale = map (+ root) [0, 2, 4, 5, 7, 9, 11] 
->     ; oct = [24, 36, 48, 60, 72, 84] }
-> in do { n0 <- clone 2 (M.brownNoise ar)
->       ; r0 <- M.expRand 0.125 0.5
->       ; r1 <- M.rand 0.7 0.9
->       ; r2 <- sequence (replicate 12 (M.rand 1.0 3.0))
->       ; f <- fmap midiCPS (liftM2 (+) (choose scale) (choose oct))
->       ; n1 <- M.lfNoise1 kr r0
->       ; let { x = n0 * 0.007 * max 0 (n1 * 0.6 + 0.4)
->             ; geom n i z = take n (iterate (* z) i)
->             ; iota n i z = take n (iterate (+ z) i)
->             ; d = klankSpec (iota 12 f f) (geom 12 1 r1) r2
->             ; k = klank x 1 0 1 d }
+> bowed_string :: IO ()
+> bowed_string =
+>     let { rrand l r = getStdRandom (randomR (l, r))
+>         ; choose l = fmap (l !!) (rrand 0 (length l - 1))
+>         ; root = 5
+>         ; scale = map (+ root) [0, 2, 4, 5, 7, 9, 11]
+>         ; oct = [24, 36, 48, 60, 72, 84] }
+>   in do { n0 <- clone 2 (M.brownNoise ar)
+>         ; r0 <- M.expRand 0.125 0.5
+>         ; r1 <- M.rand 0.7 0.9
+>         ; r2 <- sequence (replicate 12 (M.rand 1.0 3.0))
+>         ; f <- fmap midiCPS (liftM2 (+) (choose scale) (choose oct))
+>         ; n1 <- M.lfNoise1 kr r0
+>         ; let { x = n0 * 0.007 * max 0 (n1 * 0.6 + 0.4)
+>               ; geom n i z = take n (iterate (* z) i)
+>               ; iota n i z = take n (iterate (+ z) i)
+>               ; d = klankSpec (iota 12 f f) (geom 12 1 r1) r2
+>               ; k = klank x 1 0 1 d }
 >         in audition (out 0 (softClip (k * 0.1))) }
+
+> main :: IO ()
+> main = bowed_string
 
 { var root = 5
 ; var scale = #[0, 2, 4, 5, 7, 9, 11] + root
diff --git a/Help/Graphs/chain-saw.lhs b/Help/Graphs/chain-saw.lhs
--- a/Help/Graphs/chain-saw.lhs
+++ b/Help/Graphs/chain-saw.lhs
@@ -8,29 +8,31 @@
 > import qualified Sound.SC3.UGen.Monadic as M
 > import System.Random
 
-> let { rrand l r = getStdRandom (randomR (l, r)) :: IO Double
->     ; coin n a b = do { m <- rrand 0.0 1.0
->                       ; return (if m > n then a else b) }
->     ; exprange s l r = linExp s (-1) 1 l r
->     ; chain n fn = foldr (<=<) return (replicate n fn)
->     ; mceProduct = mceEdit (\l -> [product l])
->     ; clipu s = clip2 s 1
->     ; dup a = mce2 a a
->     ; f s1 = do { xr <- fmap dup (M.expRand 0.1 2)
->                 ; n1 <- M.lfNoise1 kr xr
->                 ; n2 <- M.lfNoise1 kr xr
->                 ; n3 <- M.lfNoise1 kr xr
->                 ; f1 <- coin 0.6 (exprange n1 0.01 10) (exprange n2 10 50)
->                 ; s2 <- coin 0.5 (1 - s1) (mceReverse s1)
->                 ; let { f2 = linExp s1 (-1) 1 f1 (f1 * exprange n3 2 10)
->                       ; u1 = lfSaw kr f2 0 
->                       ; u2 = lfSaw kr (f1 * 0.1) 0 * 0.1 + 1 }
+> main :: IO ()
+> main =
+>    let { rrand l r = getStdRandom (randomR (l, r)) :: IO Double
+>        ; coin n a b = do { m <- rrand 0.0 1.0
+>                          ; return (if m > n then a else b) }
+>        ; exprange s l r = linExp s (-1) 1 l r
+>        ; chain n fn = foldr (<=<) return (replicate n fn)
+>        ; mceProduct = mceEdit (\l -> [product l])
+>        ; clipu s = clip2 s 1
+>        ; dup a = mce2 a a
+>        ; f s1 = do { xr <- fmap dup (M.expRand 0.1 2)
+>                    ; n1 <- M.lfNoise1 kr xr
+>                    ; n2 <- M.lfNoise1 kr xr
+>                    ; n3 <- M.lfNoise1 kr xr
+>                    ; f1 <- coin 0.6 (exprange n1 0.01 10) (exprange n2 10 50)
+>                    ; s2 <- coin 0.5 (1 - s1) (mceReverse s1)
+>                    ; let { f2 = linExp s1 (-1) 1 f1 (f1 * exprange n3 2 10)
+>                          ; u1 = lfSaw kr f2 0
+>                          ; u2 = lfSaw kr (f1 * 0.1) 0 * 0.1 + 1 }
 >                   in return . clipu =<< coin 0.5 (u1 * s2) (u1 * u2) }
->     ; inp = lfSaw kr (0.2 * mce2 1 1.1) 0
->     ; b_freq = mce [70, 800, 9000, 5242] }
-> in do { ff <- chain 8 f inp
->       ; let { c_saw = mceProduct (saw ar (exprange ff 6 11000))
->             ; b_saw = dup (mix (bpf c_saw b_freq 0.2)) }
+>        ; inp = lfSaw kr (0.2 * mce2 1 1.1) 0
+>        ; b_freq = mce [70, 800, 9000, 5242] }
+>   in do { ff <- chain 8 f inp
+>         ; let { c_saw = mceProduct (saw ar (exprange ff 6 11000))
+>               ; b_saw = dup (mix (bpf c_saw b_freq 0.2)) }
 >         in audition (out 0 (b_saw * 0.3)) }
 
 { var f = { arg s1
diff --git a/Help/Graphs/crotale.lhs b/Help/Graphs/crotale.lhs
--- a/Help/Graphs/crotale.lhs
+++ b/Help/Graphs/crotale.lhs
@@ -3,168 +3,171 @@
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Base as B
 
-> let { crotale = ( [ 35.45676040649414
->                   , 128.59849548339844
->                   , 346.9721984863281
->                   , 483.5544128417969
->                   , 1049.2449951171875
->                   , 1564.0279541015625
->                   , 1756.3399658203125
->                   , 3391.666015625
->                   , 3451.802001953125
->                   , 3497.261962890625
->                   , 3596.89794921875
->                   , 3696.739013671875
->                   , 3835.235107421875
->                   , 3845.955078125
->                   , 4254.85107421875
->                   , 4407.533203125
->                   , 4415.26416015625
->                   , 4552.865234375
->                   , 5538.076171875
->                   , 5637.73681640625
->                   , 5690.2978515625
->                   , 5728.0068359375
->                   , 5764.27685546875
->                   , 5824.4189453125
->                   , 6377.60498046875
->                   , 6544.35009765625
->                   , 6807.14404296875
->                   , 6994.97021484375
->                   , 7026.84619140625
->                   , 7144.5859375
->                   , 7269.61279296875
->                   , 7393.6708984375
->                   , 7897.259765625
->                   , 8040.4580078125
->                   , 8157.77099609375
->                   , 8225.01953125
->                   , 9126.150390625
->                   , 9488.529296875
->                   , 9916.408203125
->                   , 10155.599609375
->                   , 11715.9599609375
->                   , 12111.830078125
->                   , 12339.990234375
->                   , 12417.669921875
->                   , 12459.2802734375
->                   , 12618.330078125
->                   , 13116.490234375
->                   , 13201.1298828125
->                   , 13297.830078125
->                   , 13533.75 ]
->                 , [ 0.0012827360769733787
->                   , 0.0008040848188102245
->                   , 0.017361238598823547
->                   , 0.004835359752178192
->                   , 0.004413491114974022
->                   , 0.004110544919967651
->                   , 0.0003338181704748422
->                   , 0.0036140112206339836
->                   , 0.006919348146766424
->                   , 0.0003224937245249748
->                   , 0.0006031467346474528
->                   , 0.06686479598283768
->                   , 0.000605064386036247
->                   , 0.003602313343435526
->                   , 0.0002835785271599889
->                   , 0.015243238769471645
->                   , 0.020536603406071663
->                   , 0.016677580773830414
->                   , 0.0009245267719961703
->                   , 0.20205098390579224
->                   , 0.0012542791664600372
->                   , 0.012705927714705467
->                   , 0.0002523190632928163
->                   , 0.0004866079252678901
->                   , 0.0006429700297303498
->                   , 0.0007763264584355056
->                   , 0.2081160992383957
->                   , 0.0024918108247220516
->                   , 0.00193469924852252
->                   , 0.005231771152466536
->                   , 0.0069242212921381
->                   , 0.001203975174576044
->                   , 0.2050020843744278
->                   , 0.04060448706150055
->                   , 0.0038344631902873516
->                   , 0.002189427148550749
->                   , 0.18056060373783112
->                   , 0.002192433224990964
->                   , 0.006516554858535528
->                   , 0.009982921183109283
->                   , 0.004745401442050934
->                   , 0.046154771000146866
->                   , 0.000510294979903847
->                   , 0.0018905038014054298
->                   , 0.0019782145973294973
->                   , 0.006729386281222105
->                   , 0.0023426134139299393
->                   , 0.0024002245627343655
->                   , 0.03515550494194031
->                   , 0.0014084168942645192 ]
->                 , [ 5.203680992126465
->                   , 1.7034343481063843
->                   , 40.16516876220703
->                   , 27.282501220703125
->                   , 0.8950523138046265
->                   , 42.84742736816406
->                   , 2.6603667736053467
->                   , 15.7678861618042
->                   , 6.848367214202881
->                   , 3.2325007915496826
->                   , 1.7343382835388184
->                   , 2.0202419757843018
->                   , 4.7279052734375
->                   , 9.400103569030762
->                   , 0.7102512717247009
->                   , 37.494625091552734
->                   , 36.24879455566406
->                   , 29.172658920288086
->                   , 3.891019344329834
->                   , 4.757885456085205
->                   , 3.851426124572754
->                   , 20.90781021118164
->                   , 3.732874870300293
->                   , 2.3834102153778076
->                   , 10.443285942077637
->                   , 8.795611381530762
->                   , 20.98564338684082
->                   , 18.01180076599121
->                   , 25.297883987426758
->                   , 14.819819450378418
->                   , 42.39189910888672
->                   , 2.9485135078430176
->                   , 11.043763160705566
->                   , 49.55165100097656
->                   , 29.882694244384766
->                   , 10.527188301086426
->                   , 23.5572452545166
->                   , 26.55561637878418
->                   , 45.099605560302734
->                   , 22.550390243530273
->                   , 36.46126174926758
->                   , 11.826201438903809
->                   , 16.818185806274414
->                   , 14.903121948242188
->                   , 32.81113815307617
->                   , 43.1389045715332
->                   , 12.289558410644531
->                   , 11.498942375183105
->                   , 10.465788841247559
->                   , 24.93169593811035 ] )
->     ; (cf, ca, cd) = crotale
->     ; ps = mce [-12, -5, 0, 2, 4, 5, 7, 12]
->     ; n = B.pinkNoise (uid 0) ar
->     ; t = B.dust (uid 0) kr 3
->     ; fs = select (B.tiRand (uid 0) 0 7 t) ps
->     ; g = B.tRand (uid 0) 0 1 t
->     ; fo = B.tRand (uid 1) 0 1 t
->     ; ds = B.tRand (uid 2) 2 7 t
->     ; p = B.tRand (uid 3) (-1) 1 t
->     ; s = decay2 t 0.06 0.01 * n * g
->     ; k = dynKlank s (midiRatio fs) fo ds (klankSpec cf ca (map recip cd)) }
-> in audition (out 0 (pan2 k p 1))
+> main :: IO ()
+> main =
+>     let { crotale = ( [ 35.45676040649414
+>                       , 128.59849548339844
+>                       , 346.9721984863281
+>                       , 483.5544128417969
+>                       , 1049.2449951171875
+>                       , 1564.0279541015625
+>                       , 1756.3399658203125
+>                       , 3391.666015625
+>                       , 3451.802001953125
+>                       , 3497.261962890625
+>                       , 3596.89794921875
+>                       , 3696.739013671875
+>                       , 3835.235107421875
+>                       , 3845.955078125
+>                       , 4254.85107421875
+>                       , 4407.533203125
+>                       , 4415.26416015625
+>                       , 4552.865234375
+>                       , 5538.076171875
+>                       , 5637.73681640625
+>                       , 5690.2978515625
+>                       , 5728.0068359375
+>                       , 5764.27685546875
+>                       , 5824.4189453125
+>                       , 6377.60498046875
+>                       , 6544.35009765625
+>                       , 6807.14404296875
+>                       , 6994.97021484375
+>                       , 7026.84619140625
+>                       , 7144.5859375
+>                       , 7269.61279296875
+>                       , 7393.6708984375
+>                       , 7897.259765625
+>                       , 8040.4580078125
+>                       , 8157.77099609375
+>                       , 8225.01953125
+>                       , 9126.150390625
+>                       , 9488.529296875
+>                       , 9916.408203125
+>                       , 10155.599609375
+>                       , 11715.9599609375
+>                       , 12111.830078125
+>                       , 12339.990234375
+>                       , 12417.669921875
+>                       , 12459.2802734375
+>                       , 12618.330078125
+>                       , 13116.490234375
+>                       , 13201.1298828125
+>                       , 13297.830078125
+>                       , 13533.75 ]
+>                     , [ 0.0012827360769733787
+>                       , 0.0008040848188102245
+>                       , 0.017361238598823547
+>                       , 0.004835359752178192
+>                       , 0.004413491114974022
+>                       , 0.004110544919967651
+>                       , 0.0003338181704748422
+>                       , 0.0036140112206339836
+>                       , 0.006919348146766424
+>                       , 0.0003224937245249748
+>                       , 0.0006031467346474528
+>                       , 0.06686479598283768
+>                       , 0.000605064386036247
+>                       , 0.003602313343435526
+>                       , 0.0002835785271599889
+>                       , 0.015243238769471645
+>                       , 0.020536603406071663
+>                       , 0.016677580773830414
+>                       , 0.0009245267719961703
+>                       , 0.20205098390579224
+>                       , 0.0012542791664600372
+>                       , 0.012705927714705467
+>                       , 0.0002523190632928163
+>                       , 0.0004866079252678901
+>                       , 0.0006429700297303498
+>                       , 0.0007763264584355056
+>                       , 0.2081160992383957
+>                       , 0.0024918108247220516
+>                       , 0.00193469924852252
+>                       , 0.005231771152466536
+>                       , 0.0069242212921381
+>                       , 0.001203975174576044
+>                       , 0.2050020843744278
+>                       , 0.04060448706150055
+>                       , 0.0038344631902873516
+>                       , 0.002189427148550749
+>                       , 0.18056060373783112
+>                       , 0.002192433224990964
+>                       , 0.006516554858535528
+>                       , 0.009982921183109283
+>                       , 0.004745401442050934
+>                       , 0.046154771000146866
+>                       , 0.000510294979903847
+>                       , 0.0018905038014054298
+>                       , 0.0019782145973294973
+>                       , 0.006729386281222105
+>                       , 0.0023426134139299393
+>                       , 0.0024002245627343655
+>                       , 0.03515550494194031
+>                       , 0.0014084168942645192 ]
+>                     , [ 5.203680992126465
+>                       , 1.7034343481063843
+>                       , 40.16516876220703
+>                       , 27.282501220703125
+>                       , 0.8950523138046265
+>                       , 42.84742736816406
+>                       , 2.6603667736053467
+>                       , 15.7678861618042
+>                       , 6.848367214202881
+>                       , 3.2325007915496826
+>                       , 1.7343382835388184
+>                       , 2.0202419757843018
+>                       , 4.7279052734375
+>                       , 9.400103569030762
+>                       , 0.7102512717247009
+>                       , 37.494625091552734
+>                       , 36.24879455566406
+>                       , 29.172658920288086
+>                       , 3.891019344329834
+>                       , 4.757885456085205
+>                       , 3.851426124572754
+>                       , 20.90781021118164
+>                       , 3.732874870300293
+>                       , 2.3834102153778076
+>                       , 10.443285942077637
+>                       , 8.795611381530762
+>                       , 20.98564338684082
+>                       , 18.01180076599121
+>                       , 25.297883987426758
+>                       , 14.819819450378418
+>                       , 42.39189910888672
+>                       , 2.9485135078430176
+>                       , 11.043763160705566
+>                       , 49.55165100097656
+>                       , 29.882694244384766
+>                       , 10.527188301086426
+>                       , 23.5572452545166
+>                       , 26.55561637878418
+>                       , 45.099605560302734
+>                       , 22.550390243530273
+>                       , 36.46126174926758
+>                       , 11.826201438903809
+>                       , 16.818185806274414
+>                       , 14.903121948242188
+>                       , 32.81113815307617
+>                       , 43.1389045715332
+>                       , 12.289558410644531
+>                       , 11.498942375183105
+>                       , 10.465788841247559
+>                       , 24.93169593811035 ] )
+>         ; (cf, ca, cd) = crotale
+>         ; ps = mce [-12, -5, 0, 2, 4, 5, 7, 12]
+>         ; n = B.pinkNoise (uid 0) ar
+>         ; t = B.dust (uid 0) kr 3
+>         ; fs = select (B.tiRand (uid 0) 0 7 t) ps
+>         ; g = B.tRand (uid 0) 0 1 t
+>         ; fo = B.tRand (uid 1) 0 1 t
+>         ; ds = B.tRand (uid 2) 2 7 t
+>         ; p = B.tRand (uid 3) (-1) 1 t
+>         ; s = decay2 t 0.06 0.01 * n * g
+>         ; ks = klankSpec cf ca (map recip cd)
+>         ; k = dynKlank s (midiRatio fs) fo ds ks }
+>   in audition (out 0 (pan2 k p 1))
 
 { var crotale = [ [ 35.45676040649414
                   , 128.59849548339844
diff --git a/Help/Graphs/deep-sea.lhs b/Help/Graphs/deep-sea.lhs
--- a/Help/Graphs/deep-sea.lhs
+++ b/Help/Graphs/deep-sea.lhs
@@ -3,22 +3,24 @@
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Base as B
 
-> let { range s l r = let m = (r - l) * 0.5 in mulAdd s m (m + l)
->     ; amp = 1
->     ; pan = 0
->     ; variation = 0.9
->     ; n = B.rand (uid 0) 7 46
->     ; dt1 = 25.0 + B.rand (uid 1) (-1.7) 1.7
->     ; dt2 = (dt1 + B.lfNoise2 (uid 0) kr 2) * variation * 0.001
->     ; freq = 901 + B.rand (uid 2) 0 65
->     ; t = impulse ar (recip dt2) 0 * 100
->     ; count = pulseCount t 0
->     ; mul = count <* n
->     ; u1 = bpf (mul * t) freq 1 * 0.1
->     ; freq2 = freq * ((count `modE` range (B.lfNoise1 (uid 0) kr 1) 2 20) + 1)
->     ; u2 = bpf u1 freq2 1 * 0.2 }
-> in audition (mrg [ detectSilence u2 0.0001 0.2 RemoveSynth
->                  , out 0 (pan2 u2 pan (amp * 10)) ])
+> main :: IO ()
+> main =
+>   let { range s l r = let m = (r - l) * 0.5 in mulAdd s m (m + l)
+>       ; amp = 1
+>       ; pan = 0
+>       ; variation = 0.9
+>       ; n = B.rand (uid 0) 7 46
+>       ; dt1 = 25.0 + B.rand (uid 1) (-1.7) 1.7
+>       ; dt2 = (dt1 + B.lfNoise2 (uid 0) kr 2) * variation * 0.001
+>       ; freq = 901 + B.rand (uid 2) 0 65
+>       ; t = impulse ar (recip dt2) 0 * 100
+>       ; count = pulseCount t 0
+>       ; mul = count <* n
+>       ; u1 = bpf (mul * t) freq 1 * 0.1
+>       ; freq2 = freq * ((count `modE` range (B.lfNoise1 (uid 0) kr 1) 2 20) + 1)
+>       ; u2 = bpf u1 freq2 1 * 0.2 }
+>   in audition (mrg [ detectSilence u2 0.0001 0.2 RemoveSynth
+>                    , out 0 (pan2 u2 pan (amp * 10)) ])
 
 { var amp = 1
 ; var pan = 0
diff --git a/Help/Graphs/diffraction.lhs b/Help/Graphs/diffraction.lhs
--- a/Help/Graphs/diffraction.lhs
+++ b/Help/Graphs/diffraction.lhs
@@ -21,3 +21,23 @@
 >                          ; return (sinOsc ar fr 0 * am) } }
 >           in liftM2 mce2 (mixFillM 16 f) (mixFillM 12 f) }
 > in audition . (out 0) . sum =<< sequence [p, q, r]
+
+{ var x = MouseX.kr(0.001, 0.02, 'exponential', 0.1)
+; var y = MouseY.kr(120, 400, 'exponential', 0.1)
+; var p = { var f = LFNoise0.kr(4) * [32, 64]
+	      ; var w = LFNoise0.kr(32) * x
+	      ; var z = LFNoise0.kr(2) * 0.1
+          ; var m = LFNoise0.kr(6)
+	      ; var s = Pulse.ar(f, w)
+          ; Resonz.ar(s, y + z, (m * 0.4) + 0.8) * 0.5 }
+; var q = { var n = LFNoise0.kr(128)
+	      ; CombN.ar(p.value, 0.2, (n * 0.1) + 0.1, 3) }
+; var r = { var x1 = MouseX.kr(0.75, 1.25, 'exponential', 0.1)
+          ; var y1 = MouseY.kr(0.25, 1, 'exponential', 0.1)
+	      ; var f = { var fr = Rand(50, 59) * x1
+	                ; var am = Rand(0.04, 0.16) * y1
+                    ; SinOsc.ar(fr, 0) * am }
+          ; [Mix.fill(16, f), Mix.fill(12, f)] }
+; Out.ar(0, p.value + q.value + r.value) }.play
+
+
diff --git a/Help/Graphs/feedr.lhs b/Help/Graphs/feedr.lhs
--- a/Help/Graphs/feedr.lhs
+++ b/Help/Graphs/feedr.lhs
@@ -4,7 +4,7 @@
 > import Sound.SC3
 
 > let { delayWr b i = recordBuf b 0 1 0 1 Loop 0 i
->     ; tap nc b dt = playBuf nc b 1 0 (dt * (- sampleRate)) Loop
+>     ; tap nc b dt = playBuf nc b 1 0 (dt * (- sampleRate)) Loop DoNothing
 >     ; dl = 6
 >     ; feedr n = do { t <- sequence (replicate n (rand 0.0 (constant dl)))
 >                    ; g <- sequence (replicate n (rand 0.4 1.0))
diff --git a/Help/Graphs/lin-sosc.lhs b/Help/Graphs/lin-sosc.lhs
--- a/Help/Graphs/lin-sosc.lhs
+++ b/Help/Graphs/lin-sosc.lhs
@@ -8,8 +8,8 @@
 
 > let { n = 1024
 >     ; x = mouseX kr 0.001 1.0 Linear 0.1
->     ; tblM b = playBuf 1 b (x * bufRateScale kr b) 0 0 Loop
->     ; tblC b c = playBuf 1 b (in' 1 kr c * bufRateScale kr b) 0 0 Loop
+>     ; tblM b = playBuf 1 b (x * bufRateScale kr b) 0 0 Loop DoNothing
+>     ; tblC b c = playBuf 1 b (in' 1 kr c * bufRateScale kr b) 0 0 Loop DoNothing
 >     ; o = sinOsc ar (tblM 0) 0 * tblM 1 
 >     ; co = clip2 (pan2 o (tblC 1 0) 0.025) 0.25
 >     ; rrand (a, b) = getStdRandom (randomR (a,b))
diff --git a/Help/Graphs/lucier.hs b/Help/Graphs/lucier.hs
new file mode 100644
--- /dev/null
+++ b/Help/Graphs/lucier.hs
@@ -0,0 +1,95 @@
+{-
+Alvin Lucier, "Music on a Long Thin Wire, Simulated"
+Chandrasekhar Ramakrishnan
+http://www.listarc.bham.ac.uk/lists/sc-users/msg47539.html
+http://www.listarc.bham.ac.uk/lists/sc-users/msg47540.html
+-}
+
+import Sound.SC3
+import qualified Sound.SC3.UGen.Base as B
+
+lucier_wire :: UGen -> IO ()
+lucier_wire freq =
+    let block_size = recip controlRate
+        mk_dt f = recip f - block_size
+	string_delay = mk_dt freq
+	pk1_pos = 0.1 -- pickup one position
+	src_pos = 0.3 -- source position
+	pk2_pos = 0.9 -- pickup two postion
+	max_delay = 1.0 -- maximum delay time (corresponds to a length = c * s)
+	mk_delay i r = lpz1 (delayC i max_delay (r * string_delay))
+	mk_allpass i r dt = lpz1 (allpassC i max_delay (r * string_delay) dt)
+	drv = localIn 1 AR -- driver (source + data stored in the string)
+	pk1_R =
+            let i = drv
+                r = src_pos - pk1_pos
+            in mk_delay i r
+	pk1_L =
+            let i = pk1_R * negate 1
+                r = pk1_pos * 2
+                dt = B.rand (uid 0) 0.001 0.11
+            in mk_allpass i r dt
+	pk2_L =
+            let i = pk1_L
+                r = pk2_pos - pk1_pos
+            in mk_delay i r * 0.99
+	stringL =
+            let i = pk2_L
+                r = 1.0 - pk2_pos
+            in mk_delay i r
+	pk2_R =
+            let i = stringL * negate 1
+                r = 1.0 - pk2_pos
+                dt = 2 + B.rand (uid 1) 0.001 0.11
+            in mk_allpass i r dt * 0.99
+	stringR =
+            let i = pk2_R
+                r = pk2_pos - src_pos
+            in mk_delay i r
+	source =
+            let s = sinOsc AR 220 0 * 0.01
+                p = pulse AR (60 + amplitude KR drv 0.01 0.01 * 11) 0.5 * 0.1
+                f = rlpf (s + p) 320 0.05
+                e = 1.0 - min (amplitude KR drv 0.01 0.01) 1.0
+	    in normalizer f 0.7 0.01 * e
+	l_out = localOut (source * 0.2 + stringR)
+	outL = pk1_L + pk1_R
+	outR = pk2_L + pk2_R
+    in audition (out 0 (mrg [mce2 outL outR, drv, source, l_out]))
+
+main :: IO ()
+main = lucier_wire 60
+
+{-
+lucier_wire 60
+
+{ var blocksize = ControlRate.ir.reciprocal
+; var mk_dt = { |f| f.reciprocal - blocksize }
+; var string_dt = mk_dt.(60)
+; var c = 425
+; var len = 40
+; var pk1_p = 0.1
+; var src_p = 0.3
+; var pk2_p = 0.9
+; var max_dt = 1
+; var mk_dl = { arg i, r
+                 ; LPZ1.ar(DelayC.ar(i, max_dt, r * string_dt)) }
+; var mk_ap = { arg i, r, dt
+	          ; LPZ1.ar(AllpassC.ar(i, max_dt, r * string_dt, dt)) }
+; var drv = LocalIn.ar(1)
+; var r = { Rand(0.001, 0.11) }
+; var pk1_R = mk_dl.(drv, src_p - pk1_p, 2 + r.())
+; var pk1_L = mk_ap.(pk1_R * -1, pk1_p * 2, r.())
+; var pk2_L = mk_dl.(pk1_L, pk2_p - pk1_p, r.()) * 0.99
+; var strL = mk_dl.(pk2_L, 1 - pk2_p, r.())
+; var pk2_R = mk_ap.(strL * -1, 1 - pk2_p, 2 + r.()) * 0.99
+; var strR = mk_dl.(pk2_R, pk2_p - src_p, 2 + r.())
+; var src = { var a = Amplitude.kr(drv, mul: 11)
+            ; p = Pulse.ar(60 + a, mul: 0.1)
+            ; RLPF.ar((SinOsc.ar(220, 0) * 0.01) + p, 320, 0.05) }
+; var src_n = { var a = Amplitude.kr(drv).min(1.0)
+              ; Normalizer.ar(src, 0.7) * (1.0 - a) }
+; LocalOut.ar(src * 0.2 + strR)
+; [pk1_L + pk1_R, pk2_L + pk2_R, drv, src] }.play
+
+-}
diff --git a/Help/Graphs/mouse-clatter.lhs b/Help/Graphs/mouse-clatter.lhs
--- a/Help/Graphs/mouse-clatter.lhs
+++ b/Help/Graphs/mouse-clatter.lhs
@@ -18,6 +18,23 @@
 >         in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                               ; play fd . out 0 =<< s }) }
 
+s.sendMsg('b_alloc', 10, 2048, 1);
+
+{ var x = MouseX.kr(100, 12000, 'linear', 0.1)
+; var y = MouseY.kr(0.01, 0.15, 'linear', 0.1)
+; var n1 = LFNoise0.kr([3, 3.25])
+; var t = Impulse.kr((n1 * 16) + 18, 0)
+; var n2 = TRand.kr(0.005, y, t)
+; var n3 = WhiteNoise.ar()
+; var n4 = TRand.kr(10, x, t)
+; var n5 = TRand.kr(0, 1, t)
+; var n6 = TExpRand.kr(0.15, 1, t)
+; var o = { var e = Decay2.kr(t, 0.01, n2)
+          ; BPF.ar(n3 * e, n4, n5) }
+; var n7 = PV_RandComb(FFT(10, o), n6, t)
+; var s = (o * 0.05) + IFFT(n7)
+; Out.ar(0, s) }.play
+
 (let* ((x (MouseX kr 100 12000 0 0.1))
        (y (MouseY kr 0.01 0.15 0 0.1))
        (n1 (LFNoise0 kr (mce2 3 3.25)))
diff --git a/Help/Graphs/record-scratcher.lhs b/Help/Graphs/record-scratcher.lhs
--- a/Help/Graphs/record-scratcher.lhs
+++ b/Help/Graphs/record-scratcher.lhs
@@ -10,7 +10,7 @@
 >     ; dx = x - delayN x 0.1 0.1
 >     ; bdx = mouseButton kr 1 0 0.3 + dx
 >     ; bdxr = bdx * bufRateScale kr 0
->     ; scr = playBuf 1 0 bdxr 0 0 Loop }
+>     ; scr = playBuf 1 0 bdxr 0 0 Loop DoNothing }
 > in withSC3 (\fd -> do { async fd (b_allocRead 0 fn 0 0)
 >                       ; play fd (out 0 (dup (scr * e))) })
 
diff --git a/Help/Graphs/rzblp.lhs b/Help/Graphs/rzblp.lhs
deleted file mode 100644
--- a/Help/Graphs/rzblp.lhs
+++ /dev/null
@@ -1,22 +0,0 @@
-rzblp (rd)
-
-> import Sound.SC3
-> import qualified Sound.SC3.UGen.Unsafe as U
-
-> let { wrp i l r = let m = (r - l) / 2
->                   in i * m + l + m
->     ; lfn f l r = wrp (U.lfNoise0 kr f) l r
->     ; hpb q = mixFill 2 (\_ -> let { f = lfn q 1330 1395
->                                    ; a = lfn q 0.001 0.007 }
->                                in blip ar f 24 * a)
->     ; mk_f d = let { q = lfn 5.2 5.2 5.21
->                    ; a = d dinf (mce [1, 3, 2, 7, 8])
->                    ; tr = impulse kr q 0
->                    ; freq = demand tr 0 a * 30 + 340 }
->                in sum [ blip ar freq 3 * lfn q 0.001 0.01
->                       , resonz (impulse ar q (mce2 0 0))
->                                    (lfn 5 30 640)
->                                    (lfn q 0.1 0.5) * lfn q 0.01 1.8
->                       , hpb q * lfn q 1.2 1.8
->                       , blip ar (lfn q 16 36) 3 * mce2 0.03 0.09 ] }
-> in audition (out 0 (mk_f U.drand + mk_f U.dxrand))
diff --git a/Help/Graphs/sample-and-hold-liquidities.lhs b/Help/Graphs/sample-and-hold-liquidities.lhs
--- a/Help/Graphs/sample-and-hold-liquidities.lhs
+++ b/Help/Graphs/sample-and-hold-liquidities.lhs
@@ -3,14 +3,16 @@
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Base as B
 
-> let { r = mouseX kr 1 200 Exponential 0.1
->     ; t = recip r
->     ; c = impulse kr r 0.4
->     ; cf = mouseY kr 100 8000 Exponential 0.1
->     ; f = latch (B.whiteNoise (uid 0) kr * cf * 0.5 + cf) c
->     ; p = latch (B.whiteNoise (uid 1) kr) c
->     ; i = pan2 (sinOsc ar f 0 * decay2 c (t * 0.1) (t * 0.9)) p 1 }
-> in audition (out 0 (combN i 0.3 0.3 2))
+> main :: IO ()
+> main =
+>   let { r = mouseX kr 1 200 Exponential 0.1
+>       ; t = recip r
+>       ; c = impulse kr r 0.4
+>       ; cf = mouseY kr 100 8000 Exponential 0.1
+>       ; f = latch (B.whiteNoise (uid 0) kr * cf * 0.5 + cf) c
+>       ; p = latch (B.whiteNoise (uid 1) kr) c
+>       ; i = pan2 (sinOsc ar f 0 * decay2 c (t * 0.1) (t * 0.9)) p 1 }
+>   in audition (out 0 (combN i 0.3 0.3 2))
 
 { var r = MouseX.kr(1, 200, 'exponential', 0.1)
 ; var t = r.reciprocal
diff --git a/Help/Graphs/strummable-guitar.lhs b/Help/Graphs/strummable-guitar.lhs
--- a/Help/Graphs/strummable-guitar.lhs
+++ b/Help/Graphs/strummable-guitar.lhs
@@ -3,16 +3,18 @@
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Base as B
 
-> let { scale = [ 52, 57, 62, 67, 71, 76 ]
->     ; str i = let { x = mouseX kr 0 1 Linear 0.2
->                   ; t = abs (hpz1 (x >* (0.25 + constant i * 0.1)))
->                   ; e = decay t 0.05
->                   ; n = B.pinkNoise (uid i) ar * e
->                   ; dt = 1 / (midiCPS (scale !! i))
->                   ; s = combL n dt dt 4 }
->               in pan2 s (constant i * 0.2 - 0.5) 1
->     ; strs = mixFill (length scale) str }
-> in audition (out 0 (leakDC (lpf strs 12000) 0.995))
+> main :: IO ()
+> main =
+>   let { scale = [ 52, 57, 62, 67, 71, 76 ]
+>       ; str i = let { x = mouseX kr 0 1 Linear 0.2
+>                     ; t = abs (hpz1 (x >* (0.25 + constant i * 0.1)))
+>                     ; e = decay t 0.05
+>                     ; n = B.pinkNoise (uid i) ar * e
+>                     ; dt = 1 / (midiCPS (scale !! i))
+>                     ; s = combL n dt dt 4 }
+>                 in pan2 s (constant i * 0.2 - 0.5) 1
+>       ; strs = mixFill (length scale) str }
+>   in audition (out 0 (leakDC (lpf strs 12000) 0.995))
 
 { var scale = [ 52, 57, 62, 67, 71, 76 ]
 ; var str = { arg i
diff --git a/Help/Graphs/tank.lhs b/Help/Graphs/tank.lhs
--- a/Help/Graphs/tank.lhs
+++ b/Help/Graphs/tank.lhs
@@ -4,35 +4,37 @@
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Monadic as M
 
-> let { r_allpass i = do { r <- clone 2 (M.rand 0.005 0.02)
->                        ; return (allpassN i 0.03 r 1) }
->     ; chain n f = foldl (>=>) return (replicate n f)
->     ; pling = do { d <- M.dust ar 0.2
->                  ; f <- M.expRand 300 2200
->                  ; p <- M.rand (-1) 1
->                  ; let { s1 = cubed (fSinOsc ar f 0)
->                        ; s2 = decay2 d 0.1 0.5 * 0.1 * s1 }
->                    in return (pan2 s2 p 1) }
->     ; bang = do { d <- M.dust ar 0.01
->                 ; n <- M.brownNoise ar
->                 ; return (pan2 (decay2 d 0.04 0.3 * n) 0 1) }
->     ; tank i = do { r1 <- clone 2 (M.rand 0.01 0.05)
->                   ; r2 <- clone 2 (M.rand 0.03 0.15)
->                   ; let { l0 = localIn 2 ar * 0.98
->                         ; l1 = onePole l0 0.33
->                         ; [l1l, l1r] = mceChannels l1
->                         ; l2 = rotate2 l1l l1r 0.23
->                         ; l3 = allpassN l2 0.05 r1 2
->                         ; l4 = delayN l3 0.3 (mce [0.17, 0.23])
->                         ; l5 = allpassN l4 0.05 r2 2              
->                         ; l6 = leakDC l5 0.995
->                         ; l7 = l6 + i }
->                     in return (mrg [l7, localOut l7]) }
->     ; signal = do { s <- liftM2 (+) bang (mixFillM 8 (const pling))
->                   ; chain 4 r_allpass s } }
-> in audition . out 0 =<< tank =<< signal
+> main :: IO ()
+> main =
+>   let { r_allpass i = do { r <- clone 2 (M.rand 0.005 0.02)
+>                          ; return (allpassN i 0.03 r 1) }
+>       ; chain n f = foldl (>=>) return (replicate n f)
+>       ; pling = do { d <- M.dust ar 0.2
+>                    ; f <- M.expRand 300 2200
+>                    ; p <- M.rand (-1) 1
+>                    ; let { s1 = cubed (fSinOsc ar f 0)
+>                          ; s2 = decay2 d 0.1 0.5 * 0.1 * s1 }
+>                      in return (pan2 s2 p 1) }
+>       ; bang = do { d <- M.dust ar 0.01
+>                   ; n <- M.brownNoise ar
+>                   ; return (pan2 (decay2 d 0.04 0.3 * n) 0 1) }
+>       ; tank i = do { r1 <- clone 2 (M.rand 0.01 0.05)
+>                     ; r2 <- clone 2 (M.rand 0.03 0.15)
+>                     ; let { l0 = localIn 2 ar * 0.98
+>                           ; l1 = onePole l0 0.33
+>                           ; [l1l, l1r] = mceChannels l1
+>                           ; l2 = rotate2 l1l l1r 0.23
+>                           ; l3 = allpassN l2 0.05 r1 2
+>                           ; l4 = delayN l3 0.3 (mce [0.17, 0.23])
+>                           ; l5 = allpassN l4 0.05 r2 2
+>                           ; l6 = leakDC l5 0.995
+>                           ; l7 = l6 + i }
+>                       in return (mrg [l7, localOut l7]) }
+>       ; signal = do { s <- liftM2 (+) bang (mixFillM 8 (const pling))
+>                     ; chain 4 r_allpass s } }
+>   in audition . out 0 =<< tank =<< signal
 
-{ var r_allpass = { arg signal 
+{ var r_allpass = { arg signal
                   ; var r = { Rand.new(0.005, 0.02) }.dup
                   ; AllpassN.ar(signal, 0.03, r, 1); }
 ; var pling = { var d = Dust.ar(0.2)
diff --git a/Help/Graphs/tgrn.lhs b/Help/Graphs/tgrn.lhs
--- a/Help/Graphs/tgrn.lhs
+++ b/Help/Graphs/tgrn.lhs
@@ -1,16 +1,23 @@
 tgrn (rd)
+ghci -e main tgrn.lhs
+C-cC-l C-cC-m
 
 > import Sound.SC3
 > import qualified Sound.SC3.UGen.Base as B
 
-> let { fn = "/home/rohan/audio/text.snd"
->     ; tgrn b = let { trate = mouseY kr 2 120 Exponential 0.1
->                    ; dur = 1.2 / trate
->                    ; clk = impulse ar trate 0
->                    ; pos = mouseX kr 0 (bufDur kr b) Linear 0.1
->                    ; pan = B.whiteNoise (uid 1) kr * 0.6
->                    ; n = roundE (B.whiteNoise (uid 2) kr * 3) 1
->                    ; rate = shiftLeft 1.2 n }
->                in tGrains 2 clk b rate pos dur pan 0.25 2 }
-> in withSC3 (\fd -> do { async fd (b_allocRead 10 fn 0 0)
->                       ; audition (out 0 (tgrn 10)) })
+> tgrn :: UGen -> UGen
+> tgrn b =
+>   let { trate = mouseY kr 2 120 Exponential 0.1
+>       ; dur = 1.2 / trate
+>       ; clk = impulse ar trate 0
+>       ; pos = mouseX kr 0 (bufDur kr b) Linear 0.1
+>       ; pan = B.whiteNoise (uid 1) kr * 0.6
+>       ; n = roundE (B.whiteNoise (uid 2) kr * 3) 1
+>       ; rate = shiftLeft 1.2 n }
+>   in tGrains 2 clk b rate pos dur pan 0.25 2
+
+> main :: IO ()
+> main =
+>   let fn = "/home/rohan/audio/text.snd"
+>   in withSC3 (\fd -> do { async fd (b_allocRead 10 fn 0 0)
+>                         ; audition (out 0 (tgrn 10)) })
diff --git a/Help/Graphs/trmlo.lhs b/Help/Graphs/trmlo.lhs
deleted file mode 100644
--- a/Help/Graphs/trmlo.lhs
+++ /dev/null
@@ -1,40 +0,0 @@
-trmlo (rd)
-
-> import Sound.SC3
-> import qualified Sound.SC3.UGen.Unsafe as U
-
-> let { mWrp i l r = linLin i (-1) 1 (midiCPS l) (midiCPS r)
->     ; mWrp1 i m = mWrp i m (m + 1)
->     ; mWrpN i m n = mWrp i m (m + n)
->     ; o1 = let { f = 5
->                ; d = 3
->                ; s = envSine d 0.1
->                ; e = envGen kr 1 1 0 1 DoNothing s
->                ; n = 65
->                ; m = sinOsc kr f 0 }
->            in pan2 (sinOsc ar (mWrp1 m n) 0) m e
->     ; o2 = let { f = U.iRand 5 9
->                ; d = U.iRand 5 9
->                ; s = envSine d (U.rand 0.1 0.2)
->                ; e = envGen kr 1 1 0 1 DoNothing s
->                ; n = U.iRand 69 72
->                ; m = sinOsc kr f 0 }
->            in pan2 (sinOsc ar (mWrp1 m n) 0) m e
->     ; o3 = let { f = U.iRand 5 9
->                ; d = U.iRand 9 12
->                ; s = envSine d (U.rand 0.1 0.2)
->                ; e = envGen kr 1 1 0 1 DoNothing s
->                ; n = U.iRand 69 72
->                ; m = sinOsc kr f 0
->                ; l = line kr 0 (U.iRand 1 5) d DoNothing }
->            in pan2 (blip ar (mWrp1 m (n + l)) (linLin m (-1) 1 1 2)) m e
->     ; o4 = let { f = U.iRand 5 18
->                ; d = U.iRand 12 15
->                ; s = envSine d (U.rand 0.1 0.2)
->                ; e = envGen kr 1 5e-2 0 1 DoNothing s
->                ; n = U.iRand 69 72
->                ; m = sinOsc kr f 0
->                ; l = line kr 0 (U.iRand 1 5) d RemoveSynth
->                ; fr = mWrpN m (n + l) (U.iRand 1 5) }
->            in pan2 (blip ar fr (linLin m (-1) 1 1 (U.iRand 2 24))) m e }
-> in audition (out 0 (o1 + o2 + o3 + o4))
diff --git a/Help/Graphs/voscil.lhs b/Help/Graphs/voscil.lhs
deleted file mode 100644
--- a/Help/Graphs/voscil.lhs
+++ /dev/null
@@ -1,30 +0,0 @@
-voscil (rd)
-
-> import Sound.SC3
-> import qualified Sound.SC3.UGen.Unsafe as U
-> import System.Random
-
-> let { rrand l r = getStdRandom (randomR (l, r))
->     ; lfn r = U.lfNoise0 kr r
->     ; b = 32
->     ; hb = (constant b - 1) / 2
->     ; bn = 8192 * 4
->     ; rt = 6
->     ; f = 600
->     ; s = let { v = vOsc ar (lfn rt * hb + hb) (f * 2) 0
->               ; o = let { bf = lfn rt * 40 + 600
->                         ; nh = lfn rt * 16 + 24 }
->                     in blip ar bf nh * (lfn rt * 0.1 + 0.1)
->               ; p = pan2 (v + o) (lfn rt) (lfn rt * 0.5 + 0.5)
->               ; w = vOsc ar (lfSaw kr (1 / rt) 0 * hb + hb) f 0
->               ; q = pan2 w (lfn rt) (lfn rt * 0.5 + 0.5) }
->           in p + q
->     ; run fd = let r_set i = 
->                        do { m <- rrand 2 512
->                           ; j <- sequence (replicate m (rrand 0 bn))
->                           ; k <- sequence (replicate m (rrand (-1) 1))
->                           ; async fd (b_alloc i bn 1)
->                           ; send fd (b_set i (zip j k)) }
->                in do { mapM_ r_set [0 .. (b - 1)]
->                      ; play fd (out 0 s) } }
-> in withSC3 run
diff --git a/Help/UGen/Analysis/amplitude.help.lhs b/Help/UGen/Analysis/amplitude.help.lhs
--- a/Help/UGen/Analysis/amplitude.help.lhs
+++ b/Help/UGen/Analysis/amplitude.help.lhs
@@ -1,6 +1,13 @@
-amplitude rate in attackTime releaseTime
+amplitude r i at rt
 
+    r - operating rate
+    i - input
+   at - attack time (0.01)
+   rt - release time (0.01)
+
 Amplitude follower. Tracks the peak amplitude of a signal.
+
+> import Sound.SC3
 
 > let { s = in' 1 AR numOutputBuses
 >     ; a = amplitude KR s 0.1 0.1 }
diff --git a/Help/UGen/Analysis/compander.help.lhs b/Help/UGen/Analysis/compander.help.lhs
--- a/Help/UGen/Analysis/compander.help.lhs
+++ b/Help/UGen/Analysis/compander.help.lhs
@@ -38,6 +38,8 @@
 
 Example signal to process.
 
+> import Sound.SC3
+
 > let { e = decay2 (impulse AR 8 0 * lfSaw KR 0.3 0 * 0.3) 0.001 0.3
 >     ; p = mix (pulse AR (mce [80, 81]) 0.3) }
 > in audition (out 0 (e * p))
diff --git a/Help/UGen/Analysis/runningSum.help.lhs b/Help/UGen/Analysis/runningSum.help.lhs
--- a/Help/UGen/Analysis/runningSum.help.lhs
+++ b/Help/UGen/Analysis/runningSum.help.lhs
@@ -7,5 +7,7 @@
 numsamp - How many samples to take the running sum over 
           (initialisation rate)
 
+> import Sound.SC3
+
 > let a = runningSum (in' 1 AR numOutputBuses) 40 * (1/40)
 > in audition (out 0 (sinOsc AR 440 0 * a))
diff --git a/Help/UGen/Analysis/slope.help.lhs b/Help/UGen/Analysis/slope.help.lhs
--- a/Help/UGen/Analysis/slope.help.lhs
+++ b/Help/UGen/Analysis/slope.help.lhs
@@ -10,6 +10,8 @@
 In the example below a is quadratic noise, b first derivative line
 segments, and c second derivative constant segments.
 
+> import Sound.SC3
+
 > do { a <- lfNoise2 KR 2
 >    ; let { s = 1/2
 >          ; b = slope a * s
diff --git a/Help/UGen/Analysis/zeroCrossing.help.lhs b/Help/UGen/Analysis/zeroCrossing.help.lhs
--- a/Help/UGen/Analysis/zeroCrossing.help.lhs
+++ b/Help/UGen/Analysis/zeroCrossing.help.lhs
@@ -9,5 +9,7 @@
 
 in - input signal.
 
+> import Sound.SC3
+
 > let a = sinOsc AR (sinOsc KR 1 0 * 600 + 700) 0 * 0.1
 > in audition (out 0 (mce [a, impulse AR (zeroCrossing a) 0 * 0.25]))
diff --git a/Help/UGen/Buffer/playBuf.help.lhs b/Help/UGen/Buffer/playBuf.help.lhs
--- a/Help/UGen/Buffer/playBuf.help.lhs
+++ b/Help/UGen/Buffer/playBuf.help.lhs
@@ -29,38 +29,40 @@
 
 Allocate buffer.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> async fd (b_allocRead 10 fileName 0 0))
 
 Play once only.
 
-> audition (out 0 (playBuf 1 10 (bufRateScale KR 10) 1 0 NoLoop))
+> audition (out 0 (playBuf 1 10 (bufRateScale KR 10) 1 0 NoLoop RemoveSynth))
 
 Play in infinite loop.
 
-> audition (out 0 (playBuf 1 10 (bufRateScale KR 10) 1 0 Loop))
+> audition (out 0 (playBuf 1 10 (bufRateScale KR 10) 1 0 Loop DoNothing))
 
 Trigger playback at each pulse.
 
 > let t = impulse KR 2 0
-> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10) t 0 NoLoop))
+> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10) t 0 NoLoop DoNothing))
 
 Trigger playback at each pulse (diminishing intervals).
 
 > let { f = xLine KR 0.1 100 10 RemoveSynth
 >     ; t = impulse KR f 0 }
-> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10) t 0 NoLoop))
+> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10) t 0 NoLoop DoNothing))
 
 Loop playback, accelerating pitch.
 
 > let r = xLine KR 0.1 100 60 RemoveSynth
-> in audition (out 0 (playBuf 1 10 r 1 0 Loop))
+> in audition (out 0 (playBuf 1 10 r 1 0 Loop DoNothing))
 
 Sine wave control of playback rate, negative rate plays backwards.
 
 > let { f = xLine KR 0.2 8 30 RemoveSynth
 >     ; r = fSinOsc KR f 0 * 3 + 0.6 }
-> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10 * r) 1 0 Loop))
+> in audition (out 0 (playBuf 1 10 (bufRateScale KR 10 * r) 1 0 Loop DoNothing))
 
 Release buffer.
 
diff --git a/Help/UGen/Buffer/vOsc.help.lhs b/Help/UGen/Buffer/vOsc.help.lhs
--- a/Help/UGen/Buffer/vOsc.help.lhs
+++ b/Help/UGen/Buffer/vOsc.help.lhs
@@ -23,13 +23,15 @@
 
 Allocate and fill tables 0 to 7.
 
+> import Sound.SC3
+
 > let { square a = a * a
->     ; harmonics i = let { n = square (i + 1)
->                         ; f j = square ((n - j) / n) }
->                     in map f [0 .. n - 1]
+>     ; harm i = let { n = square (i + 1)
+>                    ; f j = square ((n - j) / n) }
+>                in map f [0 .. n - 1]
 >     ; setup fd i = do { i' <- return (fromIntegral i)
 >                       ; async fd (b_alloc i 1024 1)
->                       ; send fd (b_gen i "sine1" (1 + 2 + 4 : harmonics i')) } }
+>                       ; send fd (b_gen i "sine1" (1 + 2 + 4 : harm i')) } }
 > in withSC3 (\fd -> mapM_ (setup fd) [0 .. 7])
 
 Oscillator at buffers 0 through 7, mouse selects buffer.
@@ -38,6 +40,9 @@
 > in audition (out 0 (vOsc AR x (mce [120, 121]) 0 * 0.3))
 
 Reallocate buffers while oscillator is running.
+
+> import Control.Monad
+> import System.Random
 
 > let { rrand l r = getStdRandom (randomR (l,r))
 >     ; rrandl n l r = replicateM n (rrand l r)
diff --git a/Help/UGen/FFT/partConv.help.lhs b/Help/UGen/FFT/partConv.help.lhs
--- a/Help/UGen/FFT/partConv.help.lhs
+++ b/Help/UGen/FFT/partConv.help.lhs
@@ -1,11 +1,11 @@
-partConv in fft_size ir_bufnum accum_bufnum
+partConv in fft_size ir_bufnum
 
 Partitioned convolution. Various additional buffers
 must be supplied.
 
 Mono impulse response only! If inputting multiple
-channels, you'll need independent accumulation
-buffers for each channel.
+channels, you'll need independent PartConvs, one
+for each channel.
 
 But the charm is: impulse response can be as large
 as you like (CPU load increases with IR
@@ -30,35 +30,28 @@
    irbufnum - Prepared buffer of spectra for each 
               partition of the impulse response
 
-accumbufnum - Accumulation buffer is a storage
-              space for spectral accumulation of
-              fft data from partitions; must be
-              same saize as irbuffer
-
 preparation; essentially, allocate an impulse
 response buffer, then follow some special buffer
 preparation steps below to set up the data the
-plugin needs. Different options are provided
-commented out for loading impulse responses from
-soundfiles.
+plugin needs. 
 
+> import Sound.SC3
+
 > let { fft_size = 2048
 >     ; ir_file = "/home/rohan/audio/church.ir.wav"
 >     ; ir_length = 82756
 >     ; accum_size = pc_calcAccumSize fft_size ir_length
 >     ; ir_td_b = 10 {- time domain -}
 >     ; ir_fd_b = 11 {- frequency domain -}
->     ; accum_b = 12  {- internal accumulator -}
->     ; target_b = 13 {- source signal -}
+>     ; target_b = 12 {- source signal -}
 >     ; target_file = "/home/rohan/audio/text.snd"
 >     ; c = constant
->     ; g = let { i = playBuf 1 (c target_b) 1 0 0 Loop
->               ; pc = partConv i (c fft_size) (c ir_fd_b) (c accum_b) }
->           in out 0 (pc / constant accum_size) }
+>     ; g = let { i = playBuf 1 (c target_b) 1 0 0 Loop DoNothing
+>               ; pc = partConv i (c fft_size) (c ir_fd_b) }
+>           in out 0 (pc * 0.1) }
 > in withSC3 (\fd -> do 
 >     { async fd (b_allocRead ir_td_b ir_file 0 ir_length)
 >     ; async fd (b_alloc ir_fd_b accum_size 1)
->     ; async fd (b_alloc accum_b accum_size 1)
 >     ; send fd (pc_preparePartConv ir_fd_b ir_td_b fft_size)
 >     ; async fd (b_allocRead target_b target_file 0 0)
 >     ; play fd g })
diff --git a/Help/UGen/FFT/pv_BinScramble.help.lhs b/Help/UGen/FFT/pv_BinScramble.help.lhs
--- a/Help/UGen/FFT/pv_BinScramble.help.lhs
+++ b/Help/UGen/FFT/pv_BinScramble.help.lhs
@@ -9,11 +9,13 @@
          distance of a bin from its original location in the spectrum.
 trig   - a trigger selects a new random ordering.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 1 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 1 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0.0 1.0 Linear 0.1
 >     ; y = mouseY KR 0.0 1.0 Linear 0.1 }
diff --git a/Help/UGen/FFT/pv_BinWipe.help.lhs b/Help/UGen/FFT/pv_BinWipe.help.lhs
--- a/Help/UGen/FFT/pv_BinWipe.help.lhs
+++ b/Help/UGen/FFT/pv_BinWipe.help.lhs
@@ -11,13 +11,15 @@
 if  wipe > 0 then it begins replacing with bins from inB from the bottom up.
 if  wipe < 0 then it begins replacing with bins from inB from the top down.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_alloc 11 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
 > do { n <- whiteNoise AR
->    ; let { b = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+>    ; let { b = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >          ; f = fft' 10 (n * 0.2)
 >          ; g = fft' 11 b
 >          ; x = mouseX KR 0.0 1.0 Linear 0.1
diff --git a/Help/UGen/FFT/pv_Diffuser.help.lhs b/Help/UGen/FFT/pv_Diffuser.help.lhs
--- a/Help/UGen/FFT/pv_Diffuser.help.lhs
+++ b/Help/UGen/FFT/pv_Diffuser.help.lhs
@@ -6,11 +6,13 @@
 buffer - fft buffer.
 trig   - a trigger selects a new set of random values.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 1 Linear 0.1
 >     ; h = pv_Diffuser f (x >* 0.5) }
diff --git a/Help/UGen/FFT/pv_LocalMax.help.lhs b/Help/UGen/FFT/pv_LocalMax.help.lhs
--- a/Help/UGen/FFT/pv_LocalMax.help.lhs
+++ b/Help/UGen/FFT/pv_LocalMax.help.lhs
@@ -6,11 +6,13 @@
 buffer    - fft buffer.
 threshold - magnitude threshold.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 100 Linear 0.1
 >     ; h = pv_LocalMax f x }
diff --git a/Help/UGen/FFT/pv_MagAbove.help.lhs b/Help/UGen/FFT/pv_MagAbove.help.lhs
--- a/Help/UGen/FFT/pv_MagAbove.help.lhs
+++ b/Help/UGen/FFT/pv_MagAbove.help.lhs
@@ -4,11 +4,13 @@
 above `threshold'.  This value is not normalized and is therefore
 dependant on the buffer size.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 100 Linear 0.1
 >     ; h = pv_MagAbove f x }
diff --git a/Help/UGen/FFT/pv_MagBelow.help.lhs b/Help/UGen/FFT/pv_MagBelow.help.lhs
--- a/Help/UGen/FFT/pv_MagBelow.help.lhs
+++ b/Help/UGen/FFT/pv_MagBelow.help.lhs
@@ -4,11 +4,13 @@
 below `threshold'.  This value is not normalized and is therefore
 dependant on the buffer size.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 100 Linear 0.1
 >     ; h = pv_MagBelow f x }
diff --git a/Help/UGen/FFT/pv_MagClip.help.lhs b/Help/UGen/FFT/pv_MagClip.help.lhs
--- a/Help/UGen/FFT/pv_MagClip.help.lhs
+++ b/Help/UGen/FFT/pv_MagClip.help.lhs
@@ -3,11 +3,13 @@
 Clip bins to a threshold.  Clips bin magnitudes to a maximum
 threshold.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 5 Linear 0.1
 >     ; h = pv_MagBelow f x }
diff --git a/Help/UGen/FFT/pv_MagFreeze.help.lhs b/Help/UGen/FFT/pv_MagFreeze.help.lhs
--- a/Help/UGen/FFT/pv_MagFreeze.help.lhs
+++ b/Help/UGen/FFT/pv_MagFreeze.help.lhs
@@ -3,11 +3,13 @@
 Clip bins to a threshold.  Clips bin magnitudes to a maximum
 threshold.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 2048 1)
 >                       ; async fd (b_allocRead 12 fileName 0 0) })
 
-> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop
+> let { a = playBuf 1 12 (bufRateScale KR 12) 0 0 Loop DoNothing
 >     ; f = fft' 10 a
 >     ; x = mouseX KR 0 1 Linear 0.1
 >     ; h = pv_MagFreeze f (x >* 0.5) }
diff --git a/Help/UGen/FFT/pvcollect.help.lhs b/Help/UGen/FFT/pvcollect.help.lhs
--- a/Help/UGen/FFT/pvcollect.help.lhs
+++ b/Help/UGen/FFT/pvcollect.help.lhs
@@ -19,6 +19,8 @@
 Note that this procedure can be relatively CPU-heavy, depending on
 how you use it.
 
+> import Sound.SC3
+
 > let fileName = "/home/rohan/audio/metal.wav"
 > in withSC3 (\fd -> do { async fd (b_alloc 10 1024 1)
 >                       ; async fd (b_allocRead 11 fileName 0 0) })
@@ -32,7 +34,7 @@
 >     ; bpf_sweep m p i = let { l = lfPar KR 0.1 0
 >                             ; e = abs (i - (linLin l (-1) 1 2 (nf / 20))) }
 >                         in ((e <* 10) * m, p)
->     ; sf = playBuf 1 11 (bufRateScale KR 11) 1 0 Loop
+>     ; sf = playBuf 1 11 (bufRateScale KR 11) 1 0 Loop DoNothing
 >     ; c1 = fft' 10 sf
 >     ; c2 = pvcollect c1 nf spectral_delay 0 250 0 }
 > in audition (out 0 (0.1 * ifft' c2))
diff --git a/Help/UGen/Filter/bpf.help.lhs b/Help/UGen/Filter/bpf.help.lhs
--- a/Help/UGen/Filter/bpf.help.lhs
+++ b/Help/UGen/Filter/bpf.help.lhs
@@ -6,6 +6,8 @@
 freq  - cutoff frequency in Hertz
 rq    - the reciprocal of Q, ie. bandwidth / cutoffFreq
 
+> import Sound.SC3
+
 > let f = fSinOsc KR (xLine KR 0.7 300 20 RemoveSynth) 0 * 3600 + 4000
 > in audition (out 0 (bpf (saw AR 200 * 0.5) f 0.3 ))
 
diff --git a/Help/UGen/Filter/delayA.help.lhs b/Help/UGen/Filter/delayA.help.lhs
deleted file mode 100644
--- a/Help/UGen/Filter/delayA.help.lhs
+++ /dev/null
@@ -1,1 +0,0 @@
-See delayN.
diff --git a/Help/UGen/Filter/delayC.help.lhs b/Help/UGen/Filter/delayC.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Filter/delayC.help.lhs
@@ -0,0 +1,1 @@
+See delayN.
diff --git a/Help/UGen/Filter/normalizer.help.lhs b/Help/UGen/Filter/normalizer.help.lhs
--- a/Help/UGen/Filter/normalizer.help.lhs
+++ b/Help/UGen/Filter/normalizer.help.lhs
@@ -1,4 +1,8 @@
-normalizer in level dur
+normalizer i l d
+
+    i - input signal
+    l - level
+    d - duration (0.01)
 
 Flattens dynamics.
 
diff --git a/Help/UGen/Filter/ramp.help.lhs b/Help/UGen/Filter/ramp.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Filter/ramp.help.lhs
@@ -0,0 +1,16 @@
+ramp in lagTime
+
+Linear lag.  This is similar to Lag but with a linear rather than
+exponential lag. This is useful for smoothing out control signals.
+
+       in - input signal
+  lagTime - 60 dB lag time in seconds
+
+Used to lag pitch
+
+> import Sound.SC3
+
+> let { o = lfPulse KR 4 0 0.5 * 50 + 400
+>     ; l = line KR 0 1 15 DoNothing
+>     ; f = ramp o l }
+> in audition (out 0 (sinOsc AR f 0 * 0.3))
diff --git a/Help/UGen/IO/in.help.lhs b/Help/UGen/IO/in.help.lhs
--- a/Help/UGen/IO/in.help.lhs
+++ b/Help/UGen/IO/in.help.lhs
@@ -1,7 +1,7 @@
 in' numChannels rate bus
 
 Read signal from an audio or control bus.
- 
+
 Patching input to output.
 
 > audition (out 0 (in' 2 AR numOutputBuses))
diff --git a/Help/UGen/IO/keyState.help.lhs b/Help/UGen/IO/keyState.help.lhs
--- a/Help/UGen/IO/keyState.help.lhs
+++ b/Help/UGen/IO/keyState.help.lhs
@@ -1,9 +1,11 @@
-keyState rate keyNum minVal maxVal lag
+keyState KR keyNum minVal maxVal lag
 
 Report the status of a particular key.  A key is either pressed, or
 not pressed.
 
 The keycode 38 is the A key on my keyboard.  Under X the xev(1)
 command is useful in determining your keyboard layout.
+
+> import Sound.SC3
 
 > audition (out 0 (sinOsc AR 800 0 * keyState KR 38 0 0.1 0.5))
diff --git a/Help/UGen/IO/localBuf.help.lhs b/Help/UGen/IO/localBuf.help.lhs
--- a/Help/UGen/IO/localBuf.help.lhs
+++ b/Help/UGen/IO/localBuf.help.lhs
@@ -1,22 +1,29 @@
-localBuf id nf nc m
+localBuf id nf nc
+maxLocalBufs n
+setBuf b xs o
+asLocalBuf id xs
 
+    id - node identifier
     nf - number of frames (default: 1)
     nc - number of channels for multiple channel buffers (default: 1)
-     m - the first LocalBuf in a SynthDef may define the maximum buffers
-         used (default 8)
+     n - maximum number of local buffers per graph
+     b - buffer identifier
+    xs - sequential values to store at buffer
 
 Allocate a buffer local to the synthesis graph.
 
 > import Sound.SC3
 
 > do { n <- whiteNoise AR
->    ; let { b = localBuf (uid 0) 2048 1 8
+>    ; let { m = maxLocalBufs 1
+>          ; b = mrg2 (localBuf (uid 0) 2048 1) m
 >          ; f = fft' b n
 >          ; c = pv_BrickWall f (sinOsc KR 0.1 0 * 0.75) }
 >      in audition (out 0 (ifft' c * 0.1)) }
 
 > do { n <- clone 2 (whiteNoise AR)
->    ; let { b = mce (map (\i -> localBuf (uid i) 2048 1 8) [0, 1])
+>    ; let { m = maxLocalBufs 2
+>          ; b = mrg2 (mce (map (\i -> localBuf (uid i) 2048 1) [0, 1])) m
 >          ; f = fft' b n
 >          ; c = pv_BrickWall f (sinOsc KR (mce2 0.1 0.11) 0 * 0.75) }
 >      in audition (out 0 (ifft' c * 0.1)) }
@@ -24,10 +31,11 @@
 not clearing the buffer accesses old data:
 slowly overwrite data with noise
 
-> let { b = localBuf (uid 0) 2048 2 8
+> let { m = maxLocalBufs 1
+>     ; b = mrg2 (localBuf (uid 0) 2048 2) m
 >     ; nf = bufFrames KR b
 >     ; x = mouseX KR 1 2 Linear 0.2
->     ; r = playBuf 2 b x 1 0 Loop * 0.1
+>     ; r = playBuf 2 b x 1 0 Loop DoNothing * 0.1
 >     ; wr ph i = bufWr b (linLin ph (-1) 1 0 nf) Loop i }
 > in do { n <- clone 2 (whiteNoise AR)
 >       ; ph <- lfNoise0 AR 530
@@ -40,7 +48,8 @@
 >    ; let { z = decay d 0.3 * n
 >          ; l = xLine KR 0.0001 0.01 20 DoNothing
 >          ; sr = sampleRate
->          ; b = mce (map (\i -> localBuf (uid i) sr 2 8) [0, 1]) }
+>          ; m = maxLocalBufs 2
+>          ; b = mrg2 (mce (map (\i -> localBuf (uid i) sr 2) [0, 1])) m }
 >      in audition (out 0 (bufCombC b z l 0.2)) }
 
 asLocalBuf combines localBuf and setBuf
@@ -61,9 +70,12 @@
 >    ; let { x = mouseX KR 0 15 Linear 0.1
 >          ; b = asLocalBuf (uid 0) [0, 2, 3.2, 5, 7, 9, 10]
 >          ; k = degreeToKey b x 12
->          ; f b = let { o = sinOsc AR (midiCPS (b + k + n * 0.04)) 0 * 0.1
->                      ; t = lfPulse AR (midiCPS (mce [48, 55])) 0.15 0.5
->                      ; d = rlpf t (midiCPS (sinOsc KR 0.1 0 * 10 + b)) 0.1 * 0.1
->                      ; m = o + d }
+>          ; mk_c bf = let { f0 = midiCPS (bf + k + n * 0.04)
+>                          ; o = sinOsc AR f0 0 * 0.1
+>                          ; f1 = midiCPS (mce [48, 55])
+>                          ; t = lfPulse AR f1 0.15 0.5
+>                          ; f2 = midiCPS (sinOsc KR 0.1 0 * 10 + bf)
+>                          ; d = rlpf t f2 0.1 * 0.1
+>                          ; m = o + d }
 >                  in combN m 0.31 0.31 2 + m }
->      in audition (out 0 ((f 48 + f 72) * 0.25)) }
+>      in audition (out 0 ((mk_c 48 + mk_c 72) * 0.25)) }
diff --git a/Help/UGen/IO/mouseButton.help.lhs b/Help/UGen/IO/mouseButton.help.lhs
--- a/Help/UGen/IO/mouseButton.help.lhs
+++ b/Help/UGen/IO/mouseButton.help.lhs
@@ -1,6 +1,8 @@
-mouseButton rate minval maxval lag
+mouseButton KR minval maxval lag
 
 Report the status of the first pointer button.  The button is either
 pressed, or not pressed.
+
+> import Sound.SC3
 
 > audition (out 0 (sinOsc AR 800 0 * mouseButton KR 0 0.1 0.1))
diff --git a/Help/UGen/IO/mouseX.help.lhs b/Help/UGen/IO/mouseX.help.lhs
--- a/Help/UGen/IO/mouseX.help.lhs
+++ b/Help/UGen/IO/mouseX.help.lhs
@@ -1,7 +1,9 @@
-mouseX rate minval maxval warp lag
+mouseX KR minval maxval warp lag
 
 Report mouse location on root window of the machine that the synthesis
 server is running on.
+
+> import Sound.SC3
 
 > let x = mouseX KR 40 10000 Exponential 0.2
 > in audition (out 0 (sinOsc AR x 0 * 0.1))
diff --git a/Help/UGen/IO/mouseY.help.lhs b/Help/UGen/IO/mouseY.help.lhs
--- a/Help/UGen/IO/mouseY.help.lhs
+++ b/Help/UGen/IO/mouseY.help.lhs
@@ -1,7 +1,9 @@
-mouseY rate minval maxval warp lag
+mouseY KR minval maxval warp lag
 
 Report mouse location on root window of the machine that the
 synthesis server is running on.
+
+> import Sound.SC3
 
 > let { freq = mouseX KR 20 2000 Exponential 0.1
 >     ; ampl = mouseY KR 0.01 0.1 Linear 0.1 }
diff --git a/Help/UGen/Math/abs.help.lhs b/Help/UGen/Math/abs.help.lhs
--- a/Help/UGen/Math/abs.help.lhs
+++ b/Help/UGen/Math/abs.help.lhs
@@ -2,4 +2,6 @@
 
 Absolute value.
 
+> import Sound.SC3
+
 > audition (out 0 (abs (syncSaw AR 100 440 * 0.1)))
diff --git a/Help/UGen/Math/absDif.help.lhs b/Help/UGen/Math/absDif.help.lhs
--- a/Help/UGen/Math/absDif.help.lhs
+++ b/Help/UGen/Math/absDif.help.lhs
@@ -3,4 +3,8 @@
 Calculates the value of (abs (- a b). Finding the magnitude of the
 difference of two values is a common operation.
 
-> audition (out 0 (fSinOsc AR 440 0 * absDif 0.2 (fSinOsc AR 2 0 * 0.5)))
+> import Sound.SC3
+
+> let { p = fSinOsc AR 440 0
+>     ; q = fSinOsc AR 2 0 * 0.5 }
+> in audition (out 0 (p * absDif 0.2 q))
diff --git a/Help/UGen/Math/add.help.lhs b/Help/UGen/Math/add.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/add.help.lhs
@@ -0,0 +1,11 @@
+a + b
+
+> import Sound.SC3
+
+> let o = fSinOsc AR 800 0
+> in do { n <- pinkNoise AR
+>       ; audition (out 0 ((o + n) * 0.1)) }
+
+DC offset.
+
+> audition (out 0 ((fSinOsc AR 440 0 * 0.1) + 0.5))
diff --git a/Help/UGen/Math/amClip.help.lhs b/Help/UGen/Math/amClip.help.lhs
--- a/Help/UGen/Math/amClip.help.lhs
+++ b/Help/UGen/Math/amClip.help.lhs
@@ -2,5 +2,7 @@
 
 0 when b <= 0, a*b when b > 0
 
+> import Sound.SC3
+
 > do { n <- whiteNoise AR
 >    ; audition (out 0 (amClip n (fSinOsc KR 1 0 * 0.2))) }
diff --git a/Help/UGen/Math/atan2.help.lhs b/Help/UGen/Math/atan2.help.lhs
--- a/Help/UGen/Math/atan2.help.lhs
+++ b/Help/UGen/Math/atan2.help.lhs
@@ -8,6 +8,8 @@
 azimuth, or direction angle, of the sound source.  Assume speakers
 at +/- 45 degrees and clip the direction to between those.
 
+> import Sound.SC3
+
 > let { x = 10
 >     ; y = lfSaw KR (1 / 6) 0 * 100
 >     ; d = hypot x y
diff --git a/Help/UGen/Math/clip2.help.lhs b/Help/UGen/Math/clip2.help.lhs
--- a/Help/UGen/Math/clip2.help.lhs
+++ b/Help/UGen/Math/clip2.help.lhs
@@ -2,6 +2,9 @@
 
 Bilateral clipping.  Clips a to +/- b
 
+> import Sound.SC3
+
 > audition (out 0 (clip2 (fSinOsc AR 400 0) 0.2))
 
-> audition (out 0 (clip2 (fSinOsc AR 400 0) (line KR 0 1 8 RemoveSynth)))
+> let l = line KR 0 1 8 RemoveSynth
+> in audition (out 0 (clip2 (fSinOsc AR 400 0) l))
diff --git a/Help/UGen/Math/dbAmp.help.lhs b/Help/UGen/Math/dbAmp.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/dbAmp.help.lhs
@@ -0,0 +1,9 @@
+dbAmp a
+
+Convert decibels to linear amplitude.
+
+> import Sound.SC3
+
+> let { a = dbAmp (line KR (-6) (-40) 10 RemoveSynth)
+>     ; o = fSinOsc AR 800 0 * a }
+> in audition (out 0 o)
diff --git a/Help/UGen/Math/difSqr.help.lhs b/Help/UGen/Math/difSqr.help.lhs
--- a/Help/UGen/Math/difSqr.help.lhs
+++ b/Help/UGen/Math/difSqr.help.lhs
@@ -4,6 +4,8 @@
 more efficient than using separate unit generators for each
 operation.
 
+> import Sound.SC3
+
 > let { a = fSinOsc AR 800 0
 >     ; b = fSinOsc AR (xLine KR 200 500 5 DoNothing) 0 }
 > in audition (out 0 (difSqr a b * 0.125))
diff --git a/Help/UGen/Math/eq.help.lhs b/Help/UGen/Math/eq.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/eq.help.lhs
@@ -0,0 +1,2 @@
+See gt (>)
+
diff --git a/Help/UGen/Math/excess.help.lhs b/Help/UGen/Math/excess.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/excess.help.lhs
@@ -0,0 +1,14 @@
+excess a b
+
+Clipping residual.  Returns the difference of the original signal and
+its clipped form: (a - clip2(a,b)).
+
+> import Sound.SC3
+
+> let { o = fSinOsc AR 1000 0
+>     ; l = line KR 0 1 8 DoNothing }
+> in audition (out 0 (excess o l))
+
+> let { o = fSinOsc AR 1000 0
+>     ; l = line KR 0 1 8 DoNothing }
+> in audition (out 0 (o - (clip2 o l)))
diff --git a/Help/UGen/Math/fdiv.help.lhs b/Help/UGen/Math/fdiv.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/fdiv.help.lhs
@@ -0,0 +1,11 @@
+a / b
+
+Division, written '/'.
+
+Division can be tricky with signals because of division by zero.
+
+> import Sound.SC3
+
+> let o = fSinOsc KR 10 0.5
+> in do { n <- pinkNoise AR
+>       ; audition (out 0 ((n * 0.1) / (o * 0.75))) }
diff --git a/Help/UGen/Math/fold2.help.lhs b/Help/UGen/Math/fold2.help.lhs
--- a/Help/UGen/Math/fold2.help.lhs
+++ b/Help/UGen/Math/fold2.help.lhs
@@ -2,4 +2,8 @@
 
 Bilateral folding.  Folds a to +/- b.
 
-> audition (out 0 (fold2 (fSinOsc AR 1000 0) (line KR 0 1 8 DoNothing)))
+> import Sound.SC3
+
+> let { o = fSinOsc AR 1000 0
+>     ; l = line KR 0 1 8 DoNothing }
+> in audition (out 0 (fold2 o l))
diff --git a/Help/UGen/Math/gt.help.lhs b/Help/UGen/Math/gt.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/gt.help.lhs
@@ -0,0 +1,25 @@
+a >* b
+a >=* b
+a <* b
+a <=* b
+a ==* b
+
+Greater than, written '>*'.  The star extensions are because the
+result of the operatros is not of type Bool, as is required by the
+signature for the class Ord.
+
+The resulting signal is 1.0 if a > b, otherwise it is 0.0. Similarly
+less than is <*, greater than or equal to is >=*, and so on.  
+
+These operators can be useful for triggering purposes, among other
+things.
+
+> import Sound.SC3
+
+> let { o = sinOsc KR 1 0
+>     ; t = [o >* 0, o >=* 0, o <* 0, o <=* 0, o ==* 0
+>           ,(o <* 0.001) * (o >* (-0.001))]
+>     ; f = [220, 330, 440, 550, 660, 770]
+>     ; p = envPerc 0.01 1
+>     ; e = envGen KR (mce t) 0.1 0 1 DoNothing p }
+> in audition (out 0 (mix (sinOsc AR (mce f) 0 * e)))
diff --git a/Help/UGen/Math/hypot.help.lhs b/Help/UGen/Math/hypot.help.lhs
--- a/Help/UGen/Math/hypot.help.lhs
+++ b/Help/UGen/Math/hypot.help.lhs
@@ -3,6 +3,8 @@
 Returns the square root of the sum of the squares of a and b. Or
 equivalently, the distance from the origin to the point (x, y).
 
+> import Sound.SC3
+
 > let { x = mouseX KR 0 0.1 Linear 0.1
 >     ; y = mouseY KR 0 0.1 Linear 0.1 }
 > in audition (out 0 (sinOsc AR 440 0 * hypot x y))
diff --git a/Help/UGen/Math/max.help.lhs b/Help/UGen/Math/max.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/max.help.lhs
@@ -0,0 +1,9 @@
+max a b
+
+Maximum.
+
+> import Sound.SC3
+
+> let { p = fSinOsc AR 500 0 * 0.25
+>     ; q = fSinOsc AR 0.5 0 }
+> in audition (out 0 (p `max` q))
diff --git a/Help/UGen/Math/mod.help.lhs b/Help/UGen/Math/mod.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/mod.help.lhs
@@ -0,0 +1,7 @@
+a `mod` b
+
+Modulo, written % in sclang.  outputs a modulo b.
+
+> import Sound.SC3
+
+> audition (out 0 (fSinOsc AR 100 4 `mod` 1))
diff --git a/Help/UGen/Math/mul.help.lhs b/Help/UGen/Math/mul.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/mul.help.lhs
@@ -0,0 +1,18 @@
+a * b
+
+Multiplication.
+
+> import Sound.SC3
+
+> audition (out 0 (sinOsc AR 440 0 * 0.5))
+
+Creates a beating effect (subaudio rate).
+
+> do { n <- pinkNoise AR
+>    ; audition (out 0 (fSinOsc kr 10 0 * n * 0.5)) }
+
+Ring modulation.
+
+> let { p = sinOsc AR (xLine KR 100 1001 10 DoNothing) 0
+>     ; q = syncSaw AR 100 200 }
+> in audition (out 0 (p * q * 0.25))
diff --git a/Help/UGen/Math/pow.help.lhs b/Help/UGen/Math/pow.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/pow.help.lhs
@@ -0,0 +1,20 @@
+a ** b
+
+Exponentiation.  When the signal is negative this function extends the
+usual definition of exponentiation and returns neg(neg(a) ** b). This
+allows exponentiation of negative signal values by noninteger
+exponents.
+
+> let a = fSinOsc AR 100 0 * 0.1
+> in audition (out 0 (mce2 a (a ** 10)))
+
+http://create.ucsb.edu/pipermail/sc-users/2006-December/029998.html
+
+> do { n0 <- lfNoise2 KR 8
+>    ; n1 <- lfNoise2 KR 3
+>    ; let { s = blip AR (n0 * 200 + 300) (n1 * 10 + 20)
+>          ; x = mouseX KR 1000 (sampleRate * 0.5) Exponential 0.1
+>          ; y = mouseY KR 1 24 Exponential 0.1
+>          ; d = latch s (impulse AR x 0)
+>          ; b = roundUp d (0.5 ** y) }
+>      in audition (out 0 (mce2 d b)) }
diff --git a/Help/UGen/Math/ring1.help.lhs b/Help/UGen/Math/ring1.help.lhs
--- a/Help/UGen/Math/ring1.help.lhs
+++ b/Help/UGen/Math/ring1.help.lhs
@@ -6,6 +6,8 @@
 
 See also Mul, Ring1, Ring2, Ring3, Ring4.
 
+> import Sound.SC3
+
 > let { a = fSinOsc AR 800 0
 >     ; b = fSinOsc AR (xLine KR 200 500 5 DoNothing) 0 }
 > in audition (out 0 (ring1 a b * 0.125))
diff --git a/Help/UGen/Math/roundUp.help.lhs b/Help/UGen/Math/roundUp.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Math/roundUp.help.lhs
@@ -0,0 +1,12 @@
+roundUp a b
+
+Rounds a up to the nearest multiple of b.
+
+> import Sound.SC3
+
+> let { x = mouseX KR 60 4000 Linear 0.1
+>     ; f = roundUp x 100 }
+> in audition (out 0 (sinOsc ar f 0 * 0.1))
+
+> let n = line KR 24 108 6 RemoveSynth
+> in audition (out 0 (saw AR (midiCPS (roundUp n 1)) * 0.2))
diff --git a/Help/UGen/Math/scaleNeg.help.lhs b/Help/UGen/Math/scaleNeg.help.lhs
--- a/Help/UGen/Math/scaleNeg.help.lhs
+++ b/Help/UGen/Math/scaleNeg.help.lhs
@@ -2,4 +2,8 @@
 
 Scale negative part of input wave.  a * b when a < 0, otherwise a.
 
-> audition (out 0 (scaleNeg (fSinOsc AR 500 0) (line AR 1 (-1) 4 RemoveSynth)))
+> import Sound.SC3
+
+> let { o = fSinOsc AR 1000 0
+>     ; l = line AR 1 (-1) 4 RemoveSynth }
+> in audition (out 0 (scaleNeg o l))
diff --git a/Help/UGen/Math/softClip.help.lhs b/Help/UGen/Math/softClip.help.lhs
--- a/Help/UGen/Math/softClip.help.lhs
+++ b/Help/UGen/Math/softClip.help.lhs
@@ -3,6 +3,8 @@
 Nonlinear distortion.  Distortion with a perfectly linear region
 from -0.5 to +0.5.
 
+> import Sound.SC3
+
 > let { e = xLine KR 0.1 10 10 DoNothing
 >     ; o = fSinOsc AR 500 0.0 }
 > in audition (out 0 (softClip (o * e) * 0.25))
diff --git a/Help/UGen/Math/sumSqr.help.lhs b/Help/UGen/Math/sumSqr.help.lhs
--- a/Help/UGen/Math/sumSqr.help.lhs
+++ b/Help/UGen/Math/sumSqr.help.lhs
@@ -3,6 +3,8 @@
 Return the value of (a*a) + (b*b). This is more efficient than
 using separate unit generators for each operation.
 
+> import Sound.SC3
+
 > let { a = fSinOsc AR 800 0
 >     ; b = fSinOsc AR (xLine KR 200 500 5 DoNothing) 0 }
 > in audition (out 0 (sumSqr a b * 0.125))
diff --git a/Help/UGen/Math/thresh.help.lhs b/Help/UGen/Math/thresh.help.lhs
--- a/Help/UGen/Math/thresh.help.lhs
+++ b/Help/UGen/Math/thresh.help.lhs
@@ -2,5 +2,7 @@
 
 Signal thresholding.  0 when a < b, otherwise a.
 
+> import Sound.SC3
+
 > do { n <- lfNoise0 AR 50
 >    ; audition (out 0 (thresh (n * 0.5) 0.45)) }
diff --git a/Help/UGen/Oscillator/blip.help.lhs b/Help/UGen/Oscillator/blip.help.lhs
--- a/Help/UGen/Oscillator/blip.help.lhs
+++ b/Help/UGen/Oscillator/blip.help.lhs
@@ -1,4 +1,4 @@
-blip rate freq numHarm
+blip AR freq numHarm
 
 Band Limited ImPulse generator. All harmonics have equal amplitude.
 
@@ -16,12 +16,16 @@
 The number of harmonics may be lowered internally if it would cause
 aliasing.
 
+> import Sound.SC3
+
 > audition (out 0 (blip AR 440 200 * 0.1))
 
 Modulate frequency
 
-> audition (out 0 (blip AR (xLine KR 20000 200 6 RemoveSynth) 100 * 0.1))
+> let f = xLine KR 20000 200 6 RemoveSynth
+> in audition (out 0 (blip AR f 100 * 0.1))
 
 Modulate number of harmonics.
 
-> audition (out 0 (blip AR 200 (line KR 1 100 20 RemoveSynth) * 0.2))
+> let nh = line KR 1 100 20 RemoveSynth
+> in audition (out 0 (blip AR 200 nh * 0.2))
diff --git a/Help/UGen/Oscillator/formant.help.lhs b/Help/UGen/Oscillator/formant.help.lhs
--- a/Help/UGen/Oscillator/formant.help.lhs
+++ b/Help/UGen/Oscillator/formant.help.lhs
@@ -1,17 +1,22 @@
-formant rate fundFreq formFreq bwFreq
+formant AR fundFreq formFreq bwFreq
 
 Formant oscillator. Generates a set of harmonics around a formant
 frequency at a given fundamental frequency.
 
 Modulate fundamental frequency, formant frequency stays constant.
 
-> audition (out 0 (formant AR (xLine KR 400 1000 8 RemoveSynth) 2000 800 * 0.125))
+> import Sound.SC3
 
+> let f = xLine KR 400 1000 8 RemoveSynth
+> in audition (out 0 (formant AR f 2000 800 * 0.125))
+
 Modulate formant frequency, fundamental frequency stays constant.
 
-> let f = mce [200, 300, 400, 500]
-> in audition (out 0 (formant AR f (xLine KR 400 4000 8 RemoveSynth) 200 * 0.125))
+> let { f = mce [200, 300, 400, 500]
+>     ; ff = xLine KR 400 4000 8 RemoveSynth }
+> in audition (out 0 (formant AR f ff 200 * 0.125))
 
 Modulate width frequency, other frequencies stay constant.
 
-> audition (out 0 (formant AR 400 2000 (xLine KR 800 8000 8 RemoveSynth) * 0.1))
+> let bw = xLine KR 800 8000 8 RemoveSynth
+> in audition (out 0 (formant AR 400 2000 bw * 0.1))
diff --git a/Help/UGen/Oscillator/lfSaw.help.lhs b/Help/UGen/Oscillator/lfSaw.help.lhs
--- a/Help/UGen/Oscillator/lfSaw.help.lhs
+++ b/Help/UGen/Oscillator/lfSaw.help.lhs
@@ -11,3 +11,9 @@
 Used as both Oscillator and LFO.
 
 > audition (out 0 (lfSaw AR (lfSaw KR 4 0 * 400 + 400) 0 * 0.1))
+
+Output range is bi-polar.
+
+> let { f = mce [linLin (lfSaw KR 0.5 0) (-1) 1 200 1600, 200, 1600]
+>     ; a = mce [0.1, 0.05, 0.05] }
+> in audition (out 0 (mix (sinOsc AR f 0 * a)))
diff --git a/Help/UGen/Oscillator/pulse.help.lhs b/Help/UGen/Oscillator/pulse.help.lhs
--- a/Help/UGen/Oscillator/pulse.help.lhs
+++ b/Help/UGen/Oscillator/pulse.help.lhs
@@ -1,8 +1,14 @@
-pulse rate freq width
+pulse AR f w
 
+   r - operating rate
+   f - frequency (hz)
+   w - width (0.5)
+
 Bandlimited pulse wave generator.
 
 Modulate frequency
+
+> import Sound.SC3
 
 > let f = xLine KR 40 4000 6 RemoveSynth
 > in audition (out 0 (pulse AR f 0.1 * 0.1))
diff --git a/Help/UGen/Oscillator/saw.help.lhs b/Help/UGen/Oscillator/saw.help.lhs
--- a/Help/UGen/Oscillator/saw.help.lhs
+++ b/Help/UGen/Oscillator/saw.help.lhs
@@ -1,6 +1,8 @@
-saw rate freq
+saw AR freq
 
 Band limited sawtooth wave generator.
+
+> import Sound.SC3
 
 > audition (out 0 (saw AR (xLine KR 40 4000 6 RemoveSynth) * 0.1))
 
diff --git a/Help/UGen/Oscillator/varSaw.help.lhs b/Help/UGen/Oscillator/varSaw.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/UGen/Oscillator/varSaw.help.lhs
@@ -0,0 +1,13 @@
+varSaw rate freq iphasewidth
+
+Variable duty saw
+
+freq   - frequency in Hertz
+iphase - initial phase offset in cycles ( 0..1 )
+width  - duty cycle from zero to one.
+
+> import Sound.SC3
+
+> let { f = lfPulse KR (mce2 3 3.03) 0 0.3 * 200 + 200
+>     ; w = linLin (lfTri KR 1 0) (-1) 1 0 1 }
+> in audition (out 0 (varSaw AR f 0 w * 0.1))
diff --git a/README b/README
--- a/README
+++ b/README
@@ -3,6 +3,9 @@
 hsc3 provides Sound.SC3, a Haskell module that facilitates using
 Haskell as a client to the SuperCollider synthesis server.  
 
+For installation and configuration information please consult the
+tutorial file at Help/Tutorial.
+
 The hsc3 interaction environment is written for GNU Emacs.
 
   http://slavepianos.org/rd/f/207949/
@@ -10,9 +13,10 @@
   http://audiosynth.com/
   http://gnu.org/software/emacs/
 
-(c) rohan drape and others, 2006-2008
+(c) rohan drape and others, 2006-2009
     gpl, http://gnu.org/copyleft/
     with contributions by henning thielemann
                         & stefan kersten
                         & alex mclean
+                        & brent yorgey
     see darcs history for details
diff --git a/Sound/SC3.hs b/Sound/SC3.hs
--- a/Sound/SC3.hs
+++ b/Sound/SC3.hs
@@ -1,6 +1,24 @@
-module Sound.SC3 (module Sound.SC3.UGen,
+module Sound.SC3 (
+                  -- $help
+
+                  module Sound.SC3.UGen,
                   module Sound.SC3.Server) where
 
 import Sound.SC3.UGen
 import Sound.SC3.Server
+
+-- $help
+-- Once the hsc3 library has been installed, you will find help files
+-- installed in @$PREFIX\/share\/hsc3-VERSION\/Help\/@.
+--
+-- For installation and configuration information please consult the
+-- tutorial file at @Help\/Tutorial\/Tutorial.lhs@.
+--
+-- For general information on supercollider and the overall design of
+-- the hsc3 bindings, see @Help\/hsc3.help.lhs@.
+--
+-- For documentation and examples for unit generators, see
+-- @Help\/UGen\/@.  Note that the Haddock documentation for many unit
+-- generators is incomplete; see the appropriate file in
+-- @Help\/UGen\/@ for complete documentation.
 
diff --git a/Sound/SC3/Server/Command.hs b/Sound/SC3/Server/Command.hs
--- a/Sound/SC3/Server/Command.hs
+++ b/Sound/SC3/Server/Command.hs
@@ -22,17 +22,17 @@
 
 -- | Remove definition once all nodes using it have ended.
 d_free :: [String] -> OSC
-d_free n = Message "/d_free" (map String n)
+d_free = Message "/d_free" . map String
 
 -- * Node commands
 
 -- | Place a node after another.
 n_after :: [(Int, Int)] -> OSC
-n_after l = Message "/n_after" (mk_duples Int Int l)
+n_after = Message "/n_after" . mk_duples Int Int
 
 -- | Place a node before another.
 n_before :: [(Int, Int)] -> OSC
-n_before l = Message "/n_before" (mk_duples Int Int l)
+n_before = Message "/n_before" . mk_duples Int Int
 
 -- | Fill ranges of a node's control values.
 n_fill :: Int -> [(String, Int, Double)] -> OSC
@@ -40,7 +40,7 @@
 
 -- | Delete a node.
 n_free :: [Int] -> OSC
-n_free nid = Message "/n_free" (map Int nid)
+n_free = Message "/n_free" . map Int
 
 -- | Map a node's controls to read from a bus.
 n_map :: Int -> [(String, Int)] -> OSC
@@ -52,11 +52,11 @@
 
 -- | Get info about a node.
 n_query :: [Int] -> OSC
-n_query nid = Message "/n_query" (map Int nid)
+n_query = Message "/n_query" . map Int
 
 -- | Turn node on or off.
 n_run :: [(Int, Bool)] -> OSC
-n_run l = Message "/n_run" (mk_duples Int (Int . fromEnum) l)
+n_run = Message "/n_run" . mk_duples Int (Int . fromEnum)
 
 -- | Set a node's control values.
 n_set :: Int -> [(String, Double)] -> OSC
@@ -65,11 +65,11 @@
 -- | Set ranges of a node's control values.
 n_setn :: Int -> [(String, [Double])] -> OSC
 n_setn nid l = Message "/n_setn" (Int nid : concatMap f l)
-    where f (s,d) = String s : Int (length d) : (map Float d)
+    where f (s,d) = String s : Int (length d) : map Float d
 
 -- | Trace a node.
 n_trace :: [Int] -> OSC
-n_trace nid = Message "/n_trace" (map Int nid)
+n_trace = Message "/n_trace" . map Int
 
 -- * Synthesis node commands
 
@@ -99,29 +99,29 @@
 
 -- | Auto-reassign synth's ID to a reserved value.
 s_noid :: [Int] -> OSC
-s_noid nid = Message "/s_noid" (map Int nid)
+s_noid = Message "/s_noid" . map Int
 
 -- * Group node commands
 
 -- | Free all synths in this group and all its sub-groups.
 g_deepFree :: [Int] -> OSC
-g_deepFree nid = Message "/g_deepFree" (map Int nid)
+g_deepFree = Message "/g_deepFree" . map Int
 
 -- | Delete all nodes in a group.
 g_freeAll :: [Int] -> OSC
-g_freeAll nid = Message "/g_freeAll" (map Int nid)
+g_freeAll = Message "/g_freeAll" . map Int
 
 -- | Add node to head of group.
 g_head :: [(Int, Int)] -> OSC
-g_head l = Message "/g_head" (mk_duples Int Int l)
+g_head = Message "/g_head" . mk_duples Int Int
 
 -- | Create a new group.
 g_new :: [(Int, AddAction, Int)] -> OSC
-g_new l = Message "/g_new" (mk_triples Int (Int . fromEnum) Int l)
+g_new = Message "/g_new" . mk_triples Int (Int . fromEnum) Int
 
 -- | Add node to tail of group.
 g_tail :: [(Int, Int)] -> OSC
-g_tail l = Message "/g_tail" (mk_duples Int Int l)
+g_tail = Message "/g_tail" . mk_duples Int Int
 
 -- * Unit Generator commands
 
@@ -165,7 +165,7 @@
 
 -- | Request \/b_info messages.
 b_query :: [Int] -> OSC
-b_query nid = Message "/b_query" (map Int nid)
+b_query = Message "/b_query" . map Int
 
 -- | Read sound file data into an existing buffer.
 b_read :: Int -> String -> Int -> Int -> Int -> Int -> OSC
@@ -192,19 +192,19 @@
 
 -- |  Fill ranges of bus values.
 c_fill :: [(Int, Int, Double)] -> OSC
-c_fill l = Message "/c_fill" (mk_triples Int Int Float l)
+c_fill = Message "/c_fill" . mk_triples Int Int Float
 
 -- | Get bus values.
 c_get :: [Int] -> OSC
-c_get nid = Message "/c_get" (map Int nid)
+c_get = Message "/c_get" . map Int
 
 -- | Get ranges of bus values.
 c_getn :: [(Int, Int)] -> OSC
-c_getn l = Message "/c_getn" (mk_duples Int Int l)
+c_getn = Message "/c_getn" . mk_duples Int Int
 
 -- | Set bus values.
 c_set :: [(Int, Double)] -> OSC
-c_set l = Message "/c_set" (mk_duples Int Float l)
+c_set = Message "/c_set" . mk_duples Int Float
 
 -- | Set ranges of bus values.
 c_setn :: [(Int, [Double])] -> OSC
diff --git a/Sound/SC3/Server/NRT.hs b/Sound/SC3/Server/NRT.hs
--- a/Sound/SC3/Server/NRT.hs
+++ b/Sound/SC3/Server/NRT.hs
@@ -15,12 +15,12 @@
 
 -- | Encode a list of OSC bundles as an NRT score.
 encodeNRT :: [OSC] -> B.ByteString
-encodeNRT s = B.concat (map oscWithSize s)
+encodeNRT = B.concat . map oscWithSize
 
 -- | Write a list of OSC bundles as an NRT score.
 writeNRT :: FilePath -> [OSC] -> IO ()
-writeNRT fn s = B.writeFile fn (encodeNRT s)
+writeNRT fn = B.writeFile fn . encodeNRT
 
 -- | Write a list of OSC bundles as an NRT score to a file handle.
 putNRT :: Handle -> [OSC] -> IO ()
-putNRT h s = B.hPut h (encodeNRT s)
+putNRT h = B.hPut h . encodeNRT
diff --git a/Sound/SC3/Server/Status.hs b/Sound/SC3/Server/Status.hs
--- a/Sound/SC3/Server/Status.hs
+++ b/Sound/SC3/Server/Status.hs
@@ -9,15 +9,15 @@
 
 -- | Collect server status information.
 serverStatus :: Transport t => t -> IO [String]
-serverStatus fd = liftM statusFormat (serverStatusData fd)
+serverStatus = liftM statusFormat . serverStatusData
 
 -- | Read nominal sample rate of server.
 serverSampleRateNominal :: (Transport t) => t -> IO Double
-serverSampleRateNominal fd = liftM (extractDouble . (!! 7)) (serverStatusData fd)
+serverSampleRateNominal = liftM (extractDouble . (!! 7)) . serverStatusData
 
 -- | Read actual sample rate of server.
 serverSampleRateActual :: (Transport t) => t -> IO Double
-serverSampleRateActual fd = liftM (extractDouble . (!! 8)) (serverStatusData fd)
+serverSampleRateActual = liftM (extractDouble . (!! 8)) . serverStatusData
 
 extractDouble :: Datum -> Double
 extractDouble (Float f) = f
diff --git a/Sound/SC3/Server/Synthdef.hs b/Sound/SC3/Server/Synthdef.hs
--- a/Sound/SC3/Server/Synthdef.hs
+++ b/Sound/SC3/Server/Synthdef.hs
@@ -1,7 +1,7 @@
 -- | The unit-generator graph structure implemented by the
 --   SuperCollider synthesis server.
 module Sound.SC3.Server.Synthdef ( Node(..), FromPort(..), Graph(..)
-                                  , synth, synthdef ) where
+                                 , synth, synthdef, synthstat ) where
 
 import qualified Data.ByteString.Lazy as B
 import qualified Data.Char as C
@@ -39,7 +39,7 @@
                   , node_u_outputs :: [Output]
                   , node_u_special :: Special
                   , node_u_ugenid :: Maybe UGenId }
-          | NodeP { node_id :: NodeId 
+          | NodeP { node_id :: NodeId
                   , node_p_node :: Node
                   , node_p_index :: PortIndex }
             deriving (Eq, Show)
@@ -55,15 +55,31 @@
 synth :: UGen -> Graph
 synth u = let (_, g) = mk_node (prepare_root u) empty_graph
               (Graph _ cs ks us) = g
-              us' = if null ks 
+              us' = if null ks
                     then reverse us
-                    else implicit (length ks) : reverse us
+                    else implicit ks : reverse us
           in Graph (-1) cs ks us'
 
 -- | Transform a unit generator into bytecode.
 synthdef :: String -> UGen -> [Word8]
-synthdef s u = B.unpack (encode_graphdef s (synth u))
+synthdef s = B.unpack . encode_graphdef s . synth
 
+-- | Simple statistical analysis of a unit generator graph.
+synthstat :: UGen -> String
+synthstat u =
+    let s = synth u
+        cs = constants s
+        ks = controls s
+        us = ugens s
+        f g = let h (x:xs) = (x, length (x:xs))
+                  h [] = undefined
+              in show . map h . group . sort . map g
+    in unlines ["number of constants       : " ++ show (length cs)
+               ,"number of controls        : " ++ show (length ks)
+               ,"control rates             : " ++ f node_k_rate ks
+               ,"number of unit generators : " ++ show (length us)
+               ,"unit generator rates      : " ++ f node_u_rate us]
+
 as_from_port :: Node -> FromPort
 as_from_port (NodeC n _) = C n
 as_from_port (NodeK n _ _ _) = K n
@@ -147,7 +163,7 @@
                   in (NodeP z n p, g { nextId = z + 1 })
 
 mk_node :: UGen -> Graph -> (Node, Graph)
-mk_node u g 
+mk_node u g
     | isConstant u = mk_node_c u g
     | isControl u = mk_node_k u g
     | isUGen u = mk_node_u u g
@@ -163,7 +179,7 @@
 
 -- Generate maps from node identifiers to synthdef indexes.
 mk_maps :: Graph -> Maps
-mk_maps (Graph _ cs ks us) = 
+mk_maps (Graph _ cs ks us) =
     ( M.fromList (zip (map node_id cs) [0..])
     , M.fromList (zip (map node_id ks) [0..])
     , M.fromList (zip (map node_id us) [0..]) )
@@ -225,13 +241,16 @@
     where (Graph _ cs ks us) = g
           mm = mk_maps g
 
--- Construct implicit control unit generator node (k-rate only).
-implicit :: Int -> Node
-implicit n = NodeU (-1) KR "Control" [] (replicate n KR) (Special 0) Nothing
+-- Construct implicit control unit generator node (i|k-rate only).
+implicit :: [Node] -> Node
+implicit ks =
+    let n = length ks
+        r = if all (== IR) (map node_k_rate ks) then IR else KR
+    in NodeU (-1) r "Control" [] (replicate n r) (Special 0) Nothing
 
 -- Transform mce nodes to mrg nodes
 prepare_root :: UGen -> UGen
-prepare_root u 
+prepare_root u
     | isMCE u = mrg (mceProxies u)
     | isMRG u = MRG (prepare_root (mrgLeft u)) (prepare_root (mrgRight u))
     | otherwise = u
diff --git a/Sound/SC3/UGen/Buffer.hs b/Sound/SC3/UGen/Buffer.hs
--- a/Sound/SC3/UGen/Buffer.hs
+++ b/Sound/SC3/UGen/Buffer.hs
@@ -108,9 +108,13 @@
 osc :: Rate -> UGen -> UGen -> UGen -> UGen
 osc r bufnum freq phase = mkOsc r "Osc" [bufnum, freq, phase] 1
 
+-- | Wavetable oscillator.
+oscN :: Rate -> UGen -> UGen -> UGen -> UGen
+oscN r bufnum freq phase = mkOsc r "OscN" [bufnum, freq, phase] 1
+
 -- | Buffer playback.
-playBuf :: Int -> UGen -> UGen -> UGen -> UGen -> Loop -> UGen
-playBuf n b r t s l = mkOsc AR "PlayBuf" [b, r, t, s, from_loop l] n
+playBuf :: Int -> UGen -> UGen -> UGen -> UGen -> Loop -> DoneAction -> UGen
+playBuf n b r t s l a = mkOsc AR "PlayBuf" [b, r, t, s, from_loop l, from_done_action a] n
 
 -- | Buffer recording.
 recordBuf :: UGen -> UGen -> UGen -> UGen -> UGen -> Loop -> UGen -> UGen -> UGen
@@ -131,10 +135,14 @@
 -- * Local buffers
 
 -- | Allocate a buffer local to the synth.
-localBuf :: UGenId -> UGen -> UGen -> UGen -> UGen
-localBuf z nf nc mx = mkOscId z IR "LocalBuf" [nc, nf, mx] 1
+localBuf :: UGenId -> UGen -> UGen -> UGen
+localBuf z nf nc = mkOscId z IR "LocalBuf" [nc, nf] 1
 -- note that nf & nc are swapped at actual ugen
 
+-- | Set the maximum number of local buffers in a synth.
+maxLocalBufs :: UGen -> UGen
+maxLocalBufs n = mkOsc IR "MaxLocalBufs" [n] 0
+
 -- | Set local buffer values.
 setBuf :: UGen -> [UGen] -> UGen -> UGen
 setBuf b xs o = mkOsc IR "SetBuf" ([b, o, fromIntegral (length xs)] ++ xs) 1
@@ -142,7 +150,8 @@
 -- | Generate a localBuf and use setBuf to initialise it.
 asLocalBuf :: UGenId -> [UGen] -> UGen
 asLocalBuf i xs =
-    let b = localBuf i (fromIntegral (length xs)) 1 8
+    let m = maxLocalBufs 8
+        b = mrg2 (localBuf i (fromIntegral (length xs)) 1) m
         s = setBuf b xs 0
     in mrg2 b s
 
diff --git a/Sound/SC3/UGen/Composite.hs b/Sound/SC3/UGen/Composite.hs
--- a/Sound/SC3/UGen/Composite.hs
+++ b/Sound/SC3/UGen/Composite.hs
@@ -1,6 +1,7 @@
 -- | Common unit generator graphs.
 module Sound.SC3.UGen.Composite where
 
+import Control.Monad
 import Sound.SC3.UGen.Buffer
 import Sound.SC3.UGen.Filter
 import Sound.SC3.UGen.Information
@@ -41,7 +42,7 @@
 
 -- | Monadic variant on mixFill.
 mixFillM :: (Monad m) => Int -> (Int -> m UGen) -> m UGen
-mixFillM n f = mapM f [0 .. n - 1] >>= return . sum
+mixFillM n f = liftM sum (mapM f [0 .. n - 1])
 
 -- | PM oscillator.
 pmOsc :: Rate -> UGen -> UGen -> UGen -> UGen -> UGen
@@ -56,7 +57,7 @@
 
 -- | Pan a set of channels across the stereo field.
 splay :: UGen -> UGen -> UGen -> UGen -> UGen
-splay i s l c = mix (pan2 i (mce p * s + c) 1) * l * (sqrt (1 / n))
+splay i s l c = mix (pan2 i (mce p * s + c) 1) * l * sqrt (1 / n)
     where n = fromIntegral (mceDegree i)
           m = n - 1
           p = map ( (+ (-1.0)) . (* (2 / m)) ) [0 .. m]
diff --git a/Sound/SC3/UGen/Envelope/Construct.hs b/Sound/SC3/UGen/Envelope/Construct.hs
--- a/Sound/SC3/UGen/Envelope/Construct.hs
+++ b/Sound/SC3/UGen/Envelope/Construct.hs
@@ -18,7 +18,7 @@
 -- | Co-ordinate based static envelope generator.
 envCoord :: [(UGen, UGen)] -> UGen -> UGen -> EnvCurve -> [UGen]
 envCoord bp dur amp c = env l t (repeat c) (-1) (-1)
-    where l = map (* amp) (map snd bp)
+    where l = map ((* amp) . snd) bp
           t = map (* dur) (d_dx (map fst bp))
 
 {- | Trapezoidal envelope generator.  The arguments are: 1. @shape@
diff --git a/Sound/SC3/UGen/External/ATS.hs b/Sound/SC3/UGen/External/ATS.hs
--- a/Sound/SC3/UGen/External/ATS.hs
+++ b/Sound/SC3/UGen/External/ATS.hs
@@ -56,19 +56,19 @@
 atsSC3 (ATS h d) = 
     let f = fromIntegral
         td = transpose d
-    in ( f (atsFileType h) :
-         f (atsNPartials h) :
-         f (atsNFrames h) :
-         f (atsWindowSize h) :
-         concatMap (td !!) (atsSC3Indices h) )
+    in f (atsFileType h) :
+       f (atsNPartials h) :
+       f (atsNFrames h) :
+       f (atsWindowSize h) :
+       concatMap (td !!) (atsSC3Indices h)
 
 -- be
 read_f64 :: Handle -> IO Double
-read_f64 h = B.hGet h 8 >>= return . decode_f64
+read_f64 h = liftM decode_f64 (B.hGet h 8)
 
 -- le
 read_f64LE :: Handle -> IO Double
-read_f64LE h = B.hGet h 8 >>= return . decode_f64 . B.reverse
+read_f64LE h = liftM (decode_f64 . B.reverse) (B.hGet h 8)
 
 -- Determine endianess and hence reader.
 get_reader :: B.ByteString -> (Handle -> IO Double)
diff --git a/Sound/SC3/UGen/External/LPC.hs b/Sound/SC3/UGen/External/LPC.hs
--- a/Sound/SC3/UGen/External/LPC.hs
+++ b/Sound/SC3/UGen/External/LPC.hs
@@ -55,8 +55,8 @@
                    in np : nf : fs : concat (transpose d)
 
 read_i32 :: Handle -> IO Int
-read_i32 h = B.hGet h 4 >>= return . decode_i32
+read_i32 h = liftM decode_i32 (B.hGet h 4)
 
 read_f32 :: Handle -> IO Double
-read_f32 h = B.hGet h 4 >>= return . decode_f32
+read_f32 h = liftM decode_f32 (B.hGet h 4)
 
diff --git a/Sound/SC3/UGen/FFT.hs b/Sound/SC3/UGen/FFT.hs
--- a/Sound/SC3/UGen/FFT.hs
+++ b/Sound/SC3/UGen/FFT.hs
@@ -35,7 +35,7 @@
 -- | Format magnitude and phase data data as required for packFFT.
 packFFTSpec :: [UGen] -> [UGen] -> UGen
 packFFTSpec m p = mce (interleave m p)
-    where interleave x y = concat (zipWith (\a b -> [a,b]) x y)
+    where interleave x = concat . zipWith (\a b -> [a,b]) x
 
 pvcollect :: UGen -> UGen -> (UGen -> UGen -> UGen -> (UGen, UGen)) -> UGen -> UGen -> UGen -> UGen
 pvcollect c nf f from to z = packFFT c nf from to z mp
@@ -43,7 +43,7 @@
         p = unpackFFT c nf from to 1
         i = [from .. to]
         e = zipWith3 f m p i
-        mp = (uncurry packFFTSpec) (unzip e)
+        mp = uncurry packFFTSpec (unzip e)
 
 pv_Add :: UGen -> UGen -> UGen
 pv_Add ba bb = mkOsc KR "PV_Add" [ba,bb] 1
@@ -154,8 +154,8 @@
     b_gen b "PreparePartConv" (map fromIntegral [irb, fft_size])
 
 -- | Partitioned convolution.
-partConv :: UGen -> UGen -> UGen -> UGen -> UGen
-partConv i sz ib ab = mkOsc AR "PartConv" [i,sz,ib,ab] 1
+partConv :: UGen -> UGen -> UGen -> UGen
+partConv i sz ib = mkOsc AR "PartConv" [i, sz, ib] 1
 
 -- Local Variables:
 -- truncate-lines:t
diff --git a/Sound/SC3/UGen/Filter.hs b/Sound/SC3/UGen/Filter.hs
--- a/Sound/SC3/UGen/Filter.hs
+++ b/Sound/SC3/UGen/Filter.hs
@@ -2,6 +2,7 @@
 module Sound.SC3.UGen.Filter where
 
 import Data.List
+import Sound.SC3.UGen.Rate
 import Sound.SC3.UGen.UGen
 
 -- | Allpass filter (no interpolation)
@@ -134,7 +135,7 @@
 
 -- | Fixed resonator filter bank.
 klank :: UGen -> UGen -> UGen -> UGen -> UGen -> UGen
-klank i fs fp d s = mkFilterMCE "Klank" [i, fs, fp, d] s 1
+klank i fs fp d s = mkFilterMCER [AR] "Klank" [i, fs, fp, d] s 1
 
 -- | Format frequency, amplitude and decay time data as required for klank.
 klankSpec :: [UGen] -> [UGen] -> [UGen] -> UGen
@@ -235,6 +236,10 @@
 -- | Pass every nth trigger.
 pulseDivider :: UGen -> UGen -> UGen -> UGen
 pulseDivider t factor start = mkFilter "PulseDivider" [t, factor, start] 1
+
+-- | Linear lag.
+ramp :: UGen -> UGen -> UGen
+ramp i t = mkFilter "Ramp" [i, t] 1
 
 -- | Resonant highpass filter.
 rhpf :: UGen -> UGen -> UGen -> UGen
diff --git a/Sound/SC3/UGen/IO.hs b/Sound/SC3/UGen/IO.hs
--- a/Sound/SC3/UGen/IO.hs
+++ b/Sound/SC3/UGen/IO.hs
@@ -54,19 +54,19 @@
 
 -- | Report the status of a particular key.
 keyState :: Rate -> UGen -> UGen -> UGen -> UGen -> UGen
-keyState r key minVal maxVal lag = mkOsc r "KeyState" [key, minVal, maxVal, lag] 1
+keyState r key minVal maxVal lag = mkOscR [KR] r "KeyState" [key, minVal, maxVal, lag] 1
 
 -- | Report the status of the first pointer button.
 mouseButton :: Rate -> UGen -> UGen -> UGen -> UGen
-mouseButton r ll rl lag = mkOsc r "MouseButton" [ll, rl, lag] 1
+mouseButton r ll rl lag = mkOscR [KR] r "MouseButton" [ll, rl, lag] 1
 
 -- | Cursor UGen, X axis.
 mouseX :: Rate -> UGen -> UGen -> Warp -> UGen -> UGen
-mouseX r ll rl w lag = mkOsc r "MouseX" [ll, rl, from_warp w, lag] 1
+mouseX r ll rl w lag = mkOscR [KR] r "MouseX" [ll, rl, from_warp w, lag] 1
 
 -- | Cursor UGen, Y axis.
 mouseY :: Rate -> UGen -> UGen -> Warp -> UGen -> UGen
-mouseY r ll rl w lag = mkOsc r "MouseY" [ll, rl, from_warp w, lag] 1
+mouseY r ll rl w lag = mkOscR [KR] r "MouseY" [ll, rl, from_warp w, lag] 1
 
 -- | Control variant.
 trigControl :: Int -> Rate -> UGen
diff --git a/Sound/SC3/UGen/MachineListening.hs b/Sound/SC3/UGen/MachineListening.hs
--- a/Sound/SC3/UGen/MachineListening.hs
+++ b/Sound/SC3/UGen/MachineListening.hs
@@ -20,7 +20,7 @@
 
 -- | Translate onset type string to constant UGen value.
 onsetType :: String -> UGen
-onsetType s = fromIntegral (maybe 3 id (findIndex (== s) t))
+onsetType s = fromIntegral (fromMaybe 3 (findIndex (== s) t))
     where t = ["power", "magsum", "complex", "rcomplex", "phase", "wphase", "mkl"]
 
 -- | Onset detector.
diff --git a/Sound/SC3/UGen/Math.hs b/Sound/SC3/UGen/Math.hs
--- a/Sound/SC3/UGen/Math.hs
+++ b/Sound/SC3/UGen/Math.hs
@@ -42,7 +42,7 @@
 -- | Unary operator class.
 class (Floating a, Ord a) => UnaryOp a where
     ampDb :: a -> a
-    ampDb a = (log10 a) * 20
+    ampDb a = log10 a * 20
     asFloat :: a -> a
     asFloat = undefined
     asInt :: a -> a
@@ -66,9 +66,9 @@
     isNil :: a -> a
     isNil a = if a == 0.0 then 0.0 else 1.0
     log10 :: a -> a
-    log10 a = logBase 10 a
+    log10 = logBase 10
     log2 :: a -> a
-    log2 a = logBase 2 a
+    log2 = logBase 2
     midiCPS :: a -> a
     midiCPS a = 440.0 * (2.0 ** ((a - 69.0) * (1.0 / 12.0)))
     midiRatio :: a -> a
@@ -79,8 +79,10 @@
     notNil a = if a /= 0.0 then 0.0 else 1.0
     octCPS :: a -> a
     octCPS a = 440.0 * (2.0 ** (a - 4.75))
+    ramp_ :: a -> a
+    ramp_ _ = undefined
     ratioMIDI :: a -> a
-    ratioMIDI a = 12.0 * (log2 a)
+    ratioMIDI a = 12.0 * log2 a
     softClip :: a -> a
     softClip = undefined
     squared :: a -> a
@@ -111,6 +113,7 @@
     notE = mkUnaryOperator Not notE
     notNil = mkUnaryOperator NotNil notNil
     octCPS = mkUnaryOperator OctCPS octCPS
+    ramp_ = mkUnaryOperator Ramp ramp_
     ratioMIDI = mkUnaryOperator RatioMIDI ratioMIDI
     softClip = mkUnaryOperator SoftClip softClip
     squared = mkUnaryOperator Squared squared
diff --git a/Sound/SC3/UGen/Oscillator.hs b/Sound/SC3/UGen/Oscillator.hs
--- a/Sound/SC3/UGen/Oscillator.hs
+++ b/Sound/SC3/UGen/Oscillator.hs
@@ -7,11 +7,11 @@
 
 -- | Band Limited ImPulse generator.
 blip :: Rate -> UGen -> UGen -> UGen
-blip r freq nharm = mkOsc r "Blip" [freq, nharm] 1
+blip r freq nharm = mkOscR [AR] r "Blip" [freq, nharm] 1
 
 -- | Formant oscillator.
 formant :: Rate -> UGen -> UGen -> UGen -> UGen
-formant r f0 f bw = mkOsc r "Formant" [f0, f, bw] 1
+formant r f0 f bw = mkOscR [AR] r "Formant" [f0, f, bw] 1
 
 -- | Fast sine wave oscillator implemented using a ringing filter.
 fSinOsc :: Rate -> UGen -> UGen -> UGen
@@ -27,7 +27,9 @@
 
 -- | Bank of fixed oscillators.
 klang :: Rate -> UGen -> UGen -> UGen -> UGen
-klang r fs fo a = mkOscMCE r "Klang" [fs, fo] a 1
+klang r fs fo a
+    | r == AR = mkOscMCE r "Klang" [fs, fo] a 1
+    | otherwise = undefined
 
 -- | Format frequency, amplitude and phase data as required for klang.
 klangSpec :: [UGen] -> [UGen] -> [UGen] -> UGen
@@ -63,15 +65,15 @@
 
 -- | Pulse wave generator (band limited).
 pulse :: Rate -> UGen -> UGen -> UGen
-pulse r freq width = mkOsc r "Pulse" [freq, width] 1
+pulse r freq width = mkOscR [AR] r "Pulse" [freq, width] 1
 
 -- | Sawtooth oscillator (band limited).
 saw :: Rate -> UGen -> UGen
-saw r freq = mkOsc r "Saw" [freq] 1
+saw r freq = mkOscR [AR] r "Saw" [freq] 1
 
 -- | Silence.
 silent :: Int -> UGen
-silent nc = mkOsc AR "Silent" [] nc
+silent = mkOsc AR "Silent" []
 
 -- | Sine oscillator.
 sinOsc :: Rate -> UGen -> UGen -> UGen
diff --git a/Sound/SC3/UGen/Rate.hs b/Sound/SC3/UGen/Rate.hs
--- a/Sound/SC3/UGen/Rate.hs
+++ b/Sound/SC3/UGen/Rate.hs
@@ -3,12 +3,14 @@
                            , rateId
                            , ar, kr, ir, dr ) where
 
+import Data.Function
+
 -- | Operating rate of unit generator.
 data Rate = IR | KR | AR | DR 
-            deriving (Eq, Show, Enum)
+            deriving (Eq, Show, Enum, Bounded)
 
 instance Ord Rate where
-    compare a b = compare (rate_ord a) (rate_ord b)
+    compare = compare `on` rate_ord
 
 -- | Rate constructors (lower case aliases of upper case data
 --   constructors).
diff --git a/Sound/SC3/UGen/UGen.hs b/Sound/SC3/UGen/UGen.hs
--- a/Sound/SC3/UGen/UGen.hs
+++ b/Sound/SC3/UGen/UGen.hs
@@ -103,7 +103,7 @@
 
 -- | Clone a unit generator (mce . replicateM).
 clone :: (UId m) => Int -> m UGen -> m UGen
-clone n u = liftM mce (replicateM n u)
+clone n = liftM mce . replicateM n
 
 -- | Number of channels to expand to.
 mceDegree :: UGen -> Int
@@ -150,12 +150,12 @@
 -- | Output channels of UGen as a list.
 mceChannels :: UGen -> [UGen]
 mceChannels (MCE l) = l
-mceChannels (MRG x y) = (MRG r y) : rs where (r:rs) = mceChannels x
+mceChannels (MRG x y) = let (r:rs) = mceChannels x in MRG r y : rs 
 mceChannels u = [u]
 
 -- | Transpose rows and columns, ie. {{a,b},{c,d}} to {{a,c},{b,d}}.
 mceTranspose :: UGen -> UGen
-mceTranspose u = mce (map mce (transpose (map mceChannels (mceChannels u))))
+mceTranspose = mce . map mce . transpose . map mceChannels . mceChannels
 
 -- * Multiple root graphs
 
@@ -220,26 +220,34 @@
     | otherwise = mkOperator "UnaryOpUGen" [a] (fromEnum i)
 
 -- | Binary math constructor with constant optimization.
-mkBinaryOperator :: Binary -> (Double -> Double -> Double) -> UGen -> UGen -> UGen
+mkBinaryOperator :: Binary -> (Double -> Double -> Double) -> 
+                    UGen -> UGen -> UGen
 mkBinaryOperator i f a b 
     | isConstant a && isConstant b = let a' = constantValue a
                                          b' = constantValue b
                                      in constant (f a' b')
     | otherwise = mkOperator "BinaryOpUGen" [a, b] (fromEnum i)
 
-mk_osc :: Maybe UGenId -> Rate -> String -> [UGen] -> Int -> UGen
-mk_osc z r c i o = mkUGen r c i (replicate o r) (Special 0) z
+mk_osc :: [Rate] -> Maybe UGenId -> 
+          Rate -> String -> [UGen] -> Int -> UGen
+mk_osc rs z r c i o
+    | r `elem` rs = mkUGen r c i (replicate o r) (Special 0) z
+    | otherwise = error ("mk_osc: rate restricted: " ++ show (r, rs, c))
 
 -- | Oscillator constructor.
 mkOsc :: Rate -> String -> [UGen] -> Int -> UGen
-mkOsc = mk_osc Nothing
+mkOsc = mk_osc [minBound .. maxBound] Nothing
 
+-- | Oscillator constructor, rate restricted variant.
+mkOscR :: [Rate] -> Rate -> String -> [UGen] -> Int -> UGen
+mkOscR rs = mk_osc rs Nothing
+
 -- | Oscillator constructor, setting identifier.
 mkOscId :: UGenId -> Rate -> String -> [UGen] -> Int -> UGen
-mkOscId z = mk_osc (Just z)
+mkOscId = mk_osc [minBound .. maxBound] . Just
 
 mk_osc_mce :: Maybe UGenId -> Rate -> String -> [UGen] -> UGen -> Int -> UGen
-mk_osc_mce z r c i j o = mk_osc z r c (i ++ mceChannels j) o
+mk_osc_mce z r c i j = mk_osc [minBound .. maxBound] z r c (i ++ mceChannels j)
 
 -- | Variant oscillator constructor with MCE collapsing input.
 mkOscMCE :: Rate -> String -> [UGen] -> UGen -> Int -> UGen
@@ -247,20 +255,30 @@
 
 -- | Variant oscillator constructor with MCE collapsing input.
 mkOscMCEId :: UGenId -> Rate -> String -> [UGen] -> UGen -> Int -> UGen
-mkOscMCEId z = mk_osc_mce (Just z)
+mkOscMCEId = mk_osc_mce . Just
 
-mk_filter :: Maybe UGenId -> String -> [UGen] -> Int -> UGen
-mk_filter z c i o = mkUGen r c i o' (Special 0) z
-    where r = maximum (map rateOf i)
-          o'= replicate o r
+mk_filter :: [Rate] -> Maybe UGenId -> String -> [UGen] -> Int -> UGen
+mk_filter rs z c i o =
+    let r = maximum (map rateOf i)
+        o'= replicate o r
+    in if r `elem` rs
+       then mkUGen r c i o' (Special 0) z
+       else error ("mk_filter: rate restriceted: " ++ show (r, rs, c))
 
+all_rates :: [Rate]
+all_rates = [minBound .. maxBound]
+
 -- | Filter UGen constructor.
 mkFilter :: String -> [UGen] -> Int -> UGen
-mkFilter = mk_filter Nothing
+mkFilter = mk_filter all_rates Nothing
 
 -- | Filter UGen constructor.
+mkFilterR :: [Rate] -> String -> [UGen] -> Int -> UGen
+mkFilterR rs = mk_filter rs Nothing
+
+-- | Filter UGen constructor.
 mkFilterId :: UGenId -> String -> [UGen] -> Int -> UGen
-mkFilterId z = mk_filter (Just z)
+mkFilterId = mk_filter all_rates . Just
 
 -- | Variant filter with rate derived from keyed input.
 mkFilterKeyed :: String -> Int -> [UGen] -> Int -> UGen
@@ -268,16 +286,21 @@
     where r = rateOf (i !! k)
           o' = replicate o r
 
-mk_filter_mce :: Maybe UGenId -> String -> [UGen] -> UGen -> Int -> UGen
-mk_filter_mce z c i j o = mk_filter z c (i ++ mceChannels j) o
+mk_filter_mce :: [Rate] -> Maybe UGenId -> 
+                 String -> [UGen] -> UGen -> Int -> UGen
+mk_filter_mce rs z c i j = mk_filter rs z c (i ++ mceChannels j)
 
 -- | Variant filter constructor with MCE collapsing input.
+mkFilterMCER :: [Rate] -> String -> [UGen] -> UGen -> Int -> UGen
+mkFilterMCER rs = mk_filter_mce rs Nothing
+
+-- | Variant filter constructor with MCE collapsing input.
 mkFilterMCE :: String -> [UGen] -> UGen -> Int -> UGen
-mkFilterMCE = mk_filter_mce Nothing
+mkFilterMCE = mk_filter_mce all_rates Nothing
 
 -- | Variant filter constructor with MCE collapsing input.
 mkFilterMCEId :: UGenId -> String -> [UGen] -> UGen -> Int -> UGen
-mkFilterMCEId z = mk_filter_mce (Just z)
+mkFilterMCEId = mk_filter_mce all_rates . Just
 
 -- | Information unit generators are very specialized.
 mkInfo :: String -> UGen
@@ -352,7 +375,7 @@
 instance Enum UGen where
     succ u                = u + 1
     pred u                = u - 1
-    toEnum i              = constant i
+    toEnum                = constant
     fromEnum (Constant n) = truncate n
     fromEnum _            = error "cannot enumerate non-constant UGens"
     enumFrom              = iterate (+1)
@@ -366,4 +389,4 @@
     randomR (Constant l, Constant r) g = let (n, g') = randomR (l,r) g
                                          in (Constant n, g')
     randomR _ _ = error "randomR: non constant (l,r)"
-    random g = randomR (-1.0, 1.0) g
+    random = randomR (-1.0, 1.0)
diff --git a/Sound/SC3/UGen/UGen/Lift.hs b/Sound/SC3/UGen/UGen/Lift.hs
--- a/Sound/SC3/UGen/UGen/Lift.hs
+++ b/Sound/SC3/UGen/UGen/Lift.hs
@@ -2,7 +2,6 @@
 
 import Sound.SC3.UGen.UGen
 import Sound.SC3.UGen.UId
-import System.IO.Unsafe
 
 -- | Lift base UGen to monadic form.
 liftU :: (UId m) => (UGenId -> a -> UGen) -> (a -> m UGen)
@@ -23,19 +22,3 @@
 liftU4 :: (UId m) => (UGenId -> a -> b -> c -> d -> UGen) -> (a -> b -> c -> d -> m UGen)
 liftU4 f a b c d = do n <- generateUId
                       return (f (UGenId n) a b c d)
-
--- | Lift monadic UGen to unsafe form.
-liftP :: (a -> IO UGen) -> (a -> UGen)
-liftP f a = unsafePerformIO (f a)
-
--- | Lift monadic UGen to unsafe form.
-liftP2 :: (a -> b -> IO UGen) -> (a -> b -> UGen)
-liftP2 f a b = unsafePerformIO (f a b)
-
--- | Lift monadic UGen to unsafe form.
-liftP3 :: (a -> b -> c -> IO UGen) -> (a -> b -> c -> UGen)
-liftP3 f a b c = unsafePerformIO (f a b c)
-
--- | Lift monadic UGen to unsafe form.
-liftP4 :: (a -> b -> c -> d -> IO UGen) -> (a -> b -> c -> d -> UGen)
-liftP4 f a b c d = unsafePerformIO (f a b c d)
diff --git a/hsc3.cabal b/hsc3.cabal
--- a/hsc3.cabal
+++ b/hsc3.cabal
@@ -1,19 +1,19 @@
 Name:              hsc3
-Version:           0.6
+Version:           0.7
 Synopsis:          Haskell SuperCollider
 Description:       hsc3 provides Sound.SC3, a haskell module that 
                    facilitates using haskell as a client to the 
                    SuperCollider synthesis server.  
 License:           GPL
 Category:          Sound
-Copyright:         (c) Rohan Drape and others, 2006-2008
+Copyright:         (c) Rohan Drape and others, 2006-2009
 Author:            Rohan Drape
 Maintainer:        rd@slavepianos.org
 Stability:         Experimental
 Homepage:          http://slavepianos.org/rd/f/207949/
-Tested-With:       GHC==6.10.1
+Tested-With:       GHC == 6.8.2
 Build-Type:        Simple
-Cabal-Version:     >= 1.2
+Cabal-Version:     >= 1.6
 
 Data-files:        README
                    emacs/hsc3.el
@@ -65,6 +65,7 @@
                    Help/Graphs/lf-pulses.lhs
                    Help/Graphs/lg-timed.lhs
                    Help/Graphs/lin-sosc.lhs
+                   Help/Graphs/lucier.hs
                    Help/Graphs/modal-space.lhs
                    Help/Graphs/moto-rev.lhs
                    Help/Graphs/mouse-clatter.lhs
@@ -81,7 +82,6 @@
                    Help/Graphs/red-frik.lhs
                    Help/Graphs/reverberated-sine-percussion.lhs
                    Help/Graphs/rm-octaver.lhs
-                   Help/Graphs/rzblp.lhs
                    Help/Graphs/sample-and-hold-liquidities.lhs
                    Help/Graphs/s-chirp.lhs
                    Help/Graphs/scratchy.lhs
@@ -105,11 +105,9 @@
                    Help/Graphs/tipnso.lhs
                    Help/Graphs/train.lhs
                    Help/Graphs/trkl.lhs
-                   Help/Graphs/trmlo.lhs
                    Help/Graphs/tr-out.lhs
                    Help/Graphs/tsort.lhs
                    Help/Graphs/vlc-distrtn.lhs
-                   Help/Graphs/voscil.lhs
                    Help/Graphs/what-was-i-thinking.lhs
                    Help/Graphs/wial.lhs
                    Help/Graphs/wind-metals.lhs
@@ -309,7 +307,7 @@
                    Help/UGen/Filter/degreeToKey.help.lhs
                    Help/UGen/Filter/delay1.help.lhs
                    Help/UGen/Filter/delay2.help.lhs
-                   Help/UGen/Filter/delayA.help.lhs
+                   Help/UGen/Filter/delayC.help.lhs
                    Help/UGen/Filter/delayL.help.lhs
                    Help/UGen/Filter/delayN.help.lhs
                    Help/UGen/Filter/formlet.help.lhs
@@ -340,6 +338,7 @@
                    Help/UGen/Filter/oneZero.help.lhs
                    Help/UGen/Filter/pitchShift.help.lhs
                    Help/UGen/Filter/pluck.help.lhs
+                   Help/UGen/Filter/ramp.help.lhs
                    Help/UGen/Filter/resonz.help.lhs
                    Help/UGen/Filter/rhpf.help.lhs
                    Help/UGen/Filter/ringz.help.lhs
@@ -388,14 +387,25 @@
                    Help/UGen/MachineListening/onsets.help.lhs
                    Help/UGen/Math/absDif.help.lhs
                    Help/UGen/Math/abs.help.lhs
+                   Help/UGen/Math/add.help.lhs
                    Help/UGen/Math/amClip.help.lhs
                    Help/UGen/Math/atan2.help.lhs
                    Help/UGen/Math/clip2.help.lhs
+                   Help/UGen/Math/dbAmp.help.lhs
                    Help/UGen/Math/difSqr.help.lhs
                    Help/UGen/Math/distort.help.lhs
+                   Help/UGen/Math/eq.help.lhs
+                   Help/UGen/Math/excess.help.lhs
+                   Help/UGen/Math/fdiv.help.lhs
                    Help/UGen/Math/fold2.help.lhs
+                   Help/UGen/Math/gt.help.lhs
                    Help/UGen/Math/hypot.help.lhs
+                   Help/UGen/Math/max.help.lhs
+                   Help/UGen/Math/mod.help.lhs
+                   Help/UGen/Math/mul.help.lhs
+                   Help/UGen/Math/pow.help.lhs
                    Help/UGen/Math/ring1.help.lhs
+                   Help/UGen/Math/roundUp.help.lhs
                    Help/UGen/Math/scaleNeg.help.lhs
                    Help/UGen/Math/softClip.help.lhs
                    Help/UGen/Math/sumSqr.help.lhs
@@ -447,6 +457,7 @@
                    Help/UGen/Oscillator/tGrains.help.lhs
                    Help/UGen/Oscillator/twChoose.help.lhs
                    Help/UGen/Oscillator/twindex.help.lhs
+                   Help/UGen/Oscillator/varSaw.help.lhs
                    Help/UGen/Panner/linPan2.help.lhs
                    Help/UGen/Panner/pan2.help.lhs
                    Help/UGen/Panner/rotate2.help.lhs
@@ -472,8 +483,14 @@
                    Help/UGen/Trigger/trig.help.lhs
 
 Library
-  Build-Depends:   base, binary, bytestring, containers, hosc == 0.6,
-                   network, process, random
+  Build-Depends:   base == 3.*,
+                   binary,
+                   bytestring,
+                   containers,
+                   hosc == 0.7,
+                   network,
+                   process,
+                   random
   GHC-Options:     -Wall -fwarn-tabs
   Exposed-modules: Sound.SC3
                    Sound.SC3.Server
