    :cubed       7
    })
 
-
-(defn- shape->id
+(defn- curve->shape-id
+    "Map curve to envelope shape. If curve is a keyword, look it up in
+     ENV-SHAPES, otherwise assume it to be the generic cuve shape id of
+     5"
+    [curve]
+    (get ENV-SHAPES curve 5))
+
+(defn- curve->curve-id
+    "Map curve to curve id. If curve is a keyword, assume the curve id
+     is a generic shape (0) otherwise, preserve curve id"
+    [curve]
+    (if-let [id (get ENV-SHAPES curve)]
+      0
+      curve))
+
+(defn- curves->shape-ids
   "Create a repeating shapes list corresponding to a specific shape type.
   Looks shape s up in ENV-SHAPES if it's a keyword. If not, it assumes the
   val represents the bespoke curve vals for a generic curve shape (shape
   type 5). the bespoke curve vals aren't used here, but are picked up in
   curve-value.
   Mirrors *shapeNumber in supercollider/SCClassLibrary/Common/Audio/Env.sc"
-  [s]
-  (if (keyword? s)
-    (repeat (s ENV-SHAPES))
-    (repeat 5)))
-
-(defn- curve-value
-  "Create the curves list for this curve type. For all standard shapes this
+  [curves]
+  (cycle (map curve->shape-id curves)))
+
+(defn- curves->curve-ids
+  "Create the curves id list for the specified curves. For all standard shapes this
   list of vals isn't used. It's only required when the shape is a generic
   'curve' shape when the curve vals represent the curvature value for each
   segment. A single float is repeated for all segments whilst a list of floats
   can be used to represent the curvature value for each segment individually.
   Mirrors curveValue in supercollider/SCClassLibrary/Common/Audio/Env.sc"
-  ;;
-  [c]
-  (cond
-   (sequential? c)  c
-   (number? c) (repeat c)
-   :else (repeat 0)))
+  [curves]
+  (cycle (map curve->curve-id curves)))
+
 
 ;; Envelope specs describe a series of segments of a line, which can be used to automate
 ;; control values in synths.

   * :sine              - sinusoidal S shaped segments.
   * :welch             - sinusoidal segments shaped like the sides of a
                          Welch window.
   * a Float            - a curvature value to be repeated for all segments.
   * an Array of Floats - individual curvature values for each segment.
                          Positive numbers curve the segment up whilst
                          negative numbers curve the segment down.

   If a release-node is specified (an integer index) the envelope will sustain
   at the release node until released which occurs when the gate input of the

   through and a list of durations (the duration in time of the lines
   between each point).

   Optionally a curve or list of curves may be specified. A single
   curve (as a keyword or float) will be repeated for all segments. A
   list of keywords or floats will be cycled through for all segments.

   Options are:

   * :step              - flat segments
   * :linear            - linear segments, the default
   * :exponential       - natural exponential growth and decay. In this
