Overview of Item Streams

Heinrich Taube

Zentrum fuer Kunst und Medientechnologie
Ritterstr. 42
7500 Karlsruhe 1
Germany
		
		Mail: hkt@zkm.de
		Fax: +49 721 9340 39 
		Vox: +49 721 9340 300

___________________________________________________________

Introduction

An item stream is an object that organizes data into patterns.  The behavior of an item stream is controlled by two attributes: its data type (the type of data the stream contains as its items) and its pattern type (the pattern its data are organized in):

	         Pattern Type  Data Type
	               \       /
	              Item Stream

For example, the cycle pattern and the note data type are mixed together by the system to produce the class description of cyclic-note-stream.

	         Cycle      Note
	            \       /
	         Cyclic-Note-Stream

There are currently nine predefined data types: amplitude, item, note, degree, pitch, rhythm, interval, step and number, and nine predefined pattern types: accumulation, cycle, function, graph, heap, random, palindrome, rotation and sequence. A number of data types have related functionality.  The note, pitch and degree types all describe different aspects of musical scale degrees.  Inteval, and step describe relative scale motion.  Several of the pattern types are broadly related as well.  For example, the heap and random patterns both use random element ordering, and the cycle and sequence patterns both access elements in a determined, linear order.

Working With Item Streams

Working with item streams is no different than working with any other type of composite lisp data.   A comparison between item streams and lisp lists can illustrate this point. In order to work with lisp lists, a list is first created using one of the list constructor functions supplied by lisp.  In the example below, we assign the variable x to a list of five integers we create using the constructor function list:

<cl> (setf x (list 1 2 3 4 5))
(1 2 3 4 5) 

Once the list is created, we can access its various elements using any number of lisp accessor functions such as car, cdr, first, etc.:

<cl> (first x)
1 

<cl> (nth 3 x)
4 

<cl> (car (cddr x))
3

Item streams are manipulated in exactly the same manner that lisp lists are: constructors create them and accessors access their elements:

<cl> (setf x (items 1 2 3 4 5))
#<CYCLIC-ITEM-STREAM 131352561> 

<cl> (item x)
1 
NIL 

In this example, the constructor items creates an item stream and the accessor item reads an item from it.  The item function will read an element from any type of item stream. In addition to item, the accessor read-items will read a full period length of items from a stream and return the results in a list:

<cl> (setf x (steps 1 2 3 4 5 in random 
                              from (notes c4 d e)
                              for 8 returning pitch))
#<RANDOM-STEP-PITCH-STREAM 132406461> 

<cl> (read-items x)
(261.62555 311.127 391.99554 415.30484 440.00018 466.16397 
	   493.88358 523.2511) 

The Recursive Nature of Item Streams

Each element of data (called an item) in an item stream may be an atomic, irreducible element or else a recursively embedded item stream.  An embedded item stream serves to delimit a subpattern in the encompassing stream.   For example, the form:

<cl> (setf x (notes C4 (notes D3 D5 in random for 5) E 
                    in cycle))
#<CYCLIC-NOTE-STREAM 137025511> 

describes a cyclic note stream with three items. The first item is the note C4. The second item is an embedded random item stream that itself has 2 items and a period length of 5. The third element in the cycle is the note E4:

<cl> (read-items x)
(C4 D5 D3 D3 D5 D3 E4) 

As another example:

<cl> (setf x (notes (notes c1 d e) (notes c2 d e)
                    (notes c3 d e) (notes c4 d e)
                   in heap))
#<HEAP-NOTE-STREAM 132717641> 

describes a heap (a type of random ordering) of cyclic item streams. Note that if an item steam constructor does not specifically indicate a pattern type, the system uses the cycle pattern as the default pattern type:

<cl> (read-items x 24)
(C1 D1 E1 C3 D3 E3 C4 D4 E4 C2 D2 E2 C1 D1 E1 C2 D2 E2 C4 
    D4 E4 C3 D3 E3) 

Item Streams Periodicity

All item streams have a period length.  A period length may be constant or may vary over time.   The length of a period determines the number of elements to be accessed in the current period.  The number of items returned in the period is the sum of all the period lengths of all the elements accessed. This distinction between period length and the number of items returned follows from the fact that items streams respect the pattern descriptions of their sub patterns. That is, a sub pattern that has a period length of 3 is considered to be a single choice by its superior stream.  In the case of a stream that contains only atomic data, the period length and the number of elements returned will be the same.  But if the stream has recursive sub streams the period length is likely to be different than the number of elements returned.

Creating Item Streams, The Item Stream Constructor Macros

Item streams are created by using system supplied constructor macros.  In lisp, a constructor creates objects.  For example, the item stream constructor macro notes creates an item stream specifically designed to return a scale's notes' names as the elements of some specified pattern.  The name of each constructor macro is always the plural form of the data type it implements: items, notes, degrees, rhythms, intervals, steps and series. For example:

<cl> (setf x (notes c4 d e f in random for 8))
#<RANDOM-NOTE-STREAM 136354031> 

is an example of the constructor macro notes being used to create a random patterned note stream with a period length of 8.  Once we have constructed the stream we can access its elements:

<cl> (read-items x)
(F4 C4 D4 E4 D4 C4 D4 C4) 
 
Similarly,

<cl> (setf x (rhythms q w e s in cycle tempo 90))
#<CYCLIC-RHYTHM-STREAM 136531621> 

is an example of the constructor macro rhythms creating a cyclic patterned rhythm stream with a tempo factor of 90:

<cl> (read-items x)
(0.6666667 2.6666667 0.33333334 0.16666667) 

Item Stream Constructor Syntax

The item stream constructor macros all share the same simple pseudo-english syntax: the name of the macro is followed by one or more item specifications followed by zero or more item stream constructor options. The constructor options allow various attributes of the item stream to be customized to a particular situation. In the previous example:

<cl> (setf x (rhythms q w e s in cycle tempo 90))

the name of the macro is rhythms, the item specification is q w e s and the options are in cycle and tempo 90.  Each option is actually a pair: an option name followed by an option value  In the previous example:

<cl> (setf x (rhythms q w e s in cycle tempo 90))

the first option has the name in and the value cycle, and the second option has the name tempo and the value 90. See the section "Item Stream Options" for further information.

A more formal way of stating the argument syntax:

{item}+  {option}*

where {item}+ is one or more elements to be included in the stream and {option}* is zero or more item stream constructor options.

Item Steam Pattern Types

Pattern types are methods used by item streams to generate data.  Each pattern type generates elements in a different manner. All item stream constructors such as items, notes, rhythms, etc., permit the specification of a pattern type as part of the item stream description. A particular pattern type is specified by the option:

in pattern

where pattern is one of the 8 predefined pattern types: accumulation, cycle, function, graph, heap, random, and sequence.  For example:

<cl> (items Moe Curley Larry in heap)
#<HEAP-ITEM-STREAM 131207741> 

creates an item stream that organizes its data, the symbols Moe, Curley and Larry, in a heap pattern.

Pattern specification in constructor macros is always optional.  If no pattern is supplied then the default pattern type cycle is used.

See the dictionary entries: accumulation, cycle, function, graph, heap, palindrome, random and sequence for complete details on pattern types.

Reading Items From Item Streams

Once an item stream has been created by using one of the constructor macros its elements may be read from the stream with the generic function item. item returns two values: the element read from the stream and a status flag indicating the current state (if any) of the stream as a result of reading the element.  As with all multiple items in lisp, this second value may simply be ignored if it is not relevant to the caller.

The function read-items reads an optionally specified number of items from a stream and return the elements in a list.  If no number is supplied, read-items will return all the elements in the stream's current period.

See documentation on item and read-items for further information.

Using Item Streams Inside Score Part Definitions

Item streams may be used to organize parameter data for score parts.  The with-part macro provides several extensions to normal Common Lisp syntax that facilitates a tight integration between item streams and score parts that use them.  The major points to remember are:

A part may be automatically terminated at the end of one or more periods of an item stream.

Item stream constructors appearing inside calls to the item function are treated as constant streams.

Macros such as unless-chording and unless-resting allow a part to conditionalize actions based on the current status of some item stream.

In general, item streams in parts behave exactly as described in the section "Working With Item Streams".   However, a brief example will serve to illustrate the three points listed above:

(in-syntax :musicKit)

(defscorefile ()
  (with-part Fm1viPoly ()
    (setf freq (item (notes c4 [d f a] e) :kill t))
    (unless-chording
      (setf rhythm (item (rhythms q e h))))))

In this example the part Fm1viPoly sets its frequency parameter to successive items in a stream of notes.  The first element in this stream is middle c, the second element is a d minor chord (delineated using the [] macro) and the third element is the note middle e. When there are no more elements left in the note stream's period, the :kill t argument to item will automatically terminate the part.  The rhythm slot is also set by reading succesive values from an item stream, but it is wrapped inside the unless-chording macro to insure that its the second rhythm is distributed across all the elements in the chord.  If unless-chording were not used, the first element of the chord would receive a quater note rhythm, the second an eighth note and the third a half note rhythm.  Note that in this with-part example, the notes constructor for the note stream is written inside the call to the item function. (Compare this to the examples in the "Working With Item Streams" section.)  Normally in lisp, this syntax would not have the intended effect of setting the freq parameter to consecutive elements read from an item stream because notes is a constructor.  That is, every time the item function would try to read an element, the notes macro would normally create a new item stream!  The item function would therefore access the first item of a freshly created stream each time it was evaluated.  The with-part macro insures that item streams appearing as constant expressions inside a call to item will be allocated only once, when the part is first created.  Note that item stream constructors appearing in other contexts or at top level lisp will behave in their normal manner.  This is a feature, not a bug.  For further information, see the documentation on parts and with-part.  

Item Stream Constructor Options

Item stream constructor options follow the data description of the stream, and may be specified in any order.  For example:

<cl> (rhythms q w e s in cycle tempo 90)
#<CYCLIC-RHYTHM-STREAM 131337701> 

<cl> (rhythms q w e s tempo 90 in cycle)
#<CYCLIC-RHYTHM-STREAM 131343501> 

create identical item streams. Option specification is optional in the sense that there are default system values for every unspecified option.  For example:

<cl> (setf x (rhythms q w e s))
#<CYCLIC-RHYTHM-STREAM 131334101> 

creates a cyclic rhythm stream because no pattern option is specified and the default pattern type is cycle. This stream also has a default tempo value of 60 and a default period length of 4 items.

For any constructor macro the complete set of item stream constructor options depends upon the data type and the pattern type being described.  

The following constructor options are appropriate for all 
item stream constuctor macros:

in pattern

The in option associates a pattern type with the new item stream. If in is not supplied the default pattern type of cycle is used.  Legal pattern specifications to in are: cycle, sequence, heap, palindrome, accumulation, function, graph, and random.

for period

The for option associates a period length with the new item stream.  The period length may be greater or less than the number of elements in the stream.  If the value is a number then the item stream will have a constant period length.  If the value is an item stream of numbers, then the period length of the stream can vary over time, according to the pattern generated by the period stream. The value of for is always evaluated.

named name

The name option allows a name to be associated with the new item stream.  A named item stream is may be subsequently referenced using the #@ motive construct.  

The following options are specific to all the note and 
interval streams constructors: notes, degrees, pitches, intervals, steps.

of scale

The of option allows a scale to be associated with the new note or interval stream.  Its value must be a scale object created by the defscale macro.  If of is not supplied the scale used by the new stream will default to the value of *standard-scale*. The initial value of *standard-scale* is the standard chromatic scale, C00 to B9.

The following options are specific to all the interval stream constructors: intervals, steps.

from interval or scale degree reference

The from option allows a transposition offset to be associated with any type of interval stream. The value may be an interval, scale degree reference or item stream. If the offset is specified as an item stream then an interval or step stream will select a new offset at the beginning of each new periodon interval or scale degree reference

Similar to from exept that the offset is incremented in parallel to the selection.  This is useful for "harmonizing" the offset stream.

returning note or pitch

The returning option forces any type of interval stream to coerce its values into absolute note or pitch references.  The value of returning is never evaluated and should be one of the unquoted symbols: Pitch or Note.

The following option is specific to rhythm streams:

tempo number or tempo function

The tempo option allows a constant or variable tempo to be associate with the new stream.  The value is either a metronome number or a tempo envelope.  If the tempo option is not supplied the tempo will default to the value of the variable *standard-tempo*, which is initially metronome 60.  See documentation on the tempo function for further details.

The following options are specific to all random and heap 
patterns, regardless of data type.

using random-state object

The using option allows a specific random state object to be associated with the new stream.  If using is not supplied, its value defaults to the random-state object contained in the variable *cm-state*.

The following option is specific to the palindrome pattern, regardless of data type.

elidid t or nil

The elided option determines if the first and last data elements are directly repeated as the pattern reverses directon.  The default value of elided is nil, which means that the terminal elements are repeated when the pattern wraps around.

The following options are specific to the graph pattern, regardless of data type.

first id

The first option sets the initial element to be considered in the graph.  The specified id is unevluated, and must be a valid node identifier from the data description of the stream.  If first is not supplied, it defaults to the first element in the data description.

with function

The with option is used to specify a graph node selection fuction to the new stream.  This function takes two arguments, the current node and the item stream, and should return the id of the next node to be generated by the stream.

The following option is specific to the function pattern, regardless of data type.

with function

The with option is used to specify a function name or function object for the new stream.  This function takes no arguments and should return a list of stream elements each time it is called at the beginning of each new period.  The
function is also allowed to return a non-list value, in which case it will be the single element in a period of length 1.  It is an error to return no elements.

Item Stream Examples

Examples demonstrating simple pattern generation techniques using item streams and algorithms can be found in the file stella/examples/item-streams.stella.