Event

superclass: Environment

related classes: Pattern

Class variables

defaultParentEvent the default event used in most cases

parentEvents an IdentityDictionary of useful parent events

partialEvents an IdentityDictionary of Events that define the default values and functions

for different aspects of note generation (timing, volume, pitch, server to use, etc)

Class methods

*new { | n, proto, parent, know = true) create an event

*default returns an empty event with defaultParentEvent as parent

*silent (dur) returns an event that describes a pause

*addEventType(type, func) Event types define alternate play functions that

are selected by the value of ~type

Methods

play play the event

delta returns a time delay until the next event in a sequence

next used to enable events to be composed

Methods that allow Events to provide user control for Synths on Groups

synth makes the event a control interface to the resultant synth when played

group makes the event a control interface to the resultant group when played

stop free the synth or group

pause pause the synth or group

resume resume the synth or group

release release the synth or group

set set a control value in the synth or group

An Event is an Environment that specifies an action to be taken in response to a play message.

The key/value pairs within the Event specify the parameters of that action.

Event provides a defaultParentEvent that defines a variety of different event types and provides

a complete set of default key/value pairs for each type. The type is determined by the value of the

key \type which defaults to \note. Note events create synths on the server.

Events can be written as a series of key value pairs enclosed in parentheses. Empty parentheses

will create an empty event.

( ).play; // the default note

( freq: 500, pan: -1) .play; // 500 Hz, panned left

( degree: (0..12)).play // a whole tone cluster

Events and SynthDefs

The key used to select what synthdef is to be played is \instrument. In order to use a SynthDef with an Event, send

it a store message. This creates a description of the SynthDef that the event can consult to determine its control names.

The values of these names in the event are used when the event is played. (See SynthDesc for details.)

SynthDef("pm", { | out=0, freq=440, amp=0.1, pan=0, gate=1, ratio = 1, index = 1, ar = 0.1, dr = 0.1 |

var z;

z = LPF.ar(

PMOsc.ar(freq, freq * ratio, Linen.kr(gate, ar,index, dr), 0, 0.3),

XLine.kr(Rand(4000,5000), Rand(2500,3200), 1)

) * Linen.kr(gate, 0.01, 0.7, dr, 2);

OffsetOut.ar(out, Pan2.ar(z, pan, amp));

}).store;

(instrument: "pm").play;

(instrument: "pm", ratio: 3.42, index: 12, freq: 150, ar: 8, dr: 3, sustain: 10).play;

note: The use of OffsetOut in the SynthDef prevents artifacts that can result from the interaction of the timing of a sequence of notes and

the control rate of the Server.

Events and Patterns

Events are closely integrated with the Patterns library. Different patterns can be bound to different keys (or collections

of keys) to specify the resultant music. See the help files Pattern and Pbind and the tutorials [Streams-Patterns-Events4]

and [Streams-Patterns-Events5] for more details on Patterns.

Here is an example that illustrates some of the keys defined by the defaultParentEvent.

(

p = Pbind(*[

stepsPerOctave: Pstep(Pseq((2..12).mirror, inf),12), // 3 - 12 tone e.t. scales

note: Pseq((0..12).mirror, inf),

ctranspose: Pwhite(-0.2, 0.2), // detune up to +-20 cents

detune: Pwhite(-1.0, 1.0), // detune up to 1 Hz

sustain: Prand([0.2, 0.2, 0.2, 4], inf), // notes last 0.2 or 4 seconds

dur: Prand([0.2, 0.2, 0.2, 0.2, 0.2, 0.8], inf), // 1 in 6 chance note lasts 0.8 seconds

db: Pstep( // 4 beat accent structure

Pseq([-15, -25, -20, -25], inf),

0.8

)

]);

p.play

)

Event's play method

When an Event (or any other Environment) receives a use(function) message, it sets itself to be

currentEnvironment, evaluates the function, and restores the original value of currentEnvironment.

This allows the function to access and alter the contents of the event using the following shortcuts:

~keyName which is equivalent to currentEnvironment.at(keyName)

and

~keyName = value which is equivalent to currentEnvironment.put(keyName, value)

We will write ~keyName whenever referring to the value stored at the key keyName in the event.

Here is the definition of Event's play method:

play {

if (parent.isNil) { parent = defaultParentEvent };

this.use { ~play.value };

}

Thus we can see that the defaultParentEvent is used unless otherwise specified and the function

stored in ~play is executed in the context of the Event.

Timing control with Event's delta method

Events also specify timing within a Pattern. Event's delta method returns the value of ~delta or,

if that is nil, ~dur * ~stretch.

Patterns are played by TempoClock' s, which have their own tempo controls. This tempo which can be

controlled through ~tempo in the event. Changes to the tempo affect everything else scheduled by the

TempoClock, so tempo provides a global tempo control while stretch provides a control limited to the

one pattern.

The structure of defaultParentEvent

The default parent event provides the collection of default values and functions needed for the different uses of an Event.

These defaults are defined in partialEvents that specify distinct aspects of default parent Event:

playerEvent defines ~play, ~type and ~eventTypes

serverEvent server, group, addAction

durEvent duration, tempo and articulation

ampEvent volume, pan, MIDI velocity

pitchEvent pitch specified in many different ways

bufferEvent buffers on the server

midiEvent midi

Useful keys for notes

Using Events is largely a matter of overwriting keys. Here is a list of keys useful for defining notes with their default values,

grouped by the partialEvent within which they are defined.

The keys in serverEvent provide the values needed to identify the server to be used and where in the tree

of nodes to place the group.

serverEvent keys:

server: nil, // if nil, Server.default is used

instrument: \default, // this is the name of a SynthDef

group: 1, // nodeID of group on the server

// whening adding before or after a node

// this could be the nodeID of a synth instead of a group

addAction: 0, // 0, 1, 2, 3 or \addToHead, \addToTail, \addBefore, \addAfter

out: 0, // usually an output bus number, but depends on the SynthDef

The ampEvent determines volume. Notice that ~amp is a function that determines its value from ~db.

The user can choose to specify the amplitude directly by overwriting ~amp or to use a decibel specification

by overwriting ~db.

ampEvent keys:

amp: #{ ~db.dbamp },

db: -20.0,

pan: 0.0,

The durEvent has keys that determine the timing of a note. Notice that ~sustain is a function that uses

~legato to determine the sustain. Like ~amp this can be overwritten to set the sustain directly.

durEvent keys:

tempo: nil, // changes tempo of a TempoClock

dur: 1.0, // delay until next note

stretch: 1.0, // inverse of tempo control, specific to the Event's stream

legato: 0.8, // ratio of sustain to duration

sustain: #{ ~dur * ~legato * ~stretch },

lag: 0.0, // delay relative to current time position of Stream

strum: 0.0 // "breaks" a chord

The pitchEvent has the most complex system of functions that provide a variety of useful ways to determine

pitch:

~freq determines the pitch directly as a frequency in Hertz

~midinote determines pitch as a fractional MIDI note (69 -> 440)

~note determines pitch as a scale degree in an ~stepsPerOctave equal tempered scale

~degree determines pitch as a scale degree within the scale ~scale

The event also provides a set of transposition keys

~mtranspose modal transposition of degree within a scale

~root transposes root of the scale

~gtranspose gamut transposition within the~stepsPerOctave equal tempered scale

~ctranspose chromatic transposition within the 12 tone equal tempered scale

~harmonic multiplies the frequency determined by ~midinote, typically to an overtone

~detune directly alters frequency

pitchEvent keys:

mtranspose: 0, // modal transposition of degree

gtranspose: 0.0, // gamut transposition of note within a ~stepsPerOctave e.t. scale

ctranspose: 0.0, // chromatic transposition of midinote within 12 tone e.t. scale

octave: 5.0, // octave offest of note

root: 0.0, // root of the scale

degree: 0, // degree in scale

scale: #[0, 2, 4, 5, 7, 9, 11], // diatonic major scale

stepsPerOctave: 12.0,

detune: 0.0, // detune in Hertz

harmonic: 1.0, // harmonic ratio

note: #{

(~degree + ~mtranspose).degreeToKey(~scale, ~stepsPerOctave);

},

midinote: #{

((~note.value + ~gtranspose + ~root) / ~stepsPerOctave + ~octave) * 12.0;

},

freq: #{

(~midinote.value + ~ctranspose).midicps * ~harmonic;

},

Event types

An Event responds to a play message by evaluating ~play in the event Here is a slightly simplified version of the default definition of ~play:

{ ~eventTypes[~type].value(server); },

The function uses the value of ~type to select a function from the dictionary held in ~eventTypes.

The collection of eventTypes can be readily extended using *addEventType(key, function).

Here is an example the uses the event types \group and \note:

(type: \group, id: 2).play // create a group with nodeID 2

(type: \note, freq: 500, group: 2).play // play a synth in that group

Here is a listing of currently existing event types:

group creates group, id must be specified

note instrument specifies synthdef

note_score

midi

monoNote

monoSet

monoOff

on play synth, id must be specified

off release synth (or free if no gate)

kill free synth

set set parameter of synth

bus write ~array to control buses starting at ~out

alloc allocate ~bufnum with ~numframes and ~numchannels

free free ~bufnum

gen send ~gencmd to ~bufnum

load load ~filename starting at ~frame into ~bufnum

read

setProperties ~receiver, ~args

sends setter messages to ~receiver for each key in ~args that

has a nonNil value in the Event

tree creates a tree of groups. ~tree can be an array of nodeIDs, and may contain associations to further nested arrays.

phrase instead of playing a single synth from a SynthDef with ~instrument, it looks up a Pdef and plays a cluster of sounds.