To extend BBCut with your own cut procedures and effects, it's important to get an understanding of how BBCut works.
An instance of BBCut2
is a player for algorithmically splicing audio. A BBCut player consists of cut synthesizers and a cut procedure.
A cut procedure acts as a sequencer, while the cut synthesizers deal with audio and effects.
The atomic unit of music in BBCut is the cut. Cuts are events where a segment of a buffer is played.
A block is a stream of one or more cuts with a restriction: all cuts within the same block must start at the same playback position in the buffer. A block wih more than one cut is a sort of "stutter" effect.
A phrase is one or more blocks. Typically, a phrase lasts several bars of 4/4.
A BBCutBuffer is an ordinary buffer with a number of roughly equally spaced marks. Each of these marks is a single beat.
Beats are used to keep track of timing in BBCut, but the beats provided by ExternalClock are different from beats in the buffer. To avoid confusion, I will use the terms "clock time" and "buffer time."
Blocks are represented by BBCutBlock
objects. Here are the properties of BBCutBlocks that you should know about.
offset
is the playback starting position of all cuts in this block. This is measured in buffer beats.cuts
is an array that describes the cuts within the block. Each cut is represented by an array of the form [ioi, dur, offsetparam, amp]
, whereioi
stands for "inter-onset interval," representing the time until the next cut measured in clock beats.dur
is the amount of time the cut spends playing, measured in buffer beats.offsetparam
is an argument that will be passed to a CutBuf* instance. We'll get to this one later. Most cut procedures set this to nil.amp
is the amplitude of the cut. Most cut procedures set this to 1.length
is the temporal duration of this block, measured in clock beats.blocknum
is the position of this block in the phrase. A blocknum of 0 means the first block in the phrase, and so on.phrasepos
is the amount of time in clock beats since the start of the phrase. phraseprop
is a number from 0 to 1 indicating how far we are in the phrase.isroll
is a flag that marks this block as a "roll." There are no technical differences between a roll and a non-roll, but some parts of BBCut give rolls special treatment.There are no objects dedicated to phrases or cuts. Instead, properties of the block object keep track of them.
Often, the offset
parameter of the BBCutBlock is set to nil. In this case, the offset is the amount of time in clock beats since the beginning of the phrase, modulo the length of the buffer in buffer beats.
That last sentence is important. Make sure you understand it!
Perhaps an example will help. Suppose you have a buffer divided into four beats, and a cut procedure produces a phrase comprised of five blocks with offsets set to nil, and the following cuts:
Then you will hear, in order:
Here is a visualization, showing the color-coded buffer and the remixed version:
In this case, the clock tempo is slower than the buffer tempo. The clock tempo can also be faster than the buffer tempo, in which case the samples will overlap.
Cut procedures are block factories. They are subclasses of BBCutProc.
A cut procedure produces a block via the instance method chooseblock
. Due to some strange architectural decisions, chooseblock
does not actually create and return a BBCutBlock object. Instead, the cut procedure must set some publicly readable instance variables. The getBlock
instance method of BBCut2 creates the BBCutBlock object and copies properties from the cut procedure to the block. See the following code, simplified from getBlock
Even worse, some of the cut procedure properties are inconsistently named compared to the block properties. I will eventually fix these weird decisions.