PR(\defPerc)

A drum machine process that produces sound based on user-defined synthdefs.

Most of the parameters are identical to bufPerc; refer to its help file for details.

Specifying synthdefs

In PR(\defPerc), the ~bufPaths and ~bufCoords parameters are ignored. Instead, the parameter ~objects lists the objects to treat as synthdefs within this process. The parameter may take an array directly, or if the synthdefs will depend on resources that you load in ~postMCCreation, you can provide a function that returns the array. The function will be evaluated after the postMCCreation resources are prepared.

The following objects are supported:

"string" or \symbol: The name of a synthdef that you have already saved in the library using .store or .memStore.

SynthDef(...): The synthdef will be .memStore'd in the library for you.

Function { ... }: Will be converted into a synthdef and .memStore'd.

Patch: Will be converted into a synthdef and .memStore'd. Do not use nested patches.

Specifying synth arguments

The only synth argument automatically sent is \amp. All others must be given in the ~argPairs array, which takes the form [argName0: pattern0, argName1: pattern1 ... ]. The arguments are treated as extra streams for Pbind.

The same ~argPairs array is used for all synthdefs, which assumes that the arguments are more or less compatible across all of them. It is recommended to keep the sounds for a single process relatively similar. The drum machine processes are not polyphonic; you should not expect to layer several sounds within the same process.

Examples

// Synthdefs do not depend on additional resources.

s.boot;

TempoClock.default.tempo = 84/60;

(

PR(\defPerc).chuck(BP(\ex1), parms: (

objects: [

{ |amp = 1, decayscale = 1|

var sig = PinkNoise.ar(amp) * Decay2.kr(Impulse.kr(0), 0.01, 0.05);

sig = Klank.ar(`[

{ rrand(500.0, 1200.0) } ! 5,

{ rrand(0.5, 1.0) } ! 5,

{ rrand(0.4, 0.8) } ! 5

], sig, decayscale: decayscale);

DetectSilence.ar(sig, doneAction: 2);

sig * 0.1 // this synth can be kind of loud

}

],

amps: 0,

ampbase: #[1, 0.6, 0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

argPairs: [decayscale: BPStream(\dscale)],

dscale: Pwhite(0.8, 1.7, inf),

pbindPreAction: {

var pool = (4..15).scramble;

~amps = ~ampbase.copy;

rrand(3, 7).do({ |i|

~amps[pool[i]] = rrand(0.2, 0.7);

});

}

));

)

BP(\ex1).play;

BP(\ex1).stop;

BP(\ex1).free;

// Synthdefs DO depend on additional resources.

// This one loads part of a soundfile and plays it with different kinds of processing.

// Could also be done with \bufPerc if you write custom synthdefs.

(

PR(\defPerc).chuck(BP(\ex2), parms: (

inChannels: 2,

// load special resources here

postMCCreation: { |chan|

~buf = Buffer.readAndQuery(s, "sounds/a11wlk01-44_1.aiff", 4785, 12900);

},

objects: { [

// this shows that the buffer loading (in postMCCreation)

// takes place before synthdef creation

// thus, ~buf is populated by this point

"\nCreating synthdefs.".postln;

// forward with ringmod

{ |amp = 1, rate = 1, pan|

var dur = BufDur.ir(~buf),

sig = PlayBuf.ar(1, ~buf, rate * BufRateScale.ir(~buf)),

sig2 = SinOsc.ar(XLine.kr(ExpRand(300, 900), ExpRand(300, 900), dur));

FreeSelfWhenDone.kr(sig);

Pan2.ar(sig * sig2, pan, amp)

},

// backward with comb filter

{ |amp = 1, rate = 1, pan|

var sig = PlayBuf.ar(1, ~buf, rate.neg * BufRateScale.ir(~buf),

startPos: BufFrames.ir(~buf) - 1),

combDelay = ExpRand(100, 650).reciprocal;

// without LeakDC, DetectSilence never detects silence!

sig = LeakDC.ar(CombL.ar(sig, combDelay, combDelay, Rand(0.1, 0.4)));

DetectSilence.ar(sig, doneAction: 2);

Pan2.ar(sig, pan, amp)

}

] },

ampbase: #[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

amps: 0,

defbase: 0 ! 16,

argPairs: [rate: Pwhite(0.8, 1.25), pan: Pwhite(-1.0, 1.0, inf)],

usedKeys: #[defs],

pbindPreAction: {

var pool = (2..15).scramble;

~amps = ~ampbase.copy;

~defs = ~defbase.copy;

rrand(5, 10).do({ |i|

~amps[pool[i]] = rrand(0.1, 0.5);

// 0 == use forward synthdef; 1 == use backward

~defs[pool[i]] = 0.7.coin.binaryValue;

});

Func(\shrinkKeys).value;

},

// I made the buffer; I have to clean it up

free: { ~buf.free }

));

)

BP(\ex2).play;

BP(\ex2).stop;

BP(\ex2).free;