ProtoEvent(\symbol) -- automatic
Playing an event pattern requires an event prototype. (Note that an event prototype is not the same as the object prototype implemented by proto.) The event pattern -- produced by the as pattern method in a chucklib process -- does nothing more than insert values into the event prototype under specific names. It's the event prototype that defines how to interpret the data from the pattern and take whatever action is required.
When you play a BP, it updates the event belonging to the process with the latest definition from the ProtoEvent repository.
Proto({
~event = (eventKey: \default);
}) => PR(\generic);
eventKey: \default means that at play time, all the definitions in ProtoEvent(\default) will be added to the ~event, and the updated event will be used to play the process' pattern. (Technical detail, skip if not interested: the proto event is actually set as the parent of the event Event so that the items in the proto event do not have to be copied every time the pattern evaluates.)
An event prototype must have a function assigned to the play key. If you don't want the event to play anything per se, you can provide a dummy like 1 (which does nothing when .value'd).
(play: #{ /* do something in here */ }) => ProtoEvent(\uselessEvent);
To use a ProtoEvent outside the BP framework, get a copy of it:
// returns a copy of the Event stored at ProtoEvent(\default)
ProtoEvent(\default).copy
Composite ProtoEvents
If the pattern needs to use different proto events at different times in the same pattern, a composite proto event may be used.
The pattern should then place the name of the proto event into the protoEvent key for each event. The correct proto event will be chosen on a per event basis.
(play: { ~number.debug("ProtoEvent(\a)") }) => ProtoEvent(\a);
(play: { ~number.debug("\tProtoEvent(\b)") }) => ProtoEvent(\b);
ProtoEvent.composite([\a, \b]) => ProtoEvent(\composite);
Proto({
~event = (eventKey: \composite);
~asPattern = {
Pbind(\number, Pseries(1, 1, inf), \protoEvent, Prand(#[\a, b], inf), \delta, 0.5)
};
}) => BP(\comp);
BP(\comp).play;
BP(\comp).stop;
BP(\comp).free;
Scheduling of server events within event prototypes
If you need server messages from custom event prototypes to sound in sync with the default event, the messages must be sent in the proper way.
The default event uses a number of parameters to adjust timing:
~lag: delay this event by this number of beats; may be different for each event
~timingOffset: delay by this number of beats; this is intended only to compensate for scheduling a process' thread slightly early to simulate higher priority for the process. See the discussion of leadTime in the [BP] helpfile.
~server.latency: apply this many seconds of latency to the outgoing OSC message, solely for the purpose of controlling network timing jitter.
Functions in the default event handle these parameters correctly. The same functions are available in the Func repository. If you are sending OSC messages in your event prototype, you should use these functions to ensure consistent timing with other event prototypes.
Func('schedEventBundle').value(time, server, bundle)
e.g.,
Func('schedEventBundle').value(~lag, ~server, [message1...], [message2...])
time: ~lag value plus whatever adjustment in beats is needed
server: the server to receive the message
bundle: one or more arrays containing OSC messages
Func('schedEventBundleArray').value(time, server, bundleArray)
e.g.,
Func('schedEventBundleArray').value(~lag, ~server, [[message1...], [message2...]])
The above two functions handle most needs. Optionally, when scheduling notes, the following may be used.
Func('schedEventStrummedNote').value(lag, strumTime, sustain, server, msg, sendGate)
lag: ~lag time (beats)
strumTime: used by the default event prototype when scheduling a chord; the notes may be offset from each other by ~strum beats
sustain: how long (in beats) the note should last
server: the server to receive the message
msg: the message to send; it must be a /s_new message
sendGate: a Boolean flag; if true, send a release message after sustain beats; if false, do not send a release (the synth node is expected to free itself)