Tuesday, August 03, 2010

Event

The most important subclass of Dictionary is Event:

(
 var evt;
 evt = Event.new;
 evt.play;
)

Much like Arrays can be declared just by square brackets, Events can be declared just with parenthesees:

( ).play;

The sonic results of that line of code might sound familiar to you:

Pbind.new.play

This is not a coincidence! Patterns create Events and play them sequentially. Compare:

Pbind(\freq, 660, \pan, -1).play

and

(freq: 660, pan: -1).play

Note that the syntax for the Event is (key: value, key2: value2) . You can have as many key: value pairs as you want. In the example above, freq and pan are both symbols, both in the Pbind and the event.

Events are Dictionaries and they are created with a bunch of default keys and values. Although, you can use any sort of object as the key for a Dictionary, you should only use symbols as keys for an Event.

The Pbind modifies elements of a default Event and then plays the results of that. To find out what interesting thigns can be changed in an Event, (and therefore also in a Pbind), check out it's helpfile, specifically the section called "Useful keys for notes."

In your Pbind, you can get access to the current event:

(
 Pbind(
  \freq, Pseq([550], 1),
  \event, Pfunc({ |evt|
     evt[\freq].postln;
    })
 ).play
)

The current event is passed as an argument to the function in Pfunc and also the one in Prout. Here, we have created a key, \event, that doesn't have meaning to the Synth, nor to the Event. This is allowed. For example:

(
 Pbind(
  \freq, Pseq([550], 1),
  \foo, \bar
 ).play
)

Every time the Pbind makes an event, it goes through the list of keys and values in the order that it recieves them. For example:

(
 Pbind(
  \event, Pfunc({ |evt|
     "Pan before: %".format(evt[\pan]).postln;
    }),
    
  \pan, Pseq([-1], 1),
  
  \event2, Pfunc({ |evt|
     "Pan after: %".format(evt[\pan]).postln;
    })
 ).play
)

The first postln prints out 0, because that's the default value for \pan. The second postln prints out -1. Then it goes back to the first one because the Pbind does not run out the Pseq returns a nil.

Let's make the duration depend on the frequency:

(
 Pbind(
  \freq, Prand([440, 550, 660, 770], 10),
  \dur, Pfunc({ |evt|
   
     var dur;
     
     dur = evt[\freq] / 1000
    })
 ).play
)

Events are one way you can tie together two keys in an event. You can also do this with arrays:

(
 Pbind(
 
  [\freq, \dur],
   Prout({
    var arr, freq, dur;
    
    arr = [440, 550, 660, 770];
    
    10.do({
     
     freq = arr.choose;
     dur = freq / 1000;
     
     [freq, dur].yield;
    })
   })
 ).play
)

Two or more keys can be grouped together in an array. Then, the stream, which can be a Prout, a Pfunc or any other P-thing, must return an array which is the same length as the key array. The first item in the returned array gets paired with the first item in the key array, the second item goes with the second key and so forth.

Summary

  • Event is a subclass of Dictionary.
  • You can declare an event by just using parenthesis.
  • You should only use Symbols as keys for Events.
  • Patterns work by creating events over and over again.
  • You can access events in Pfunc. It's passed to the function as an argument.
  • You can use keys in your Event or Pbind that are not meaningful to the Pbind, the Even or the Synth.
  • Events can be used to tie together two different elements in a Pbind.
  • Arrays can also be used to tie together two different elements in a Pbind.

4 comments:

J. Simon van der Walt said...

Useful posting, thanks!

Aris Bezas said...

Thanks!

Andrew Kaiser said...

Hello: these are very useful tutorials, thank you for publishing. I do have a question..I'm very new to all this, and I am also looking at cSound. In the cSound score, I can define the start of an event as a fixed point in the overal time of the piece say, at 3 seconds, do this...at 15.5 seconds, do that). Is there a similar concept in SC? I see things like patterns with wait times (all very cool)...maybe I need to change my way of thinking about organizing events also.

Again, thanks very much for this blog.

Charles Céleste Hutchins said...

I think this is an example of where SuperCollider and cSound have different philosophies.

It's possible to time things using a Ptpar, but if you try to schedule too many Events that way, you can eventually cause the Event queue to overflow. Otherwise, you can use subtraction to figure out how long to pause between items in a Pseq.

If you want to do things in non-real time, check out the Score object.

Otherwise, this is one place where the language does tend to share the output.