The process prototype PR defines functionality without any musical data. When you bind musical material to a process prototype, you have a bound process (BP).
PR's cannot be played. BP's can.
Conceptually, a BP is a pattern coupled with all the resources that the pattern needs: buses/groups (or a MixerChannel), buffers, data, control synths, etc. All objects required for a musical behavior should be packaged in the BP. The BP should know how to initialize itself, and clean itself up, so that usage in performance is as simple as possible.
Technically, a BP is a reference to a Proto. The Proto may be given directly, or retrieved from a process PRototype PR -- aProtoOrPR => BP(\name)
.
BP's methods use the following special items in the Proto:
~asPattern
~prep
~freeCleanup
~event
~event
, the \eventKey
entry can retrieve a parent event from chucklib's ProtoEvent collection.~alwaysReset
.play
. Default is false; set to true if you want ~preparePlay
to execute every time the process plays.~preparePlay
~stopCleanup
~onAsStreamError
~asPattern
. This may be: \throw
to throw the error normally; \report
to print the error report and attempt to continue; \warn
to print a simple warning and attempt to continue; or a Function (receiving the error object as argument) for custom error handling.~printStopMsg
~requiredKeys
Note that BP has two pairs of initializers/finalizers: ~prep
and ~freeCleanup
for the instance, and ~preparePlay
and ~stopCleanup
for play-time resources. For the latter, be sure to set ~alwaysReset
to true.
The long syntax of .chuck
makes it easy to fill in parameters in the Proto -- before ~prep
is called, so chuck-time parameters will be available to the Proto's initializer.
Much of BP's functionality is in its Chuck-operator =>
support.
Objects that can be chucked into a bound process:
Processes
These prepare the BP to receive data.
If the BP already holds a process, chucking another BP, PR or Proto will wrap the current process inside the new one, based on the adverb:
=>.wrap
-- default action if no adverb. If the process is already wrapped, remove the current wrapper first. Then add the new wrapper.=>.nest
-- wrap the process, whether it's already wrapped or not.=>.replace
-- replace the current bound process with the new one.It is supported to chuck fully realized BPs into other BPs. The receiving BP gets a copy of the incoming process's Proto. This, for instance, is a way to save the state of a process to reuse.
Quantization factors
nil
(converts to NilTimeSpec)Chucking one of these into a BP defines the default quantization for that process, or for all processes if chucked into the class BP.
Material from MIDI
You can also index a MBM directly: MBM(0)[0] returns the first midi buffer stored in the MBM at index 0. This may then be chucked into the BP. The index may be an integer or symbolic name.
Support patterns
Some processes depend on patterns for various parameters (most importantly, MacRh, MicRh, ArpegPat, Func). Use an adverb to determine which pattern you're sending in.
A Symbol may be used to retrieve a predefined pattern from the Pdefn class; if the Pdefn doesn't exist, the Symbol will be turned into a pattern that outputs itself: Pn(symbol, inf).
BP prefers to use TimeSpecs for scheduling; as noted above, several object types are automatically converted into TimeSpecs. BasicTimeSpec is the most commonly used and corresponds to SC's standard Quant time specifier (but BasicTimeSpec handles leadTime
, discussed next).
Every BP has a property, BP: -leadTime, which pushes the process's scheduling time earlier. This is to ensure that processes providing information to other processes can evaluate first; see PG_06g_Data_Sharing.html: Communicating values between separate event patterns.
In the Data Sharing pattern tutorial, timingOffset
"shifts" the bass pattern's scheduling time, and it needs to be specified every time the pattern is played. In BP, simply set the leadTime once (as a property of the process), and it will take effect every time the process is played.
Note that DelayTimeSpec and AbsoluteTimeSpec do not take a BP's leadTime into account. If you need to use these with leadTime, use DelayTimeSpecLeadTime and AbsoluteTimeSpecLeadTime instead.
Get or set the default leadTime for new BPs. Normally this should be 0. The default leadTime is assigned when the BP is created. Changing the default will not affect any BPs that already exist.
Get or set the default clock. If a clock is not assigned within the process, it will revert to the default clock. Changing the default will affect existing BPs.
The default clock may be set by chucking: aClock => BP
.
Get or set the default quant. The default is used in BP: -quant, so changing the default will affect existing BPs.
The default quant may be set by chucking any of the objects described under "Quantization factors" about into the BP class itself: timeSpec => BP
.
Get or set the default event. If a BP does not specify an event prototype (normally, it will), the default event will be applied at play time.
A Boolean, determining the behavior if a BP() object is dragged into a Voicer GUI. If true, the BP will play using the proxy represented in the GUI (and, changing the voicer in the GUI will change the sound); if false, it will use the Voicer to which the proxy is pointing (and, changing the voicer in the GUI will not change the sound). Default is true
.
Largely deprecated. A Function returning a clock, applied when binding a Proto to the BP.
Begin playing the process at the time indicated by argQuant
, on the clock argClock
. If the process is being reset (or it is the first time to play it), the Proto object's preparePlay
pseudo-method will be called as an initializer.
argQuant |
The quantization factor describing the onset time. See above. If not given, play time will fall back to the BP's |
argClock |
The clock on which to play. If not given, it will fall back to the BP's |
doReset |
If true, call BP: -reset on the process before playing. Default is false. |
notify |
If true, issue a |
Stop the process at the time indicated by argQuant
. Also calls the associated Proto object's stopCleanup
pseudo-method as a finalizer.
argQuant |
The quantization factor describing the stop time. See above. If not given, stop time will fall back to the BP's |
Stop the process immediately. Normally you will not use this method directly. BP: -stop calls this method internally.
adhoc |
A process may need to stop an old Proto object, which used to be associated with this BP but was replaced. Use with caution. This is not typical usage; it is for internal use and regular users should avoid it. |
quant |
A timespec that will be passed to the "adhoc"'s stopCleanup pseudo-method. Internal use. |
notify |
If true, send the |
doCleanup |
If true, execute the "adhoc"'s stopCleanup action. Default is true. |
notifyTime |
A clock time to pass with the |
At the specified argQuant
time, fetch one event from the process's event stream and play it. This is useful for on-demand (rather than time-driven) sequencing.
You may need to call BP(\name).prepareForPlay
before trying triggerOneEvent
.
argQuant |
The quantization factor describing the onset time. See above. If not given, play time will fall back to the BP's |
argClock |
The clock to use for scheduling. If not given, it will fall back to the BP's |
doReset |
If true, call BP: -reset on the process before getting the event. Default is false. |
Removes the BP instance for garbage collection. Also calls the associated Proto object's freeCleanup
pseudo-method. If the process is playing, it will be stopped first.
Resets the process. The current event stream will be discarded and recreated. Also calls the Proto object's reset
and preparePlay
pseudo-methods.
Schedules BP: -reset to be called at a time given by argQuant
.
argQuant |
The quantization factor describing the reset time. See above. If not given, reset time will fall back to the BP's |
Normally internal use; however, in specific cases (typically BP: -triggerOneEvent), you may need to call it manually.
argQuant |
If the process was already playing, the old event stream player needs to be stopped. This is a timespec describing the time when that should happen. |
argClock |
The clock used for scheduling the termination of the old event stream player. |
doReset |
If true, call BP: -reset. Default is false. |
Playing/stopped status.
Boolean, true if the process is playing.
Get or set the process's clock. Typically setting the clock is done by chucking instead: aClock => BP(\name)
.
cl |
The new clock (normally a TempoClock). |
The BP's clock instance.
Get or set the process's default timespec. Typically setting the timespec is done by chucking instead: timeSpecOrShortcut => BP(\name)
.
argQuant |
Anything that responds to |
The current default quant.
A number, in clock beats, for early scheduling. See BP: Scheduling above.
lat |
How early to schedule? |
The current leadTime (number).
2018-10-11: Previously, leadTime
could be set only when the process was stopped. As of now, you can set it at any time. If the process is playing, the new leadTime
will take effect at the next barline (defined by the process's BP: -quant). Use BP: -setLeadTime to override the barline.
Changing leadTime
while playing requires the stream to be reset -- use caution. However, in some live coding contexts, it may be impossible to determine all leadTimes in advance, and necessary to change them on the fly.
Set the leadTime
at some arbitrary quant
timepoint. See BP: -leadTime for details. (The only difference in this method is the additional quantize argument.)
lat |
How early to schedule? |
q |
A |
If the process is playing, this returns the time of the next event (compatible with Thread and PauseStream's nextBeat
methods).
Calculates the next scheduling time for the given timespec, taking BP: -leadTime into account. This is used internally to resolve all "quant" references; normally you will not need to use it, but you can use it to predict when something should happen.
argQuant |
The quantization factor describing the scheduling time. See above. If not given, it falls back to the BP's |
The clock time (in absolute beats).
Test whether the process is ready to play. The normal test is to check whether all of the ~requiredKeys
are populated. You can override the default test by assigning a function: BP(name).canStream = { ... }
.
Boolean: true if the process is ready; false if not.
A convenience method to set the Voicer. It does two things: 1. Store the voicer object in the BP's ~event
under \voicer
. 2. Call the Proto's bindVoicer
pseudo-method (so that the BP can do something upon receipt of a Voicer).
This method is called whenever you chuck a Voicer, VoicerProxy or VC.
vc |
A Voicer, VoicerProxy or VC. |
Create and return the event stream player (really, an instance of BlockableEventStreamPlayer). Normally, you will not need to use this method directly.
A BlockableEventStreamPlayer.
Calls the Proto's ~asPattern
pseudo-method and returns the pattern object.
A Pattern.
Protos may be nested: a BP's Proto may contain another Proto, in the ~child
variable. This is meant to support various kinds of hierarchical behavior. For instance, PR(\macroRh) is a chord player where the outer Proto chooses properties of the harmony, and the inner Proto chooses the specific notes and arpeggiates them according to predefined note orderings (ArpegPat) and rhythms (MicRh).
Wrapping behavior is determined by the adverb given to the chuck operator, e.g., newProto =>.nest BP(\name)
.
Adverb | Method | Description |
\nest | BP: -wrap | BP's current Proto goes into the new Proto's ~child . If done multiple times, the hierarchy goes several layers deep. |
\wrap or none | BP: -rewrap | If the BP is already wrapped, replace the outer layer (but don't make the hierarchy any deeper). If not wrapped, same as \nest . |
\overwrite | BP: -overwrite | Throw away the current Proto and replace it with the new one. |
\relate | (none) | Put the chucked Proto into the current BP as \subordinate . Then this BP can do other operations on the subordinate. |
The new Proto being chucked in may set a flag, ~doReplay
. If true, and the BP is playing, the process will call BP: -replay to continue. If false, the BP will be stopped.
The following methods are mainly for internal use, to support the above chuck operations.
If the process is not wrapped, wrap it; if it is wrapped, strip out the old wrapper and wrap the child in the new. If you only ever use this one, the hierarchy will be at most two levels.
process |
The new Proto. |
doReplay |
A Boolean: true means, if playing, keep playing; false means, stop playing. |
Always wrap the current hierarchy in one more layer.
process |
The new Proto. |
doReplay |
A Boolean: true means, if playing, keep playing; false means, stop playing. |
Remove the entire current hierarchy and replace it with the incoming Proto. Most likely, the hierarchy will then have a depth of 1. Always tries to replay.
process |
The new Proto. NOTE: A comment in the source code says "this method is not fully supported yet." Use at your own risk. |
Remove the outer layer of the hierarchy, and set the BP's proto to (what was) the ~child
. This method is the only way to do this; there is no corresponding chuck operation.
doReplay |
A Boolean: true means, if playing, keep playing; false means, stop playing. |
The Proto that was the parent, before unwrapping.
Following is a very basic usage of BP. The possibilities are nearly limitless; it's impractical to provide examples of everything you can do. I might add more examples later, but time doesn't permit at the moment.