SuperCollider CLASSES (extension)

RecursiveCutProc1

Recursive breakbeat cutting, version 2
Inherits from: BBCutProc : Object

Description

This class implements explicit recursive cutting, as described in LMJ13. The level of recursion can be set as a parameter of the cut procedure. The user chooses cut, repeat and offset functions which are applied through successive iteratinos to make new cut sequences. Only the final cut sequence of a cut sequence of a cut sequence... is rendered.

For additional data on the algorithm see

Nick Collins, "Recursive Audio Cutting",

Leonardo Music Journal 13

Class Methods

*new (cutfunc, repeatfunc, offsetfunc, reclevel: 2, phraselength: 4, bpsd: 0.5)

Create a RecursiveCutProc1 object with the given parameters.

Arguments:

cutfunc

A user specified function determining the next cut size, passed the arguments phrase length filled so far and current phraselength.

repeatfunc

A user specified function determining the number of repeats of the new cutsize, passed the arguments phrase length determined and current phraselength.

offsetfunc

A user specified function determining the offset for the new block, passed the arguments quantise level (= currphraselength/beats per sub division, so one 4/4 bar phrase with bpsd 0.5 gives quantise level of 8, ie eighth notes) ,current beats per sub division,phrase completed so far and current phrase length. The default method is

{arg q,bpsubdiv; rrand(0,q - 1)*bpsubdiv};  //random offset into source
reclevel

Level of recursion, so 0 gives back the source exactly, 1 is one cutup, 4 is four recursive cutups. The higher the reclevel , the greater the performance hit at the start of the phrase. Outside realtime rendering is required for very high values, and the output will be increasingly set on one offset at a greatest common divisor cut size (see the paper for technical analysis). Notes however that the CPU cost is in the language app, not the server. In implicit cutting, the cost is in the Server.

phraselength

Next length of phrase in beats.

bpsd

beats per sub division.

Inherited class methods

Instance Methods

-initRecursiveCutProc1 (cf, rf, of, rl)

Called internally after a new.

-chooseblock

this uses the setoffset method of BBCutSynth to specify offset jumps relative to the current phrase size. In normal use phrasesize will be the same as the beat length of the source you wish to cut up. Note that sources which don't respond to setoffset will not be effected by RecCutProc except for any enveloping/panning etc caused by blocks.

Inherited instance methods

Undocumented instance methods

-calculatecuts (array)

-prepare (array)

Examples

//you must have run this line before any of the examples below
f= BBCutBuffer(Platform.resourceDir +/+ "sounds/break.aiff",8); 


//defaults
BBCut2(CutBuf2(f), RecursiveCutProc1.new).play(2);




(//20 recursion levels with simple user defined functions plus quick delay hack
var sf, group;

group=Group.new;

Routine.run({

//f=BBCutBuffer("sounds/a11wlk01.wav",4); 

s.sync;

BBCut2(CutGroup(CutBuf2(f, pbsfunc:{rrand(0.98,1.02)}),Group.before(group)), RecursiveCutProc1.new({[4.0,2.5,1.5].choose},{rrand(1,3)},{[0.0,2.0].choose},20)
).play(4);

{var in; 

in= In.ar(0,2);

ReplaceOut.ar(0, CombN.ar(0.3*in, 0.25, 0.25, 20, 1, 0.7*in))}.play(group);

});

)



(//recursion level control
var w,slider;
    
w = SCWindow("panel", Rect.new(200,200,200,100));
slider=DDSlider( w, Rect.new(5,5,180,40), "recursion level", 0, 50, 'linear', 1, 0);

w.front;

BBCut2(CutBuf2(f), RecursiveCutProc1.new(reclevel:slider)).play(2);
)


(//user defined functions
var w,slider;
var cutfunc, repeatfunc, offsetfunc;

cutfunc= {arg done, currpl; if((done<(currpl*0.7)), {[1.5,0.5].choose},{[0.25,1.0].choose});};
repeatfunc= {arg done, currpl; if((done<(currpl*0.7)), {1},{rrand(1,3)});};
//3/4 of the time let through what is there already, otherwise a random offset
offsetfunc= {arg q, bpsd, done, currphraselength; if(0.75.coin, {done%(q*bpsd)},{(q.rand)*bpsd});};

BBCut2(CutBuf2(f), RecursiveCutProc1.new(cutfunc, repeatfunc, offsetfunc,3, 8.0)).play(2);
)



//as a comparison, here is the easier but more CPU expensive implicit recursive method
//implicit recursive cutting, nth order

//this code assumes 8 out busses 0-7, 8 in (8-15 = 1-8 for AudioIn UGen)
//then spare audio busses from 16 up

//There will be a delay in hearing output proportional to n since the 
//various audio capture devices need to be capturing a flow before 
//the next can capture a flow, passing down to the final one. 
(
var clock, n;
var source, reccutters;
var group;

group=Group.new;

//number of levels of recursive audio cutting
//be careful, costs go up for large n...
n=4; 

clock= ExternalClock(TempoClock(2.6)).play;

Routine.run({

source=BBCut2(CutGroup([CutBuf2(f),CutMixer(16,1.0,1.0,0.0)],Group.head(group),numChannels:1));

reccutters= Array.fill(n);

n.do({arg i; 
reccutters.put(i, BBCut2(CutGroup([CutStream1((2*i)+16, atkprop:0.02, relprop:0.02),CutMixer((2*i)+18,1.0,1.0,0.0)],Group.tail(group),numChannels:2)));
});

{Out.ar(0,In.ar((2*n)+16,2))}.play(Group.tail(group));

s.sync;
});



//give it all chance to set up- can do without this, just being safe
//Task({
//1.0.wait;
source.play(clock);
reccutters.do({arg val; val.play(clock);});
//nil
//}).start;


)