A quick tour of Item Streams

by Fernando Lípez Lezcano (nando@ccrma.stanford.edu)
ã 1991, CCRMA, Stanford University 

Introduction

One of the most important tools you have available in Common Music is the pattern generation capabilities of item streams. This will attempt to provide a short description with small examples on how to use different capabilities of the item stream pattern generator.

After this short introduction you can find all the details in two documents: ªoverview.wnº (reference manual of the Common Music language), and ªdictionary.wnº (detailed description of all the available functions, macros and variables).

Item Streams

An item stream is a Common Music object that organizes data into patterns. There are two components that must be mixed to define the behavior of an item stream. The first is the data type that the item stream manipulates and the second is the pattern in which that data is organized.

The data types currently supported are:

items
notes
pitches
rhythms
degrees
intervals
steps
viocings
series
amplitudes

and the patterns inwhich these data can be organized are

cycle
sequence
heap
random
palindrome
function

As with any lisp object, you will need to learn how to create an item stream and how to access its elements. The simplest way to create an item stream is to use the appropriate constructor macro. The constructor macro is the blender we use to create an item stream with the proper  data type and pattern type.

The name of the constructor macro is the name of the data type you are going to use. Since we are going to work with numbers the appropriate macro is called ªitemsº. Let's create a cyclic item stream that holds the numbers 1, 2 and 3:

<cl> (setf x (items 1 2 3 in cycle))
#<CYCLIC-ITEM-STREAM 137427041> 
<cl> 

Now we have defined a new global variable called ªxº that holds our item stream. The data type is ªitemsº, the pattern type is ªcycleº and the items contained in it are ª1 2 3º. The idea behind item streams is to organize data in complex ways and then access that data in a very simple way. The standard function you can use to access the next available item within an item stream is called ªitemº.

<cl> (item x)
1 			<--- returned item
NIL 
<cl> 

The cycle pattern selects the elements in the order specified when the item stream was created. After the item stream returns the last element it selects again the first and so on (in our example the sequence of numbers returned should be ª1 2 3 1 2 3 1...º). Now execute the function item two more times:

<cl> (item x)
2 			<--- returned item
NIL 
<cl> (item x)
3 			<--- returned item
:END-OF-PERIOD 	<--- state flag
<cl> 

Note that the item function is always returning two values. We normally want to use only the first value, which is the selected item. The second value is the state of the item stream. After we extracted the third element this state changed to :END-OF-PERIOD telling us that we have reached the end of a period of the item stream. The next time we access the item stream we will get the first element again. Let's do it:

<cl> (item x)
1 
NIL 
<cl> 

If you don't specify otherwise, the period of an item stream is equal to its number of elements. There is a Common Music function that calls the item function until the end of the period is reached and returns a list with all the elements. It is called read-items. 

<cl> (read-items x)
(2 3) 
<cl> (read-items x)
(1 2 3) 
<cl> 

The first call to read-items read the remainder of the period (remember that the result of our last item call was ª1º). Keep in mind that the item stream always remembers which was the last element accessed. The second call returned a list with the whole period. We can change the period explicitly using the for option in the constructor macro:

<cl> (setf x (items 1 2 3 in cycle for 5))
#<CYCLIC-ITEM-STREAM 131272111> 
<cl> (read-items x)
(1 2 3 1 2) 
<cl> 

Now a period spans 5 elements instead of the default value of 3. Note that the pattern has not changed. The selection process for the next item follows the same cyclic behavior as before.

Recursive item streams

One of the most interesting properties of item streams is that any element contained in an item stream can be another item stream!. 

<cl> (setf x (items 1 2 (items 10 11 12) in cycle))
#<CYCLIC-ITEM-STREAM 136177001> 
<cl> (read-items x)
(1 2 10 11 12) 
<cl> 

Note the result. The period spanned the periods of both item streams. We can of course change the period of the enclose stream to ª1º:

<cl> (setf x (items 1 2 (items 10 11 12 for 1) in cycle))
#<CYCLIC-ITEM-STREAM 136210451> 
<cl> (read-items x)
(1 2 10) 
<cl> (read-items x)
(1 2 11) 
<cl> (read-items x)
(1 2 12) 
<cl> (read-items x)
(1 2 10) 
<cl> 

This time the behavior is different. The inner item stream has a period of 1 and the outer cycles through 3 items each time. The third item, always fetched from the inner item stream follows its own cyclic pattern from call to call!. Not only the items can be item streams. The period itself can be an item stream as in the following example:

<cl> (setf x (items 1 2 (items 10 11 12 for 1) in cycle for (items 1 2 3)))
#<CYCLIC-ITEM-STREAM 136233471> 
<cl> (read-items x)
(1) 
<cl> (read-items x)
(2 10) 
<cl> (read-items x)
(1 2 11) 
<cl> (read-items x)
(1) 
<cl> 

In this case the length of the period itself is changing from period to period. But the pattern in which elements are selected has not changed from the last example.

The sequence pattern

The sequence pattern reads all its items until it reaches the last one. Then it continues selecting the last element forever. 

(items 1 2 3 in sequence)
returned elements --> 1 2 3 3 3 3 3 ...

The sequence pattern makes more sense when the last element is not a number, but an item stream:

(items 1 2 3 (items 10 11 12 in cycle) in sequence)
returned elements --> 1 2 3 10 11 12 10 11 12 10 ...