BP:
Filter:
ddwChucklib/Classes (extension) | Libraries > ChuckLib > Objects

BP
ExtensionExtension

A "bound process" (process prototype bound to musical data)

Description

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).

NOTE: See BP: Chuck support and BP: Scheduling for important background information. These sections are, in some ways, more important than the method documentation, but they are forced to appear at the bottom.

PR's cannot be played. BP's can.

BP structure

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
A function to create the pattern object to play. Mandatory. This is the most important element!
~prep
A function to run when the Proto is chucked in. Use this to allocate the process's resources.
~freeCleanup
A function to run when freeing the BP. Use this to destroy the resources.
~event
The event prototype that will be used during play. You can pre-populate it with fixed values. Within the ~event, the \eventKey entry can retrieve a parent event from chucklib's ProtoEvent collection.
~alwaysReset
A Boolean: true means to reset the process on every .play. Default is false; set to true if you want ~preparePlay to execute every time the process plays.
~preparePlay
A function to run before play time. Use this for temporary resources.
~stopCleanup
A function to run when the process stops.
~onAsStreamError
(Optional, rarely used.) In special cases, you might want to error handling for errors in ~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
(Optional, rarely used.) If the process stops by itself (because it ran out of events), often this indicates a bug in the pattern definition, so the normal behavior is to print a warning in the post window. Set this to false to suppress the warning.
~requiredKeys
An Array of Symbols, naming Proto variables that must be populated before play. If any is empty, a warning will be printed and the process will not play. A useful safety check, but optional.

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.

Chuck support

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:

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

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).

Scheduling

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.

Class Methods

.defaultLeadTime

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.

.defaultClock

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.

.defaultQuant

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.

.defaultEvent

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.

.useVoicerProxy

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.

.defaultInitClock

Largely deprecated. A Function returning a clock, applied when binding a Proto to the BP.

Instance Methods

.play

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.

Arguments:

argQuant

The quantization factor describing the onset time. See above. If not given, play time will fall back to the BP's quant or BP.defaultQuant, successively. BP: -leadTime will be applied automatically, if appropriate for the timespec.

argClock

The clock on which to play. If not given, it will fall back to the BP's clock or BP.defaultClock.

doReset

If true, call BP: -reset on the process before playing. Default is false.

notify

If true, issue a changed(\play, goTime) notification. Default is true.

.stop

Stop the process at the time indicated by argQuant. Also calls the associated Proto object's stopCleanup pseudo-method as a finalizer.

Arguments:

argQuant

The quantization factor describing the stop time. See above. If not given, stop time will fall back to the BP's quant or BP.defaultQuant, successively.

.stopNow

Stop the process immediately. Normally you will not use this method directly. BP: -stop calls this method internally.

Arguments:

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 changed(\stop, \stopped, notifyTime) notification based on "adhoc." Default is true.

doCleanup

If true, execute the "adhoc"'s stopCleanup action. Default is true.

notifyTime

A clock time to pass with the \stop notification.

.triggerOneEvent

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.

Arguments:

argQuant

The quantization factor describing the onset time. See above. If not given, play time will fall back to the BP's quant or BP.defaultQuant, successively.

argClock

The clock to use for scheduling. If not given, it will fall back to the BP's clock or BP.defaultClock.

doReset

If true, call BP: -reset on the process before getting the event. Default is false.

.free

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.

.reset

Resets the process. The current event stream will be discarded and recreated. Also calls the Proto object's reset and preparePlay pseudo-methods.

.resetq

Schedules BP: -reset to be called at a time given by argQuant.

Arguments:

argQuant

The quantization factor describing the reset time. See above. If not given, reset time will fall back to the BP's quant or BP.defaultQuant, successively.

.prepareForPlay

Normally internal use; however, in specific cases (typically BP: -triggerOneEvent), you may need to call it manually.

Arguments:

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.

.isPlaying

Playing/stopped status.

Returns:

Boolean, true if the process is playing.

.clock

Get or set the process's clock. Typically setting the clock is done by chucking instead: aClock => BP(\name).

Arguments:

cl

The new clock (normally a TempoClock).

Returns:

The BP's clock instance.

.quant

Get or set the process's default timespec. Typically setting the timespec is done by chucking instead: timeSpecOrShortcut => BP(\name).

Arguments:

argQuant

Anything that responds to asTimeSpec.

Returns:

The current default quant.

.leadTime

A number, in clock beats, for early scheduling. See BP: Scheduling above.

Arguments:

lat

How early to schedule?

Returns:

The current leadTime (number).

Discussion:

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.

.setLeadTime

Set the leadTime at some arbitrary quant timepoint. See BP: -leadTime for details. (The only difference in this method is the additional quantize argument.)

Arguments:

lat

How early to schedule?

q

A quant parameter specifying when to update the leadTime. This should be in the future.

.nextBeat

If the process is playing, this returns the time of the next event (compatible with Thread and PauseStream's nextBeat methods).

.eventSchedTime

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.

Arguments:

argQuant

The quantization factor describing the scheduling time. See above. If not given, it falls back to the BP's quant or BP.defaultQuant, successively.

Returns:

The clock time (in absolute beats).

.canStream

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 = { ... }.

Returns:

Boolean: true if the process is ready; false if not.

.voicer

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.

Arguments:

vc

A Voicer, VoicerProxy or VC.

.asEventStreamPlayer

Create and return the event stream player (really, an instance of BlockableEventStreamPlayer). Normally, you will not need to use this method directly.

NOTE: This method changes the BP's internal state.

Returns:

A BlockableEventStreamPlayer.

.asPattern

Calls the Proto's ~asPattern pseudo-method and returns the pattern object.

Returns:

A Pattern.

.asStream

Gets the BP's pattern from BP: -asPattern and makes a stream from it.

Returns:

A Stream.

Wrapping support

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).

AdverbMethodDescription
\nestBP: -wrapBP's current Proto goes into the new Proto's ~child. If done multiple times, the hierarchy goes several layers deep.
\wrap or noneBP: -rewrapIf the BP is already wrapped, replace the outer layer (but don't make the hierarchy any deeper). If not wrapped, same as \nest.
\overwriteBP: -overwriteThrow 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.

NOTE: The simple nesting case in this example is extensively tested. Other permutations are not heavily tested and may not be reliable.

The following methods are mainly for internal use, to support the above chuck operations.

.rewrap

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.

Arguments:

process

The new Proto.

doReplay

A Boolean: true means, if playing, keep playing; false means, stop playing.

.wrap

Always wrap the current hierarchy in one more layer.

Arguments:

process

The new Proto.

doReplay

A Boolean: true means, if playing, keep playing; false means, stop playing.

.overwrite

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.

Arguments:

process

The new Proto.

NOTE: A comment in the source code says "this method is not fully supported yet." Use at your own risk.

.unwrap

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.

Arguments:

doReplay

A Boolean: true means, if playing, keep playing; false means, stop playing.

Returns:

The Proto that was the parent, before unwrapping.

Examples

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.