Next Chapter
Previous Chapter
Table of Contents

Loading, Browsing and Listening

This chapter introduces a few basic editor operations. See the help texts on load, list, show and mix for complete information.

Load

First, use load to load the first example into Stella.

[The opus1.cm example file is located in the same directory as this tutorial. On a Macintosh you can load files using the "Load..." File menu item.. If you prefer typing file names remember that the directory delimiter is `:' rather than `/' on the Mac.]

Stella [Top Level]: load /Lisp/cm/doc/tutorials/stella/opus1
Loading /Lisp/cm/doc/tutorials/stella/opus1.cm
Syntax set to MIDI
Stella [Top-Level]: 
load loads a Lisp file. By default load looks for .cm archive files. Archive files contain Lisp code that recreates the archived objects.

List

Use list to display the current contents of the editor:

Stella [Top-Level]: list
Top-Level:
      1.    #<THREAD: Pulse>
      2.    #<ALGORITHM: Sinus>
Stella [Top-Level]: 
If list is invoked without any arguments the current focus object is listed. The current focus is Top-Level, a system container holding all the named objects currently defined. There are currently two objects, a thread named Pulse and an algorithm named Sinus. list prints the name of the listed container in the first column, and each indented line shows the position and the object at that position in the listed container (the #<> delimiters always indicate an object of some sort.

Show

Now take a closer look at each object:

Stella [Top-Level]: show pulse,sinus

Object:   Pulse
Type:     Thread
Status:   Normal
Objects:  80
Start:    unset

Object:   Sinus
Type:     Algorithm
Status:   Normal
Code:
(algorithm sinus midi-note
           (length 80 amplitude 0.5 rhythm 0.1 duration 0.1)
  (setf note
        (round (rescale (sin (* 2pi (/ count length) 4))
                        -1
                        1
                        20
                        100))))

Stella [Top-Level]:
Show prints information about an object. The first three lines include the name of the object, its class and its current status (an object might be "hidden", "deleted" or "frozen", etc.) Following the basic information comes information specific to the type of object shown. For threads, this information includes the current output start time and the number of sub-objects that the thread contains. For algorithms, the information includes a "pretty printed" version of the algorithm's program.

Listening to Output

Next, listen to each of the objects separately:

Stella [Top-Level]: open midi port a
Stream: #<Port: Midi to A>.

Stella [Top-Level]: mix pulse
Start time offset: (<cr>=None) 1
Stella [Top-Level]:

[Sound starts after 1 second.  Wait until the example is though before continuing.]
Stella [Top-Level]: mix sinus 1
[Sound starts after 1 second.]
Stella [Top-Level]:

Open

Common Music defines musical input and output in terms of "event streams". An event stream is a named connection to some resource, for example a file on disk or a MIDI driver. Use open to create or initialize a stream. When a stream is opened it becomes the default destination for processing commands like Mix and Seq. It is not necessary to open a stream each time musical material is sent to it. It is also not necessary to close a stream after output has finished. The system container Io-Streams holds all the event streams currently defined. You can examine the contents of this container using the list command.

Here are a few examples of using open to initialize various types of event streams:

Open MIDI on port A: open midi port a
Open a CLM sound file: open /zap/test.snd srate 44100
Open a CMN postscript file: open aaa.eps size 16 metronome 120
Open a CSound score file: open test.sco orchestra "test.orc"
Open a CLM score file: open test.clm

Mix

Mix sends musical output to the currently open output stream. Mix processes one or more containers in parallel such that their combined musical events are sent to the stream in the proper, time sorted order. Mix uses a merge object to mix musical output. You can use a merge explicitly as part of your own compositional structure.

There are several commands similar to mix. Seq processes objects in sequential, rather than parallel, order. Seq prompts for the number of times to sequence the objects and an optional pause amount between repetitions. As you may have guessed, seq uses a thread to process its material. The commands Write, Swrite, Listen, and Slisten are also similar to Mix and Seq. They are available for historical reasons, and require that you distinguish between types of streams. Avoid using them because they will be removed in some future release.

Listening to Multiple Containers

Next, listen to both objects in parallel:

Stella [Top-Level]: mix pulse,sinus
Start time offset: (<cr>=None) <cr>
[output messages elided]
Stella [Top-Level]:
Now offset Sinus by two seconds relative to Pulse:

Stella [Top-Level]: mix pulse,sinus
Start time offset: (<cr>=None) *
Start time offset for Pulse: (<cr>=None) <cr>
Start time offset for Sinus: (<cr>=None) 2
[output messages elided]
Stella [Top-Level]: 
Now repeat the example, but specify offsets directly on the command line:

Stella [Top-Level]: mix pulse,sinus 0,2
[output messages elided]
Stella [Top-Level]: 
Start time offsets specified to Mix and Seq affect the current processing pass only. A single offset becomes the global offset for all the objects. A sequence of offsets (delimited by comma) will be applied to a corresponding sequence of object in left to right order. If * is specified you will be prompted for each offset. In addition to their obvious compositional role, offsets are useful for solving problems related to real time processing. Sometimes a complex algorithm will not be able to "keep up" with the speed at which it schedules output. Providing a start time offset will give the algorithm that much "head start" before output starts sounding.

About Time

Common Music supports two clock modes, seconds and millisconds. When the clock mode is seconds (the default) then time is expressed using floats or integers where 1.0 or 1 means one second. In millisecond clock mode, time is expressed using integers where 1000 means one second. Millisecond clock mode is slightly less intuitive but results in "conless" time calculations when running the scheduler in real time. For more information abut clock modes see Working with Algorithms in Real-Time and clock-mode for more information.

In adddition to clock time, output streams may have time scalers associated with them. This scaler is normally set to 1, so time can usually be thought of as clock time.

When musical processing is initiated by commands like mix or seq, the associated event stream first resets its clock to zero before musical events are processed. As each event is processed its time slot is "stamped" with the current time. Every object in Stella has a time slot as one of its basic attributes. Instead of setting time directly, the composer sets either start time offsets for containers or relative time increments for musical data, using the rhythm slot that all data objects possess. A rest object may be used anywhere to increment time without sound output.

More About Referencing

The ability to select objects according to musically salient criteria is one of the nicest features of Stella. We next use the list command to learn a bit about object referencing. See Command References for a complete discussion of referencing objects in commands.

In this next example we look inside Pulse, a thread containing eighty midi notes.

Stella [Top-Level]: list pulse
Pulse:
      1.   #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0>
      2.   #<MIDI-NOTE | D4| 0.100| 0.100| 0.321| 0>

[listing elided]

     49.   #<MIDI-NOTE | G4| 0.100| 0.100| 0.250| 0> 
     50.   #<MIDI-NOTE |GS4| 0.100| 0.100| 0.321| 0> 
More unlisted objects.
Stella [Top-Level]:
Note that when midi-note objects are listed they do not look like threads or algorithms. The format of a midi-note display is:

    #<MIDI-NOTE |note|rhythm|duration|amplitude|channel>
Note is the frequency of the midi note, rhythm is the time increment to the next note, duration is the amount of time the note sounds, amplitude is a logical amplitude 0.0<=1.0 or MIDI velocity 0<=127 and channel is its MIDI channel >=0. See the midi-note for a full explanation of midi notes.

Only certain types of objects, called containers, have names. Howver, all objects have a position relative to some container, if only the Top-Level container. The focus object provides a context for selecting objects by position. For example, the contents of Pulse can also be listed by specifying Pulse's position in the current focus container (Top-Level):

Stella [Top-Level]: list 1
Pulse:
      1.    #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0>
      2.    #<MIDI-NOTE | D4| 0.100| 0.100| 0.321| 0>
[listing elided]
Stella [Top-Level]:
In general, we can replace the name of an object by its path relative to another object. So in the examples that follow the index 1 may be substituted for the name Pulse and 2 may be substituted for the name Sinus as long as we remain inside the Top-Level container.

Referencing Sub-Objects

What if we only wanted to see a subset of Pulse, for example, just the first element?

Stella [Top-Level]: list 1[1]
Pulse:
      1.    #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0>
Stella [Top-Level]:
Sub-object references are specified using an array-like syntax

    container[ref]
where container is the name (or position) of a container and ref is the sub-object specification. For example, Pulse[1]is a reference to the first object in Pulse, and Pulse[1:10,15] is a reference to objects 1 to 10 and 15. Each element of the reference inside [] can be specified using (up to) four fields delimited by colon:

[low:high:step:width]
where low is the low bound of the reference, high is the inclusive upper bound, step is the stepping increment between low and high, and width is the number of sub-objects to reference in parallel.

It is only necessary to specify as many fields as are needed to adequately describe the reference. The editor currently distinguishes between five types of references:

Shorthand Notation

Because sub-object notation can get so complex, Stella supports a few notational shortcuts. The character * is used to designate either an upper index or all the sub-objects. If * is used by itself it stands for all the sub-objects. If * appears as the upper bound it stands for the last object. The token end may also be used to refer to the last object in a container. End also supports "subtraction", i.e. end-4 references the 4th-from-last object.

Reference fields may be elided if the default value for that field applies, in which case only the delimiter for that field need be specified. The default values for the fields are 1:*:1:1. So, for example, ::2 means the same as 1:*:2 and defines an iteration over every other sub-object; :56::4 defines a four element group ranging over the first fifty-six objects.

A Few Referencing Examples

To see the first three elements of Pulse:

Stella [Top-Level]: list 1[1:3]
Pulse:
     1. #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0> 
     2. #<MIDI-NOTE | D4| 0.100| 0.100| 0.321| 0> 
     3. #<MIDI-NOTE | C5| 0.100| 0.100| 0.393| 0> 
Stella [Top-Level]: 
To list every third element between the first and the tenth elements of Pulse:

Stella [Top-Level]: list Pulse[1:10:3]
Pulse:
     1. #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0> 
     4. #<MIDI-NOTE | G4| 0.100| 0.100| 0.464| 0> 
     7. #<MIDI-NOTE |GS4| 0.100| 0.100| 0.679| 0> 
    10. #<MIDI-NOTE | C4| 0.100| 0.100| 0.321| 0> 
Stella [Top-Level]: 
To list the first, fifth through tenth, and sixteenth element of Pulse:

Stella [Top-Level]: list Pulse[1,5:10,16]
Pulse:
     1. #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0> 
Pulse:
     5. #<MIDI-NOTE | D4| 0.100| 0.100| 0.536| 0> 
     6. #<MIDI-NOTE | G4| 0.100| 0.100| 0.607| 0> 
     7. #<MIDI-NOTE |GS4| 0.100| 0.100| 0.679| 0> 
     8. #<MIDI-NOTE |GS4| 0.100| 0.100| 0.750| 0> 
     9. #<MIDI-NOTE | C4| 0.100| 0.100| 0.250| 0> 
    10. #<MIDI-NOTE | C4| 0.100| 0.100| 0.321| 0> 
Pulse:
    16. #<MIDI-NOTE |GS4| 0.100| 0.100| 0.750| 0> 
Stella [Top-Level]: 
To compare the first two objects with the last two:

Stella [Top-Level]: list 1[1:2], 1[end-2:end]
Pulse:
     1. #<MIDI-NOTE | C5| 0.100| 0.100| 0.250| 0> 
     2. #<MIDI-NOTE | D4| 0.100| 0.100| 0.321| 0> 
Pulse:
    79. #<MIDI-NOTE |AS4| 0.100| 0.100| 0.679| 0> 
    80. #<MIDI-NOTE | G4| 0.100| 0.100| 0.750| 0> 
Stella [Top-Level]: 
To list from the seventy-fifth position to the end of Pulse:

Stella [Top-Level]: list Pulse[75:*]
Pulse:
    75. #<MIDI-NOTE | C5| 0.100| 0.100| 0.393| 0> 
    76. #<MIDI-NOTE | G4| 0.100| 0.100| 0.464| 0> 
    77. #<MIDI-NOTE |AS4| 0.100| 0.100| 0.536| 0> 
    78. #<MIDI-NOTE | C5| 0.100| 0.100| 0.607| 0> 
    79. #<MIDI-NOTE |AS4| 0.100| 0.100| 0.679| 0> 
    80. #<MIDI-NOTE | G4| 0.100| 0.100| 0.750| 0> 
Stella [Top-Level]:

Referencing Containers vs. Sub-objects

Some commands interpret unqualified container names as a reference to all the sub-objects. For example, list treats pulse and pulse[*] identically. Other commands operate on containers and their sub-objects independently. For example, hide can mark either a container or its sub-objects as unavailable for output (it is much more efficient to hide a container than to hide all its sub-objects individually).

Next Chapter
Previous Chapter
Table of Contents

Last Modified: 6-Mar-1998