diff --git a/Help/Collection/collection.help.lhs b/Help/Collection/collection.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Collection/collection.help.lhs
@@ -0,0 +1,44 @@
+* Lists of numbers are numerical, Extension
+
+> import Sound.SC3.Lang.Collection
+
+Pointwise operations in the supercollider 
+language extend the shorter input by
+cycling.
+
+That is, the expression:
+
+| [1, 2] + [3, 4, 5]
+
+is equivalent to:
+
+| [1, 2, 1] + [3, 4, 5]
+
+and so describes the three element 
+list [4, 6, 6].
+
+The collection module provides list 
+instances for the standard haskell 
+numerical type classes with the same 
+extension behaviour, so that:
+
+> [1, 2] + [3, 4, 5]
+
+has the same value as in the supercollider
+language, and as distinct from the value of:
+
+> zipWith (+) [1, 2] [3, 4, 5]
+
+which is the two element list [4, 6].
+
+The function underlying the list numerical 
+instances is zipWith_c:
+
+> zipWith_c (+) [1, 2] [3, 4, 5]
+
+Since literals are interpreted as single
+element lists, the expression:
+
+> [1, 2, 3] * 4
+
+denotes the list [4, 8, 12].
diff --git a/Help/Math/pitch.help.lhs b/Help/Math/pitch.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Math/pitch.help.lhs
@@ -0,0 +1,54 @@
+* Pitch & record
+
+> import Sound.SC3.Lang.Math
+
+The supercollider language pitch model
+is organised as a tree with three separate
+layers, and is designed to allow separate
+processes to manipulate aspects of the
+model independently.
+
+The haskell variant implements Pitch as
+a labeled data type, with a default value
+such that scale degree 5 is the a above
+middle c.
+
+> freq (defaultPitch { degree = 5 })
+
+The note is given as a degree, with a modal
+transposition, indexing a scale interpreted
+relative to an equally tempered octave
+divided into the indicated number of steps.
+
+The midinote is derived from the note by
+adding the inidicated root, octave and
+gamut transpositions.
+
+The frequency is derived by a chromatic
+transposition of the midinote, with a
+harmonic multiplier.
+
+> let { p = defaultPitch
+>     ; n = p { stepsPerOctave = 12
+>             , scale = [0, 2, 4, 5, 7, 9, 11]
+>             , degree = 0
+>             , mtranspose = 5 }
+>     ; m = n { root = 0
+>             , octave = 5
+>             , gtranspose = 0 }
+>     ; f = m { ctranspose = 0
+>             , harmonic = 1 } }
+> in (note n, midinote m, freq f)
+
+By editing the values of aspects of
+a pitch, processes can cooperate. 
+Below one process controls the note
+by editing the modal transposition,
+a second edits the octave.
+
+> let { edit_mtranspose p d = p { mtranspose = mtranspose p + d }
+>     ; edit_octave p o = p { octave = octave p + o }
+>     ; p = repeat defaultPitch
+>     ; q = zipWith edit_mtranspose p [0, 2, 4, 3, 5]
+>     ; r = zipWith edit_octave q [0, -1, 0, 1, 0] }
+> in (map midinote q, map midinote r)
diff --git a/Help/Pattern/pattern.help.lhs b/Help/Pattern/pattern.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pattern.help.lhs
@@ -0,0 +1,251 @@
+> import Sound.SC3.Lang.Pattern
+
+* Beginning
+
+| One goal of separating the synthesis engine and
+| the language in SC Server is to make it possible
+| to explore implementing in other languages the
+| concepts expressed in the SuperCollider language
+| and class library.  (McCartney, 2000)
+
+Patterns in supercollider language provide
+a concise and expressive notation for writing
+complex processes.
+
+In a strict language the distinction between
+data and process is quite clear.
+
+In non-strict and purely functional languages
+ordinary data types may be of indefinite extent.
+
+> let ones = 1 : ones
+> in take 5 ones
+
+Since there is no mutation in haskell the
+pattern and stream distinction is less 
+clear.
+
+> let { a = [1,2,3] ++ a
+>     ; b = drop 2 (fmap negate a) }
+> in take 5 (zip a b)
+
+However, as was noted in relation to the noise
+and related unit generators, a notation for
+describing indeterminate structures presents
+some interesting questions.
+
+* Patterns are abstract
+
+The type of a pattern is abstract.
+
+> data P a
+
+(P a) is the abstract data type of a pattern 
+with elements of type a.
+
+Patterns are constructed, manipulated and destructured 
+using the functions provided.
+
+* Patterns are Monoids
+
+> class Monoid a where
+>   mempty :: a
+>   mappend :: a -> a -> a
+
+Patterns are instances of monoid.  mempty is the
+empty pattern, and mappend makes a sequence of two
+patterns.
+
+> pempty :: P a
+> pappend :: P a -> P a -> P a
+
+* Patterns are Functors
+
+> class Functor f
+>     where fmap :: (a -> b) -> f a -> f b
+
+Patterns are an instance of Functor.  fmap applies
+a function to each element of a pattern.
+
+> pmap :: (a -> b) -> P a -> P b
+
+* Patterns are Applicative
+
+> class (Functor f) => Applicative f where
+>   pure :: a -> f a
+>   (<*>) :: f (a -> b) -> f a -> f b
+
+Patterns are instances of Applicative (McBride and
+Paterson, 2007).  The pure function lifts a value
+into an infinite pattern of itself.  The (<*>)
+function applies a pattern of functions to a
+pattern of values.
+
+> ppure :: a -> P a
+> papply :: P (a -> b) -> P a -> P b
+
+Consider summing two patterns:
+
+> import Control.Applicative
+
+> let { p = pseq [1, 3, 5] 1
+>     ; q = pseq [6, 4, 2] 1 }
+> in evalP 0 (pure (+) <*> p <*> q)
+
+* Patterns are Monads
+
+> class Monad m where
+>     (>>=) :: m a -> (a -> m b) -> m b
+>     return :: a -> m a
+
+Patterns are an instance of the Monad class
+(Wadler, 1990).  The (>>=) function, pronounced
+bind, is the mechanism for processing a monadic
+value.  The return function places a value into
+the monad, for the pattern case it creates a 
+single element pattern.
+
+> pbind :: P x -> (x -> P a) -> P a
+> preturn :: a -> P a
+
+The monad instance for Patterns follows the
+standard monad instance for lists, for example:
+
+> evalP 0 (pseq [1, 2] 1 >>= \x ->
+>          pseq [3, 4, 5] 1 >>= \y ->
+>          return (x, y))
+
+which may be written using the haskell do notation
+as:
+
+> evalP 0 (do { x <- pseq [1, 2] 1
+>             ; y <- pseq [3, 4, 5] 1
+>             ; return (x, y) })
+
+denotes the pattern having elements (1,3), (1,4),
+(1,5), (2,3), (2,4) and (2,5).
+
+* Patterns are numerical
+
+Patterns are instances of both Num:
+
+> class (Eq a, Show a) => Num a where
+>   (+) :: a -> a -> a
+>   (*) :: a -> a -> a
+>   (-) :: a -> a -> a
+>   negate :: a -> a
+>   abs :: a -> a
+>   signum :: a -> a
+>   fromInteger :: Integer -> a
+
+and fractional:
+
+> class (Num a) => Fractional a where
+>   (/) :: a -> a -> a
+>   recip :: a -> a
+>   fromRational :: Rational -> a
+
+Summing two patterns does not require using the
+applicative notation above, and the numerical
+pattern (return x) can be written as the literal
+'x':
+
+> let { p = pseq [1, 3, 5] 1
+>     ; q = pseq [6, 4, 2] 1 }
+> in evalP 0 (p + q)
+
+The numerical instances are written using the 
+applicative functions pure and <*>.
+
+* Intederminacy, Randomness
+
+A pattern may be given by a function from
+a random number generator to a duple of
+a pattern and a derived random number 
+generator.
+
+> prp :: (StdGen -> (P a, StdGen)) -> P a
+
+pfix makes a pattern determinate by seeding 
+the random number generator for the pattern.
+
+> type Seed = Int
+> pfix :: Seed -> P a -> P a
+
+* Accumulation, Threading
+
+pscan is an accumulator.  It provides a mechanism
+for state to be threaded through a pattern.  It can
+be used to write a function to remove succesive
+duplicates from a pattern, to count the distance
+between occurences of an element in a pattern and
+so on.
+
+> pscan :: (x -> y -> (x, a)) -> (x -> a) -> x -> P y -> P a
+
+* Continuing
+
+pcontinue provides a mechanism to destructure a
+pattern and generate a new pattern based on the
+first element and the 'rest' of the pattern.
+
+> pcontinue :: P x -> (x -> P x -> P a) -> P a
+
+The bind instance of monad is written in relation
+to pcontinue.
+
+> pbind p f = pcontinue p (\x q -> f x `mappend` pbind q f)
+
+pcontinue can be used to write pfilter the
+basic pattern filter, ptail which discards
+the front elment of a pattern, and so on.
+
+* Destructuring, folding
+
+A pattern has an ordinary right fold, with the
+additional requirement of a seed value for the 
+random number generator.
+
+> pfoldr :: Seed -> (a -> b -> b) -> b -> P a -> b
+
+pfoldr is the primitive traversal function for
+a pattern.  
+
+Right folding with the list constructor (:) and
+the empty list transforms a pattern into a list.
+
+> let p = pser [1, 2, 3] 5 + pseq [0, 10] 3
+> in pfoldr 0 (:) [] p
+
+* Extension
+
+The haskell patterns follow the normal haskell
+behavior when operating pointwise on sequences of
+different length - the longer sequence is
+truncated.
+
+The haskell expression:
+
+> zip [1, 2] [3, 4, 5]
+
+describes a list of two elements, being (1, 3) and
+(2, 4).
+
+This differs from the ordinary supercollider
+language behaviour, where the shorter sequence is
+extended in a cycle, so that the expression:
+
+| [[1, 2], [3, 4, 5]].flop
+
+computes a list of three elements, [1, 3], [2, 4]
+and [1, 5].
+
+* References
+
++ C. McBride and R. Paterson.  Applicative
+  Programming with Effects.  Journal of Functional
+  Programming, 17(4), 2007.
+
++ P. Wadler.  Comprehending Monads.  In Conference
+  on Lisp and Funcional Programming, Nice, France,
+  June 1990. ACM.
diff --git a/Help/Pattern/pclutch.help.lhs b/Help/Pattern/pclutch.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pclutch.help.lhs
@@ -0,0 +1,29 @@
+pclutch :: (Num b, Ord b) => P a -> P b -> P a
+pclutch' :: P a -> P Bool -> P a
+
+ i - input
+ c - clutch
+
+Sample and hold a pattern.  For values greater than
+zero in the control pattern, step the value pattern,
+else hold the previous value. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3, 4, 5] 3
+>     ; q = pseq [1, 0, 1, 0, 0, 0, 1, 1] 1 }
+> in evalP 0 (pclutch p q)
+
+There is a variant that requires a boolean 
+pattern.  
+
+> let { p = pseq [1, 2, 3, 4, 5] 3
+>     ; q = fmap not (pbool (pseq [0, 0, 1, 0, 0, 0, 1, 1] 1)) }
+> in evalP 0 (pclutch' p q)
+
+Note the initialization behavior, nothing
+is generated until the first true value.
+
+> let { p = pseq [1, 2, 3, 4, 5] 3
+>     ; q = pseq [0, 0, 0, 1, 0, 0, 1] 1 }
+> in evalP 0 (pclutch p q)
diff --git a/Help/Pattern/pcollect.help.lhs b/Help/Pattern/pcollect.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pcollect.help.lhs
@@ -0,0 +1,9 @@
+pcollect :: (a -> b) -> P a -> P b
+pcollect = fmap
+
+Patterns are functors.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pcollect (* 3) (pseq [1, 2, 3] 3)
+> in evalP 0 p
diff --git a/Help/Pattern/pcountpre.help.lhs b/Help/Pattern/pcountpre.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pcountpre.help.lhs
@@ -0,0 +1,10 @@
+pcountpre :: P Bool -> P Int
+pcountpost :: P Bool -> P Int
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pbool (pseq [0, 0, 1, 0, 0, 0, 1, 1] 1)
+> in evalP 0 (pcountpre p)
+
+> let p = pbool (pseq [1, 0, 1, 0, 0, 0, 1, 1] 1)
+> in evalP 0 (pcountpost p)
diff --git a/Help/Pattern/pdegreeToKey.help.lhs b/Help/Pattern/pdegreeToKey.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pdegreeToKey.help.lhs
@@ -0,0 +1,26 @@
+pdegreeToKey :: (RealFrac a) => P a -> P [a] -> P a -> P a
+
+         degree - scale degree (zero based)
+          scale - list of divisions (ie. [0, 2, 4, 5, 7, 9, 11])
+ stepsPerOctave - division of octave (ie. 12)
+
+Derive notes from an index into a scale.
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [0, 1, 2, 3, 4, 3, 2, 1, 0, 2, 4, 7, 4, 2] 2
+>     ; q = prepeat [0, 2, 4, 5, 7, 9, 11]
+>     ; r = prepeat 12 }
+> in evalP 0 (pdegreeToKey p q r)
+
+> let { p = pseq [0, 1, 2, 3, 4, 3, 2, 1, 0, 2, 4, 7, 4, 2] 2
+>     ; q = pseq [preturn [0, 2, 4, 5, 7, 9, 11]
+>                ,preturn [0, 2, 3, 5, 7, 8, 11]] 1
+>     ; r = prepeat 12 }
+> in evalP 0 (pdegreeToKey p (pstutter 14 q) r)
+
+The degree_to_key function is also given.
+
+> import Sound.SC3.Lang.Math
+
+> map (\n -> degree_to_key n [0,2,4,5,7,9,11] 12) [0,2,4,7,4,2,0]
diff --git a/Help/Pattern/pdrop.help.lhs b/Help/Pattern/pdrop.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pdrop.help.lhs
@@ -0,0 +1,8 @@
+pdrop :: P Int -> P a -> P a
+
+Drop first n element from pattern.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pseq [1, 2, 3] 4
+> in evalP 0 (pdrop 7 p)
diff --git a/Help/Pattern/pexprand.help.lhs b/Help/Pattern/pexprand.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pexprand.help.lhs
@@ -0,0 +1,13 @@
+pexprand :: (Floating a, Random a) => P a -> P a -> P Int -> P a
+
+Exponential distribution distribution in given range.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pexprand 0.01 0.99 12
+> in evalP 0 p
+
+> let { l = pseq [1, 11] 1
+>     ; r = pseq [2, 12] 1
+>     ; p = pexprand l r 12 }
+> in evalP 0 p
diff --git a/Help/Pattern/pfilter.help.lhs b/Help/Pattern/pfilter.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pfilter.help.lhs
@@ -0,0 +1,9 @@
+pfilter :: (a -> Bool) -> P a -> P a
+
+Allows values for which the predicate is true. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3] 3
+>     ; q = pfilter (< 3) p }
+> in evalP 0 q
diff --git a/Help/Pattern/pfin.help.lhs b/Help/Pattern/pfin.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pfin.help.lhs
@@ -0,0 +1,26 @@
+pfin :: P Int -> P a -> P a
+pfin_ :: Int -> P a -> P a
+ptake :: P Int -> P a -> P a
+ptake_ :: P Int -> P a -> P a
+
+  n - number of elements to take
+  x - value pattern
+
+Take only the first n elements of the pattern 
+into the stream.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pseq [1, 2, 3] pinf
+> in evalP 0 (pfin 5 p)
+
+There is a variant where the count not a pattern.
+
+> let p = pseq [1, 2, 3] 1
+> in evalP 0 (pfin_ 5 p)
+
+Note that pfin does not extend the input pattern,
+unlike pser.
+
+> let p = pseq [1, 2, 3] 1
+> in evalP 0 (pser [p] 5)
diff --git a/Help/Pattern/pgeom.help.lhs b/Help/Pattern/pgeom.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pgeom.help.lhs
@@ -0,0 +1,17 @@
+pgeom :: (Num a) => a -> a -> Int -> P a
+
+Geometric series pattern.
+
+  start - start value
+   grow - multiplication factor
+ length - number of values produced
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pgeom 1 2 12
+> in evalP 0 p
+
+Real numbers work as well.
+
+> let p = pgeom 1.0 1.1 6
+> in evalP 0 p
diff --git a/Help/Pattern/pif.help.lhs b/Help/Pattern/pif.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pif.help.lhs
@@ -0,0 +1,41 @@
+pif :: Int -> P Bool -> P a -> P a -> P a
+pif' :: P Bool -> P a -> P a -> P a
+
+Pattern-based conditional expression.
+
+ condition - pattern of selectors
+    iftrue - pattern selected from when condition is true
+   iffalse - pattern selected from when condition is false
+
+The primary form requires a seed to allow the 
+condition pattern to be fixed.  The variant form
+provides a zero seed, and allows one to indicate
+that the condition pattern is deterministic (or
+that the seed is not important).
+
+> import Sound.SC3.Lang.Pattern
+
+A determinstic condition pattern, with deterministic
+branches.
+
+> let { c = pbool (pseq [1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0] 1)
+>     ; p = pseq [1,2,3,4,5] pinf
+>     ; q = pseq [11,12,13,14,15] pinf }
+> in evalP 0 (pif' c p q)
+
+A non-deterministic condition pattern, with
+noisy branches.
+
+> let { c = fmap (< 0.3) (pwhite 0 1 20)
+>     ; p = pwhite 0 9 pinf
+>     ; q = pwhite 100 109 pinf }
+> in evalP 0 (pif 3 c p q)
+
+Note that the noisy variant can be had for
+less trouble as:
+
+> let { c = fmap (< 0.3) (pwhite 0 1 20)
+>     ; p = pwhite 0 9 pinf
+>     ; q = pwhite 100 109 pinf 
+>     ; if_f c' p' q' = if c' then p' else q' }
+> in evalP 0 (pzipWith3 if_f c p q)
diff --git a/Help/Pattern/pinterleave.help.lhs b/Help/Pattern/pinterleave.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pinterleave.help.lhs
@@ -0,0 +1,13 @@
+pinterleave :: P a -> P a -> P a
+
+Interleave elements from two patterns.
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3] 3
+>     ; q = pseq [4, 5, 6, 7] 2 }
+> in evalP 0 (pinterleave p q)
+
+> let p = pinterleave (pwhite 1 9 5) (pseries 10 1 10)
+> in evalP 1317 p
+
diff --git a/Help/Pattern/pn.help.lhs b/Help/Pattern/pn.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pn.help.lhs
@@ -0,0 +1,16 @@
+pn :: P a -> P Int -> P a
+preplicate :: P Int -> P a -> P a
+
+Repeats the enclosed pattern a number of times.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pn (pseq [1, 2, 3] 1) 4
+> in evalP 0 p
+
+There is a variant with the arguments
+reversed.
+
+> let p = preplicate 4 (pseq [1, 2, 3] 1)
+> in evalP 0 p
+
diff --git a/Help/Pattern/prand.help.lhs b/Help/Pattern/prand.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/prand.help.lhs
@@ -0,0 +1,19 @@
+prand :: [P a] -> P Int -> P a
+
+Returns one item from the list at random for each repeat. 
+
+> import Sound.SC3.Lang
+
+> let p = prand [1, 2, 3, 4, 5] 6
+> in evalP 9 p
+
+> let p = prand [ pseq [1, 2] 1
+>               , pseq [3, 4] 1
+>               , pseq [5, 6] 1 ] 9
+> in evalP 3 p
+
+> let p = pseq [prand [pempty, pseq [24, 31, 36, 43, 48, 55] 1] 1
+>              ,pseq [60, prand [63, 65] 1
+>                    ,67, prand [70, 72, 74] 1] (prrand 2 5)
+>              ,prand [74, 75, 77, 79, 81] (prrand 3 9)] pinf
+> in take 24 (evalP 7 p)
diff --git a/Help/Pattern/preject.help.lhs b/Help/Pattern/preject.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/preject.help.lhs
@@ -0,0 +1,10 @@
+preject :: (a -> Bool) -> P a -> P a
+preject f = pfilter (not . f)
+
+Rejects values for which the predicate is true. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3] 3
+>     ; q = preject (== 1) p }
+> in evalP 0 q
diff --git a/Help/Pattern/prorate.help.lhs b/Help/Pattern/prorate.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/prorate.help.lhs
@@ -0,0 +1,11 @@
+prorate
+
+Divide stream proportionally
+
+ proportions - a pattern that returns either numbers (divides the
+               pattern into pairs) or arrays of size n which are used
+               to split up the input into n parts.
+     pattern - a numerical pattern
+
+> let p = prorate (pseq [0.35, 0.5, 0.8] 1) 1
+> in evalP 0 p
diff --git a/Help/Pattern/prsd.help.lhs b/Help/Pattern/prsd.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/prsd.help.lhs
@@ -0,0 +1,8 @@
+prsd :: (Eq a) => P a -> P a
+
+Remove successive duplicates.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pfix 0 (prand [1,2,3] 9)
+> in evalP 0 (pzip (prsd p) p)
diff --git a/Help/Pattern/pseq.help.lhs b/Help/Pattern/pseq.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pseq.help.lhs
@@ -0,0 +1,48 @@
+pseq :: [P a] -> P Int -> P a
+pseq_ :: [P a] -> Int -> P a
+
+Cycle over a list of patterns. The repeats pattern gives
+the number of times to repeat the entire list. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let a = pseq [1, 2, 3] 2
+> in evalP 0 a
+
+Unlike Pseq, pseq does not have an offset argument to
+give a starting offset into the list.
+
+> import Sound.SC3.Lang.Collection
+
+> let p = pseq (rotate 3 [1, 2, 3, 4]) 3
+> in evalP 0 p
+
+Because the repeat counter is a pattern one can have
+a random number of repeats.
+
+> let p = pseq [1, 2] (prrand 1 9)
+> in evalP 7 p
+
+For the same reason the pattern is not static when 
+re-examined.
+
+> let p = pseq [ 0, pseq [1] (prrand 1 3), 2] 5
+> in take 24 (evalP 94 p)
+
+Further, if the repeat pattern is not singular,
+the sequence will repeat until the pattern is exhausted.
+
+> let { p = pseq [1] 3
+>     ; q = pseq [1] p }
+> in evalP 0 q
+
+If one specifies the value pinf for the repeats variable, 
+then it will repeat indefinitely.
+
+> let p = pseq [1, 2, 3] pinf
+> in take 9 (evalP 0 p)
+
+There is a variant with a true integer repeat count.
+
+> let p = pseq_ [1, 2, 3] 5
+> in evalP 0 p
diff --git a/Help/Pattern/pser.help.lhs b/Help/Pattern/pser.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pser.help.lhs
@@ -0,0 +1,14 @@
+pser :: [P a] -> P Int -> P a
+
+pser is like pseq, however the repeats variable 
+gives the number of elements in the sequence,
+not the number of cycles of the pattern.
+
+> let p = pser [1, 2, 3] 5
+> in evalP 0 p
+
+> let p = pser [1, pser [100, 200] 3, 3] 9
+> in evalP 0 p
+
+> let p = pser [1, 2, 3] 5 *. 3
+> in evalP 0 p
diff --git a/Help/Pattern/pseries.help.lhs b/Help/Pattern/pseries.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pseries.help.lhs
@@ -0,0 +1,13 @@
+pseries :: (Num a) => a -> a -> Int -> P a
+
+An arithmetric series. 
+
+  start - start value
+   step - addition factor
+ length - number of values
+
+> let p = pseries 0 2 24
+> in evalP 0 p
+
+> let p = pseries 1.0 0.1 24
+> in evalP 0 p
diff --git a/Help/Pattern/pstutter.help.lhs b/Help/Pattern/pstutter.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pstutter.help.lhs
@@ -0,0 +1,26 @@
+pstutter :: P Int -> P a -> P a
+pstutter' :: P Int -> P a -> P a
+
+  count - number of repeats *cyc*
+      x - value pattern
+
+Repeat each element of a pattern n times.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pstutter 2 (pseq [1, 2, 3] pinf)
+> in take 13 (evalP 0 p)
+
+> let { p = pseq [1, 2] pinf
+>     ; q = pseq [1, 2, 3] pinf
+>     ; r = pstutter p q }
+> in take 13 (evalP 0 r)
+
+There is a variant, pstutter', that does not do
+implicit extension on the count pattern.
+
+> let p = pstutter' (prepeat 2) (pseq [1, 2, 3] pinf)
+> in take 13 (evalP 0 p)
+
+> let p = pstutter' (pseq [2,3] 1) (pseq [1, 2, 3] pinf)
+> in evalP 0 p
diff --git a/Help/Pattern/pswitch.help.lhs b/Help/Pattern/pswitch.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pswitch.help.lhs
@@ -0,0 +1,11 @@
+pswitch :: [P a] -> P Int -> P a
+pswitch l i = i >>= (l !!)
+
+Select elements from a list of patterns by a pattern of indices.
+
+> import Sound.SC3.Lang.Pattern
+
+> let { a = pseq [1, 2, 3] 2
+>     ; b = pseq [65, 76] 1
+>     ; c = pswitch [a, b, 800] (pseq [2, 2, 0, 1] pinf) }
+> in take 24 (evalP 0 c)
diff --git a/Help/Pattern/pswitch1.help.lhs b/Help/Pattern/pswitch1.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pswitch1.help.lhs
@@ -0,0 +1,22 @@
+pswitch1 :: [P a] -> P Int -> P a
+pswitch1m :: IntMap (P a) -> P Int -> P a
+
+  list - patterns to index
+ which - index
+
+The pattern of indices is used select which pattern
+to retrieve the next value from.  Only one value 
+is selected from each the pattern.
+
+This is in comparison to pswitch, which embeds the 
+pattern in its entirety.  pswitch1 switches every value.
+
+pswitch1 is implemented in terms of pswitch1m.
+
+> import Control.Applicative
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3] pinf
+>     ; q = pseq [65, 76] pinf
+>     ; r = pswitch1 [p, q, pure 800] (pseq [2, 2, 0, 1] pinf) }
+> in take 24 (evalP 0 r)
diff --git a/Help/Pattern/ptail.help.lhs b/Help/Pattern/ptail.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/ptail.help.lhs
@@ -0,0 +1,10 @@
+ptail :: P a -> P a
+
+Drop first element from pattern.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pseq [1, 2, 3] 1
+> in evalP 0 (ptail p)
+
+> evalP 0 (ptail pempty)
diff --git a/Help/Pattern/ptrigger.help.lhs b/Help/Pattern/ptrigger.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/ptrigger.help.lhs
@@ -0,0 +1,17 @@
+ptrigger :: P Bool -> P a -> P (Maybe a)
+
+  tr - boolean pattern
+   x - value pattern
+
+The 'tr' pattern determines the rate
+at which values are read from the 'x'
+pattern.  For each sucessive true 
+value at 'tr' the output is a 'Just e'
+of each succesive element at x.  False
+values at 'tr' generate Nothing values. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseq [1, 2, 3, 4, 5] 3     
+>     ; t = pbool (pseq [0, 0, 1, 0, 0, 0, 1, 1] 1) } 
+> in evalP 0 (ptrigger t p)
diff --git a/Help/Pattern/pwhite.help.lhs b/Help/Pattern/pwhite.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pwhite.help.lhs
@@ -0,0 +1,20 @@
+pwhite :: (Random a) => P a -> P a -> P Int -> P a
+
+Uniform linear distribution in given range.
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pwhite 0.0 1.0 12
+> in evalP 0 p
+
+> let { l = pseq [0.0, 10.0] 1
+>     ; r = pseq [1.0, 11.0] 1
+>     ; p = pwhite l r 12 }
+> in evalP 0 p
+
+Or equivalently,
+
+> let { b = pseq [return (0.0, 1.0)
+>                ,return (10.0, 11.0)] 1
+>     ; p = pwhite (fmap fst b) (fmap snd b) 12 }
+> in evalP 0 p
diff --git a/Help/Pattern/pwrap.help.lhs b/Help/Pattern/pwrap.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pwrap.help.lhs
@@ -0,0 +1,17 @@
+pwrap :: (Ord a, Num a) => P a -> P a -> P a -> P a
+
+ x - input
+ l - lower bound *cycle*
+ r - upper bound *cycle*
+
+If x is outside of (l, r) wrap until it lies inside.
+
+> import Sound.SC3.Lang.Pattern
+
+> let { p = pseries 6 2 9
+>     ; q = pwrap p 2 10 }
+> in evalP 0 q
+
+> let { p = pseries 6 2 9
+>     ; q = pwrap p 1 11 }
+> in evalP 0 q
diff --git a/Help/Pattern/pxrand.help.lhs b/Help/Pattern/pxrand.help.lhs
new file mode 100644
--- /dev/null
+++ b/Help/Pattern/pxrand.help.lhs
@@ -0,0 +1,9 @@
+pxrand :: (Eq a) => [P a] -> P Int -> P a
+
+Like prand, returns one item from the list at random for each 
+step, but pxrand never repeats the same element twice in a row. 
+
+> import Sound.SC3.Lang.Pattern
+
+> let p = pxrand [1,2,3] 10
+> in evalP 0 p
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,12 @@
+hsc3-lang - Haskell SuperCollider Language Library
+
+hsc3-lang provides Sound.SC3.Lang, a Haskell module that 
+defines a subset of functions from the SuperCollider 
+class library.
+
+  http://slavepianos.org/rd/
+  http://haskell.org/
+  http://audiosynth.com/
+
+(c) rohan drape, 2007-2009
+    gpl, http://gnu.org/copyleft/
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Sound/SC3/Lang.hs b/Sound/SC3/Lang.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang.hs
@@ -0,0 +1,8 @@
+module Sound.SC3.Lang 
+    ( module Sound.SC3.Lang.Collection
+    , module Sound.SC3.Lang.Math
+    , module Sound.SC3.Lang.Pattern ) where
+
+import Sound.SC3.Lang.Collection
+import Sound.SC3.Lang.Math
+import Sound.SC3.Lang.Pattern
diff --git a/Sound/SC3/Lang/Collection.hs b/Sound/SC3/Lang/Collection.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Collection.hs
@@ -0,0 +1,8 @@
+module Sound.SC3.Lang.Collection 
+    ( module Sound.SC3.Lang.Collection.Collection
+    , module Sound.SC3.Lang.Collection.Numerical
+    , module Sound.SC3.Lang.Collection.SequenceableCollection ) where
+
+import Sound.SC3.Lang.Collection.Collection
+import Sound.SC3.Lang.Collection.Numerical
+import Sound.SC3.Lang.Collection.SequenceableCollection
diff --git a/Sound/SC3/Lang/Collection/Collection.hs b/Sound/SC3/Lang/Collection/Collection.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Collection/Collection.hs
@@ -0,0 +1,56 @@
+module Sound.SC3.Lang.Collection.Collection where
+
+import Data.List
+import Data.Maybe
+
+fill :: Int -> (Int -> a) -> [a]
+fill n f = map f [0 .. n - 1]
+
+size :: [a] -> Int
+size = length
+
+isEmpty :: [a] -> Bool
+isEmpty = null
+
+ignoringIndex :: (a -> b) -> a -> Int -> b
+ignoringIndex f e _ = f e
+
+collect :: (a -> Int -> b) -> [a] -> [b]
+collect f l = zipWith f l [0..]
+
+select :: (a -> Int -> Bool) -> [a] -> [a]
+select f l = map fst (filter (uncurry f) (zip l [0..]))
+
+reject :: (a -> Int -> Bool) -> [a] -> [a]
+reject f l = map fst (filter (not . uncurry f) (zip l [0..]))
+
+detect :: (a -> Int -> Bool) -> [a] -> Maybe a
+detect f l = maybe Nothing (Just . fst) (find (uncurry f) (zip l [0..]))
+
+detectIndex :: (a -> Int -> Bool) -> [a] -> Maybe Int
+detectIndex f l = maybe Nothing (Just . snd) (find (uncurry f) (zip l [0..]))
+
+inject :: a -> (a -> b -> a) -> [b] -> a
+inject i f = foldl f i
+
+any' :: (a -> Int -> Bool) -> [a] -> Bool
+any' f = isJust . detect f
+
+every :: (a -> Int -> Bool) -> [a] -> Bool
+every f = let g e = not . f e
+          in not . any' g
+
+count :: (a -> Int -> Bool) -> [a] -> Int
+count f = length . select f
+
+occurencesOf :: (Eq a) => a -> [a] -> Int
+occurencesOf k = count (\e _ -> e == k)
+
+sum' :: (Num a) => (b -> Int -> a) -> [b] -> a
+sum' f = sum . collect f
+
+maxItem :: (Ord b) => (a -> Int -> b) -> [a] -> b
+maxItem f = maximum . collect f
+
+minItem :: (Ord b) => (a -> Int -> b) -> [a] -> b
+minItem f = minimum . collect f
diff --git a/Sound/SC3/Lang/Collection/Numerical.hs b/Sound/SC3/Lang/Collection/Numerical.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Collection/Numerical.hs
@@ -0,0 +1,37 @@
+module Sound.SC3.Lang.Collection.Numerical where
+
+import Sound.SC3.Lang.Collection.SequenceableCollection (zipWith_c)
+
+instance Num a => Num [a] where
+    negate         = map negate
+    (+)            = zipWith_c (+)
+    (-)            = zipWith_c (-)
+    (*)            = zipWith_c (*)
+    abs            = map abs
+    signum         = map signum
+    fromInteger n  = [fromInteger n]
+
+instance Fractional a => Fractional [a] where
+    recip          = map recip
+    (/)            = zipWith_c (/)
+    fromRational n = [fromRational n]
+
+instance Floating a => Floating [a] where
+    pi             = cycle [pi]
+    exp            = map exp
+    log            = map log
+    sqrt           = map sqrt
+    (**)           = zipWith_c (**)
+    logBase        = zipWith_c logBase
+    sin            = map sin
+    cos            = map cos
+    tan            = map tan
+    asin           = map asin
+    acos           = map acos
+    atan           = map atan
+    sinh           = map sinh
+    cosh           = map cosh
+    tanh           = map tanh
+    asinh          = map asinh
+    acosh          = map acosh
+    atanh          = map atanh
diff --git a/Sound/SC3/Lang/Collection/SequenceableCollection.hs b/Sound/SC3/Lang/Collection/SequenceableCollection.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Collection/SequenceableCollection.hs
@@ -0,0 +1,142 @@
+module Sound.SC3.Lang.Collection.SequenceableCollection where
+
+import Control.Monad
+import Data.List
+import Data.Maybe
+import Sound.SC3.Lang.Collection.Collection
+import System.Random
+
+-- | Arithmetic series (size, start, step)
+series :: (Num a) => Int -> a -> a -> [a]
+series 0 _ _ = []
+series n i j = i : series (n - 1) (i + j) j
+
+-- | Geometric series (size, start, grow)
+geom :: (Num a) => Int -> a -> a -> [a]
+geom 0 _ _ = []
+geom n i j = i : series (n - 1) (i * j) j
+
+-- | Fibonacci series (size, initial step, start)
+fib :: (Num a) => Int -> a -> a -> [a]
+fib 0 _ _ = []
+fib n i j = j : fib (n - 1) j (i + j)
+
+-- | Random values (size, min, max) - ought this be in floating?
+rand :: (Random a) => Int -> a -> a -> IO [a]
+rand n l r = replicateM n (getStdRandom (randomR (l, r)))
+
+-- | Random values in the range -abs to +abs (size, abs)
+rand2 :: (Num a, Random a) => Int -> a -> IO [a]
+rand2 n m = replicateM n (getStdRandom (randomR (negate m, m)))
+
+-- | The first element.
+first :: [t] -> Maybe t
+first (x:_) = Just x
+first _ = Nothing
+
+-- | The last element.
+last' :: [t] -> Maybe t
+last' [] = Nothing
+last' [x] = Just x
+last' (_:xs) = last' xs
+
+-- | flip elemIndex
+indexOf :: Eq a => [a] -> a -> Maybe Int
+indexOf = flip elemIndex
+
+-- | indexOf
+indexOfEqual :: Eq a => [a] -> a -> Maybe Int
+indexOfEqual = indexOf
+
+-- | Collection is sorted, index of first greater element.
+indexOfGreaterThan :: (Ord a) => a -> [a] -> Maybe Int
+indexOfGreaterThan e = detectIndex (ignoringIndex (> e))
+
+-- | Collection is sorted, index of nearest element.
+indexIn :: (Ord a, Num a) => a -> [a] -> Int
+indexIn e l = maybe (size l - 1) f (indexOfGreaterThan e l)
+    where f 0 = 0
+          f j = if (e - left) < (right - e) then i else j 
+              where i = j - 1
+                    right = l !! j
+                    left = l !! i
+
+-- | Collection is sorted, linearly interpolated fractional index.
+indexInBetween :: (Ord a, Fractional a) => a -> [a] -> a
+indexInBetween e l = maybe (fromIntegral (size l) - 1) f (indexOfGreaterThan e l)
+    where f 0 = 0
+          f j = if d == 0 then i else ((e - a) / d) + i - 1
+              where i = fromIntegral j
+                    a = l !! (j - 1)
+                    b = l !! j
+                    d = b - a
+
+keep :: Int -> [a] -> [a]
+keep n l | n < 0 = fromMaybe l (find (\e -> length e == negate n) (tails l))
+         | otherwise = take n l
+
+drop' :: Int -> [a] -> [a]
+drop' n l | n < 0 = take (length l + n) l
+          | otherwise = drop n l
+
+extendSequences :: [[a]] -> [[a]]
+extendSequences l = map (take n . cycle) l
+    where n = maximum (map length l)
+
+flop :: [[a]] -> [[a]]
+flop = transpose . extendSequences
+
+choose :: [a] -> IO a
+choose l = liftM (l!!) (getStdRandom (randomR (0, length l - 1)))
+
+separateAt :: (a -> a -> Bool) -> [a] -> ([a], [a])
+separateAt f (x1:x2:xs) = if f x1 x2 
+                          then ([x1], x2:xs) 
+                          else x1 `g` separateAt f (x2:xs)
+                              where g e (l,r) = (e:l, r)
+separateAt _ l = (l,[])
+
+separate :: (a -> a -> Bool) -> [a] -> [[a]]
+separate f l = if null r then [e] else e : separate f r
+    where (e, r) = separateAt f l
+
+clump :: Int -> [a] -> [[a]]
+clump n l = if null r then [e] else e : clump n r
+    where (e, r) = splitAt n l
+
+clumps :: [Int] -> [a] -> [[a]]
+clumps m s = f (cycle m) s
+    where f [] _ = undefined
+          f (n:ns) l = if null r then [e] else e :clumps ns r
+              where (e, r) = splitAt n l
+
+-- | dx -> d
+integrate :: (Num a) => [a] -> [a]
+integrate [] = []
+integrate (x:xs) = x : snd (mapAccumL f x xs)
+    where f p c = (p + c, p + c)
+
+-- | d -> dx
+differentiate :: (Num a) => [a] -> [a]
+differentiate l = zipWith (-) l (0:l)
+
+-- | Rotate n places to the left (ie. rotate 1 [1, 2, 3] is [2, 3, 1]).
+rotate :: Int -> [a] -> [a]
+rotate n p = let (b, a) = splitAt n p 
+             in a ++ b 
+
+-- | Ensure sum of elements is one.
+normalizeSum :: (Fractional a) => [a] -> [a]
+normalizeSum l = let n = sum l
+                 in map (/ n) l
+
+-- | Variant that cycles the shorter input.
+zipWith_c :: (a -> b -> c) -> [a] -> [b] -> [c]
+zipWith_c f a b = g a b (False, False)
+    where g [] [] _ = []
+          g [] b' (_, e) = if e then [] else g a b' (True, e)
+          g a' [] (e, _) = if e then [] else g a' b (e, True)
+          g (a0 : aN) (b0 : bN) e = f a0 b0 : g aN bN e
+
+zip_c :: [a] -> [b] -> [(a, b)]
+zip_c = zipWith_c (,)
diff --git a/Sound/SC3/Lang/Math.hs b/Sound/SC3/Lang/Math.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Math.hs
@@ -0,0 +1,3 @@
+module Sound.SC3.Lang.Math ( module Sound.SC3.Lang.Math.Pitch ) where
+
+import Sound.SC3.Lang.Math.Pitch
diff --git a/Sound/SC3/Lang/Math/Pitch.hs b/Sound/SC3/Lang/Math/Pitch.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Math/Pitch.hs
@@ -0,0 +1,64 @@
+module Sound.SC3.Lang.Math.Pitch where
+
+data Pitch a = Pitch { mtranspose :: a
+                     , gtranspose :: a
+                     , ctranspose :: a
+                     , octave :: a
+                     , root :: a 
+                     , scale :: [a]
+                     , degree :: a
+                     , stepsPerOctave :: a
+                     , detune :: a
+                     , harmonic :: a
+                     , freq_f :: Pitch a -> a
+                     , midinote_f :: Pitch a -> a
+                     , note_f :: Pitch a -> a }
+
+midi_cps :: (Floating a) => a -> a
+midi_cps a = 440.0 * (2.0 ** ((a - 69.0) * (1.0 / 12.0)))
+
+defaultPitch :: (Floating a, RealFrac a) => Pitch a
+defaultPitch = 
+    Pitch { mtranspose = 0
+          , gtranspose = 0
+          , ctranspose = 0
+          , octave = 5
+          , root = 0
+          , degree = 0
+          , scale = [0, 2, 4, 5, 7, 9, 11]
+          , stepsPerOctave = 12
+          , detune = 0
+          , harmonic = 1
+          , freq_f = default_freq_f
+          , midinote_f = default_midinote_f
+          , note_f = default_note_f
+          }
+
+default_freq_f :: (Floating a) => Pitch a -> a
+default_freq_f e = midi_cps (midinote e + ctranspose e) * harmonic e
+
+default_midinote_f :: (Fractional a) => Pitch a -> a
+default_midinote_f e = let n = note e + gtranspose e + root e
+                       in (n / stepsPerOctave e + octave e) * 12
+
+default_note_f :: (RealFrac a) => Pitch a -> a
+default_note_f e = let d = degree e + mtranspose e
+                   in degree_to_key d (scale e) (stepsPerOctave e)
+
+degree_to_key :: (RealFrac a) => a -> [a] -> a -> a
+degree_to_key d s n = (n * fromIntegral (d' `div` l)) + (s !! (d' `mod` l)) + a
+    where l = length s
+          d' = round d
+          a = (d - fromIntegral d') * 10.0 * (n / 12.0)
+
+note :: Pitch a -> a
+note e = note_f e e
+
+midinote :: Pitch a -> a
+midinote e = midinote_f e e
+
+freq :: Pitch a -> a
+freq e = freq_f e e
+
+detunedFreq :: (Num a) => Pitch a -> a
+detunedFreq e = freq e + detune e
diff --git a/Sound/SC3/Lang/Pattern.hs b/Sound/SC3/Lang/Pattern.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern.hs
@@ -0,0 +1,11 @@
+module Sound.SC3.Lang.Pattern ( module Sound.SC3.Lang.Pattern.Pattern
+                              , module Sound.SC3.Lang.Pattern.Control
+                              , module Sound.SC3.Lang.Pattern.Extend
+                              , module Sound.SC3.Lang.Pattern.List
+                              , module Sound.SC3.Lang.Pattern.Random ) where
+
+import Sound.SC3.Lang.Pattern.Pattern
+import Sound.SC3.Lang.Pattern.Control
+import Sound.SC3.Lang.Pattern.Extend
+import Sound.SC3.Lang.Pattern.List
+import Sound.SC3.Lang.Pattern.Random
diff --git a/Sound/SC3/Lang/Pattern/Control.hs b/Sound/SC3/Lang/Pattern/Control.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern/Control.hs
@@ -0,0 +1,168 @@
+module Sound.SC3.Lang.Pattern.Control where
+
+import Control.Applicative
+import Control.Monad
+import Data.List
+import Data.Maybe
+import Data.Monoid
+import Sound.SC3.Lang.Math.Pitch
+import Sound.SC3.Lang.Pattern.Pattern
+
+pfilter :: (a -> Bool) -> P a -> P a
+pfilter f p = pcontinue p (\x p' -> if f x 
+                                    then mappend (return x) (pfilter f p')
+                                    else pfilter f p')
+
+plist :: [P a] -> P a
+plist = foldr mappend mempty
+
+pcons :: a -> P a -> P a
+pcons = mappend . return
+
+preplicate_ :: Int -> P a -> P a
+preplicate_ n p | n > 0 = mappend p (preplicate_ (n - 1) p)
+                | otherwise = mempty
+
+preplicate :: P Int -> P a -> P a
+preplicate n p = n >>= (\x -> preplicate_ x p)
+
+pn :: P a -> P Int -> P a
+pn = flip preplicate
+
+pn_ :: P a -> Int -> P a
+pn_ = flip preplicate_
+
+-- | 'n' initial values at 'p'.
+ptake_ :: Int -> P a -> P a
+ptake_ n p = pzipWith const p (preplicate_ n (return undefined))
+
+ptake :: P Int -> P a -> P a
+ptake n p = pzipWith const p (preplicate n (return undefined))
+
+-- | 'n' initial values at pcycle of 'p'.
+prestrict_ :: Int -> P a -> P a
+prestrict_ n = ptake_ n . pcycle
+
+prestrict :: P Int -> P a -> P a
+prestrict n = ptake n . pcycle
+
+pmapMaybe :: (a -> Maybe b) -> P a -> P b
+pmapMaybe f = fmap fromJust . pfilter isJust . fmap f
+
+preject :: (a -> Bool) -> P a -> P a
+preject f = pfilter (not . f)
+
+pzipWith3 :: (a -> b -> c -> d) -> P a -> P b -> P c -> P d
+pzipWith3 f p q = (<*>) (pure f <*> p <*> q)
+
+pzip :: P a -> P b -> P (a,b)
+pzip = pzipWith (,)
+
+pseries :: (Num a) => a -> a -> Int -> P a
+pseries i s n = plist (unfoldr f (i, n))
+    where f (_, 0) = Nothing
+          f (j, m) = Just (return j, (j + s, m - 1))
+
+pgeom :: (Num a) => a -> a -> Int -> P a
+pgeom i s n = plist (unfoldr f (i, n))
+    where f (_, 0) = Nothing
+          f (j, m) = Just (return j, (j * s, m - 1))
+
+pstutter' :: P Int -> P a -> P a
+pstutter' n p =
+    let f :: Int -> a -> P a
+        f i e = preplicate (return i) (return e)
+    in psequence (pzipWith f n p)
+
+pstutter :: P Int -> P a -> P a
+pstutter = pstutter' . pcycle
+
+-- | Count false values preceding each true value. 
+pcountpre :: P Bool -> P Int
+pcountpre p = pmapMaybe id (pscan f Nothing 0 p)
+    where f x e = if e then (0, Just x) else (x + 1, Nothing)
+
+-- | Count false values following each true value. 
+pcountpost :: P Bool -> P Int
+pcountpost p = ptail (pmapMaybe id (pscan f (Just Just) 0 p))
+    where f x e = if e then (0, Just x) else (x + 1, Nothing)
+
+pclutch' :: P a -> P Bool -> P a
+pclutch' p q = pstutter' r p
+    where r = fmap (+ 1) (pcountpost q)
+
+pbool :: (Ord a, Num a) => P a -> P Bool
+pbool = fmap (> 0)
+
+pclutch :: (Num b, Ord b) => P a -> P b -> P a
+pclutch p = pclutch' p . pbool
+
+pcollect :: (a -> b) -> P a -> P b
+pcollect = fmap
+
+pdegreeToKey :: (RealFrac a) => P a -> P [a] -> P a -> P a
+pdegreeToKey = pzipWith3 degree_to_key
+
+pfin :: P Int -> P a -> P a
+pfin = ptake
+
+pfin_ :: Int -> P a -> P a
+pfin_ = ptake_
+
+wrap :: (Ord a, Num a) => a -> a -> a -> a
+wrap l r x = if x > r
+             then wrap l r (x - (r - l))
+             else if x < l 
+                  then wrap l r (x + (r - l))
+                  else x
+
+pwrap :: (Ord a, Num a) => P a -> P a -> P a -> P a
+pwrap x l r = pzipWith3 f x (pcycle l) (pcycle r)
+    where f x' l' r' = wrap l' r' x'
+
+-- | Remove successive duplicates.
+prsd :: (Eq a) => P a -> P a
+prsd p = pmapMaybe id (pscan f Nothing Nothing p)
+    where f Nothing a = (Just a, Just a)
+          f (Just x) a = (Just a, if a == x then Nothing else Just a)
+
+psequence :: P (P a) -> P a
+psequence = join
+
+pduple :: (a, a) -> P a
+pduple (x, y) = return x `mappend` return y
+
+pinterleave :: P a -> P a -> P a
+pinterleave p = psequence . fmap pduple . pzip p
+
+ptrigger :: P Bool -> P a -> P (Maybe a)
+ptrigger p q = join (pzipWith f r q)
+    where r = pcountpre p
+          f i = mappend (preplicate_ i (return Nothing)) . return . Just
+
+pif :: Int -> P Bool -> P a -> P a -> P a
+pif s b p q = pzipWith f p' q'
+    where b' = pfix s b
+          p' = ptrigger b' p
+          q' = ptrigger (fmap not b') q
+          f (Just x) Nothing = x
+          f Nothing (Just x) = x
+          f _ _ = undefined
+
+pif' :: P Bool -> P a -> P a -> P a
+pif' = pif 0
+
+phead :: P a -> P a
+phead p = pcontinue p (\x _ -> return x)
+
+ptail :: P a -> P a
+ptail p = pcontinue p (\_ p' -> p')
+
+pdrop :: P Int -> P a -> P a
+pdrop n p = n >>= (\x -> if x > 0 
+                         then pdrop (return (x-1)) (ptail p)
+                         else p)
+
+pscanl :: (a -> y -> a) -> a -> P y -> P a
+pscanl f i p = pcons i (pscan g Nothing i p)
+    where g x y = let r = f x y in (r, r) 
diff --git a/Sound/SC3/Lang/Pattern/Extend.hs b/Sound/SC3/Lang/Pattern/Extend.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern/Extend.hs
@@ -0,0 +1,18 @@
+module Sound.SC3.Lang.Pattern.Extend where
+
+import Sound.SC3.Lang.Pattern.Pattern
+
+pzipWith_c :: (a -> b -> c) -> P a -> P b -> P c
+pzipWith_c f p = pzipWith f p . pcycle
+
+(+.) :: Num a => P a -> P a -> P a
+(+.) = pzipWith_c (+)
+
+(*.) :: Num a => P a -> P a -> P a
+(*.) = pzipWith_c (*)
+
+(/.) :: Fractional a => P a -> P a -> P a
+(/.) = pzipWith_c (/)
+
+(-.) :: Num a => P a -> P a -> P a
+(-.) = pzipWith_c (-)
diff --git a/Sound/SC3/Lang/Pattern/List.hs b/Sound/SC3/Lang/Pattern/List.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern/List.hs
@@ -0,0 +1,51 @@
+module Sound.SC3.Lang.Pattern.List where
+
+import qualified Data.IntMap as M
+import Data.List
+import Data.Monoid
+import Sound.SC3.Lang.Pattern.Pattern
+import Sound.SC3.Lang.Pattern.Control
+
+pseq_ :: [P a] -> Int -> P a
+pseq_ l n = plist (concat (replicate n l))
+
+pseq :: [P a] -> P Int -> P a
+pseq l n = n >>= (\x -> plist (concat (replicate x l)))
+
+-- | 'n' values from the infinite cycle of the streams at l.
+pser_ :: [P a] -> Int -> P a
+pser_ l n = prestrict_ n (plist l)
+
+pser :: [P a] -> P Int -> P a
+pser l n = prestrict n (plist l)
+
+pswitch :: [P a] -> P Int -> P a
+pswitch l i = i >>= (l !!)
+
+pswitch1m :: M.IntMap (P a) -> P Int -> P a
+pswitch1m m is = let f i js = let h = phead (m M.! i)
+                                  t = ptail (m M.! i)
+                              in h `mappend` pswitch1m (M.insert i t m) js
+                 in pcontinue is f
+
+pswitch1 :: [P a] -> P Int -> P a
+pswitch1 = pswitch1m . M.fromList . zip [0..]
+
+ppatlace :: [P a] -> P Int -> P a
+ppatlace ps n = let is = pseq (map return [0 .. length ps - 1]) pinf
+                in ptake n (pswitch1 ps is)
+
+{-
+
+Neither the definition above or the variant below are correct.
+Both deadlock once all patterns are empty.  pswitch1 has the 
+same problem.  
+
+ppatlacea :: P (P a) -> P a
+ppatlacea ps = 
+    let f p qs = let h = phead p
+                     t = ptail p
+                     rs = qs `mappend` return t
+                 in h `mappend` (ppatlacea rs)
+    in pcontinue ps f
+-}
diff --git a/Sound/SC3/Lang/Pattern/Pattern.hs b/Sound/SC3/Lang/Pattern/Pattern.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern/Pattern.hs
@@ -0,0 +1,167 @@
+{-# LANGUAGE ExistentialQuantification #-}
+
+module Sound.SC3.Lang.Pattern.Pattern
+    ( P
+    , pfoldr, evalP
+    , pfix
+    , pcontinue
+    , pmap -- Prelude.fmap
+    , punfoldr -- Data.List.unfoldr
+    , preturn -- Control.Monad.return
+    , pbind -- Control.Monad.(>>=)
+    , pempty -- Data.Monoid.mempty
+    , pappend -- Data.Monoid.mappend
+    , ppure -- Control.Applicative.pure
+    , papply -- Control.Applicative.(<*>)
+    , prp
+    , pscan
+    , pinf
+    , pzipWith
+    , pcycle
+    , prepeat ) where
+
+import Control.Applicative
+import Data.Monoid
+import System.Random
+
+data P a = Empty
+         | Value a
+         | RP (StdGen -> (P a, StdGen))
+         | Append (P a) (P a)
+         | Fix StdGen (P a)
+         | forall x . Unfoldr (x -> Maybe (a, x)) x
+         | forall x . Continue (P x) (x -> P x -> P a)
+         | forall x . Apply (P (x -> a)) (P x)
+         | forall x y . Scan (x -> y -> (x, a)) (Maybe (x -> a)) x (P y)
+
+data Result a = Result StdGen a (P a)
+              | Done StdGen
+
+step :: StdGen -> P a -> Result a
+step g Empty = Done g
+step g (Value a) = Result g a pempty
+step g (RP f) = let (p, g') = f g
+                in step g' p
+step g (Append x y) = case step g x of
+    Done g' -> step g' y
+    Result g' a x' -> Result g' a (Append x' y)
+step g (Fix fg p) = case step fg p of
+    Done _ -> Done g
+    Result fg' x p' -> Result g x (Fix fg' p')
+step g (Continue p f) = case step g p of
+    Done g' -> Done g'
+    Result g' x p' -> step g' (f x p')
+step g (Unfoldr f x) = let y = f x 
+                       in case y of
+                            Nothing -> Done g
+                            Just (a, x') -> Result g a (Unfoldr f x')
+step g (Apply p q) = case step g p of
+    Done g' -> Done g'
+    Result g' f p' -> case step g' q of
+        Done g'' -> Done g''
+        Result g'' x q' -> Result g'' (f x) (Apply p' q')
+step g (Scan f f' i p) = case step g p of
+    Done g' -> case f' of
+                 Just h -> Result g' (h i) Empty
+                 Nothing -> Done g'
+    Result g' a p' -> let (j, x) = f i a
+                      in Result g' x (Scan f f' j p')
+
+pfoldr' :: StdGen -> (a -> b -> b) -> b -> P a -> b
+pfoldr' g f i p = case step g p of
+                    Done _ -> i
+                    Result g' a p' -> f a (pfoldr' g' f i p')
+
+pfoldr :: Seed -> (a -> b -> b) -> b -> P a -> b
+pfoldr = pfoldr' . mkStdGen
+
+evalP :: Int -> P a -> [a]
+evalP n = pfoldr n (:) []
+
+instance (Show a) => Show (P a) where
+    show _ = show "a pattern"
+
+instance (Eq a) => Eq (P a) where
+    _ == _ = False
+
+-- | Apply `f' pointwise to elements of `p' and `q'.
+pzipWith :: (a -> b -> c) -> P a -> P b -> P c
+pzipWith f p = (<*>) (pure f <*> p)
+
+instance (Num a) => Num (P a) where
+    (+) = pzipWith (+)
+    (-) = pzipWith (-)
+    (*) = pzipWith (*)
+    abs = fmap abs
+    signum = fmap signum
+    fromInteger = return . fromInteger
+    negate = fmap negate
+
+instance (Fractional a) => Fractional (P a) where
+    (/) = pzipWith (/)
+    recip = fmap recip
+    fromRational = return . fromRational
+
+pcycle :: P a -> P a
+pcycle x = x `mappend` pcycle x
+
+prepeat :: a -> P a
+prepeat = pcycle . return
+
+pmap :: (a -> b) -> P a -> P b
+pmap = (<*>) . prepeat
+
+instance Functor P where
+    fmap = pmap
+
+instance Monad P where
+    (>>=) = pbind
+    return = preturn
+
+instance Monoid (P a) where
+    mempty = pempty
+    mappend = pappend
+
+ppure :: a -> P a
+ppure = prepeat
+
+instance Applicative P where
+    pure = ppure
+    (<*>) = papply
+
+-- * Basic constructors
+
+pempty :: P a
+pempty = Empty
+
+preturn :: a -> P a
+preturn = Value
+
+prp :: (StdGen -> (P a, StdGen)) -> P a
+prp = RP
+
+pinf :: P Int
+pinf = return 83886028 -- 2 ^^ 23
+
+pappend :: P a -> P a -> P a
+pappend = Append
+
+type Seed = Int
+
+pfix :: Seed -> P a -> P a
+pfix = Fix . mkStdGen
+
+pcontinue :: P x -> (x -> P x -> P a) -> P a
+pcontinue = Continue
+
+pbind :: P x -> (x -> P a) -> P a
+pbind p f = pcontinue p (\x q -> f x `mappend` pbind q f)
+
+papply :: P (a -> b) -> P a -> P b
+papply = Apply
+
+pscan :: (x -> y -> (x, a)) -> Maybe (x -> a) -> x -> P y -> P a
+pscan = Scan
+
+punfoldr :: (x -> Maybe (a, x)) -> x -> P a
+punfoldr = Unfoldr
diff --git a/Sound/SC3/Lang/Pattern/Random.hs b/Sound/SC3/Lang/Pattern/Random.hs
new file mode 100644
--- /dev/null
+++ b/Sound/SC3/Lang/Pattern/Random.hs
@@ -0,0 +1,43 @@
+module Sound.SC3.Lang.Pattern.Random where
+
+import Control.Monad
+import Data.Array
+import Data.List
+import Sound.SC3.Lang.Pattern.Pattern
+import Sound.SC3.Lang.Pattern.Control
+import Sound.SC3.Lang.Pattern.List
+import System.Random
+
+-- Random numbers
+
+prrandf :: (Random a) => (a -> a -> a -> a) -> a -> a -> P a
+prrandf f l r = prp (\g -> let (x, g') = randomR (l,r) g
+                           in (preturn (f l r x), g'))
+
+prrand :: (Random a) => a -> a -> P a
+prrand = prrandf (\_ _ x -> x)
+
+prrandexp :: (Floating a, Random a) => a -> a -> P a
+prrandexp = prrandf (\l r x -> l * (log (r / l) * x))
+
+pchoosea :: Array Int (P a) -> P a
+pchoosea r = prp (\g -> let (i, g') = randomR (bounds r) g 
+                        in (r ! i, g'))
+
+pchoose :: [P a] -> P a
+pchoose l = pchoosea (listArray (0, length l - 1) l)
+
+prand :: [P a] -> P Int -> P a
+prand p = pseq [pchoose p]
+
+pwhite :: (Random a) => P a -> P a -> P Int -> P a
+pwhite l r n = prestrict n (join (pzipWith prrand l r))
+
+pexprand :: (Floating a, Random a) => P a -> P a -> P Int -> P a
+pexprand l r n = prestrict n (join (pzipWith prrandexp l r))
+
+pxrand :: (Eq a) => [P a] -> P Int -> P a
+pxrand p n = ptake n (prsd (pseq [pchoose p] pinf))
+
+pwrand :: [P a] -> [P a] -> P Int -> P a
+pwrand = undefined
diff --git a/hsc3-lang.cabal b/hsc3-lang.cabal
new file mode 100644
--- /dev/null
+++ b/hsc3-lang.cabal
@@ -0,0 +1,70 @@
+Name:              hsc3-lang
+Version:           0.7
+Synopsis:          Haskell SuperCollider Language
+Description:       Haskell library defining operations from the
+                   SuperCollider language class library
+License:           GPL
+Category:          Sound
+Copyright:         (c) Rohan Drape, 2007-2009
+Author:            Rohan Drape
+Maintainer:        rd@slavepianos.org
+Stability:         Experimental
+Homepage:          http://slavepianos.org/rd/f/649352/
+Tested-With:       GHC == 6.8.2
+Build-Type:        Simple
+Cabal-Version:     >= 1.6
+
+Data-files:        README
+                   -- The below is appended by:
+                   -- find Help -name "*.*hs" | sort | \
+                   -- sed "s/^/                   /" >> hsc3-lang.cabal
+                   Help/Collection/collection.help.lhs
+                   Help/Math/pitch.help.lhs
+                   Help/Pattern/pattern.help.lhs
+                   Help/Pattern/pclutch.help.lhs
+                   Help/Pattern/pcollect.help.lhs
+                   Help/Pattern/pcountpre.help.lhs
+                   Help/Pattern/pdegreeToKey.help.lhs
+                   Help/Pattern/pdrop.help.lhs
+                   Help/Pattern/pexprand.help.lhs
+                   Help/Pattern/pfilter.help.lhs
+                   Help/Pattern/pfin.help.lhs
+                   Help/Pattern/pgeom.help.lhs
+                   Help/Pattern/pif.help.lhs
+                   Help/Pattern/pinterleave.help.lhs
+                   Help/Pattern/pn.help.lhs
+                   Help/Pattern/prand.help.lhs
+                   Help/Pattern/preject.help.lhs
+                   Help/Pattern/prorate.help.lhs
+                   Help/Pattern/prsd.help.lhs
+                   Help/Pattern/pseq.help.lhs
+                   Help/Pattern/pser.help.lhs
+                   Help/Pattern/pseries.help.lhs
+                   Help/Pattern/pstutter.help.lhs
+                   Help/Pattern/pswitch1.help.lhs
+                   Help/Pattern/pswitch.help.lhs
+                   Help/Pattern/ptail.help.lhs
+                   Help/Pattern/ptrigger.help.lhs
+                   Help/Pattern/pwhite.help.lhs
+                   Help/Pattern/pwrap.help.lhs
+                   Help/Pattern/pxrand.help.lhs
+
+Library
+  Build-Depends:   array,
+                   base == 3.*,
+                   containers,
+                   random
+  GHC-Options:     -Wall -fwarn-tabs
+  Exposed-modules: Sound.SC3.Lang
+                   Sound.SC3.Lang.Collection
+                   Sound.SC3.Lang.Math
+                   Sound.SC3.Lang.Pattern
+  Other-modules:   Sound.SC3.Lang.Collection.Collection
+                   Sound.SC3.Lang.Collection.Numerical
+                   Sound.SC3.Lang.Collection.SequenceableCollection
+                   Sound.SC3.Lang.Math.Pitch
+                   Sound.SC3.Lang.Pattern.Pattern
+                   Sound.SC3.Lang.Pattern.Extend
+                   Sound.SC3.Lang.Pattern.Control
+                   Sound.SC3.Lang.Pattern.List
+                   Sound.SC3.Lang.Pattern.Random
