LocalBuf allocate a buffer local to the synth

superclass: UGen

*new(numFrames, numChannels)

return a new buffer – the ugen outputs its buffer number and can thus be used in

any other ugen that requires a buffer number input.

numFrames number of frames (default: 1)

numChannels number of channels for multiple channel buffers (default: 1)

*newFrom(list)

return a new buffer from a given list of values. The list may be two-dimensional for numChannels > 1.

It is then reshaped into the buffer's current format by flattening.

Since newFrom is called by the as message, one may thus convert an array to a LocalBuf:

[1, 2, 3].as(LocalBuf)

set(list, offset)

set the buffer slots with a list of values. If list is smaller than numFrames, it will only set

part of the buffer. The list may be two-dimensional for numChannels > 1.

offset is the starting index (default: 0)

clear set the buffer slot to zero. This is important when randomly acessing buffer slots

(e.g. with a BufRd) or not overwriting them. Clear is not an efficient real time operation

for larger buffers, so it should be only used when really needed - but then it is essential:

a LocalBuf is "created" in each new synth, and it may reuse old space. So if an older

synth has already ended, this part of memory may be the same as the new synth's.

see also SetBuf, ClearBuf

// example: FFT

(

{

var in, chain;

in = WhiteNoise.ar(0.1.dup);

chain = FFT({LocalBuf(2048, 1)}.dup, in);

chain = PV_BrickWall(chain, SinOsc.kr([0.1, 0.11]));

IFFT(chain) // inverse FFT

}.play;

)

// spawn some FFT based synths:

(

SynthDef(\fftgrain, { |out, sustain = 1, rate = 0.2|

var in, chain;

in = WhiteNoise.ar(0.1).dup;

chain = FFT({LocalBuf(128, 1)}.dup, in);

chain = PV_BrickWall(chain,

SinOsc.kr(rate * XLine.kr(1, 15 * [1, 1.6], sustain), Rand(0, pi))

);

Out.ar(out, IFFT(chain) * XLine.kr(1, 0.001, sustain, doneAction: 2)) // inverse FFT

}).add;

)

(

Pbind(

\instrument, \fftgrain,

\rate, Pwhite().linexp(0, 1, 0.01, 300),

\legato, Pwhite(1, 3.0, inf),

\dur, Prand([0.2, 1, 1.2], inf)

).play

)

// IndexL

(

{

var buf = LocalBuf.newFrom((0..5).scramble);

var freq = IndexL.kr(buf, MouseX.kr(0, BufFrames.kr(buf))).poll * 100 + 40;

Saw.ar(freq * [1, 1.1]) * 0.1

}.play;

)

// DetectIndex

(

{

var buf1 = LocalBuf.newFrom((0..5).scramble);

var buf2 = LocalBuf.newFrom((0..5).scramble - 1);

var buf3 = LocalBuf.newFrom((0..5).scramble + 1);

var index = DetectIndex.kr([buf1, buf2], SinOsc.kr([0.85, 0.8], 0, 6).trunc).poll;

var freq = IndexL.kr([buf2, buf3], index).poll * 40 + 40;

Saw.ar(freq) * 0.1

}.play;

)

// DegreeToKey

// modal space

// mouse x controls discrete pitch in dorian mode

(

play({

var mix;

mix =

// lead tone

SinOsc.ar(

(

DegreeToKey.kr(

[0, 2, 3.2, 5, 7, 9, 10].as(LocalBuf),

MouseX.kr(0, 15), // mouse indexes into scale

12, // 12 notes per octave

1, // mul = 1

72 // offset by 72 notes

).poll

+ LFNoise1.kr([3,3], 0.04) // add some low freq stereo detuning

).midicps, // convert midi notes to hertz

0,

0.1)

// drone 5ths

+ RLPF.ar(LFPulse.ar([48,55].midicps, 0.15),

SinOsc.kr(0.1, 0, 10, 72).midicps, 0.1, 0.1);

// add some 70's euro-space-rock echo

CombN.ar(mix, 0.31, 0.31, 2, 1, mix)

})

)

// Osc

(

{

var buf;

var list = Wavetable.sineFill(512, 1.0 / [1, 10, 3, 10, 5, 6, 10]);

// list.plot;

buf = LocalBuf.newFrom(list);

Osc.ar(buf,

XLine.kr(2000, 200 + {30.0.rand}.dup, 10) + SinOsc.ar(Line.kr(2, 300, 10),

0, 100)

) * 0.1;

}.play;

)

// see how not clearing the buffer accesses old data:

// slowly overwrite data with noise

(

{

var buf = LocalBuf(2048, 2);

BufWr.ar(WhiteNoise.ar(1.dup), buf, LFNoise0.ar(530).range(0, BufFrames.kr(buf)));

PlayBuf.ar(2, buf, MouseX.kr(1, 2), loop: 1) * 0.1

}.play

)

// avoid this (unless you like the glitch) by clearing buffer first:

(

{

var buf = LocalBuf(2048, 2).clear;

BufWr.ar(WhiteNoise.ar(1.dup), buf, LFNoise0.ar(530).range(0, BufFrames.kr(buf)));

PlayBuf.ar(2, buf, MouseX.kr(1, 2), loop: 1) * 0.1

}.play

)

// BufCombC stereo (needs no clearing, because delay is filled by ugen)

(

{

var z = Decay.ar(Dust.ar(1.dup, 0.1), 0.3, WhiteNoise.ar);

BufCombC.ar(LocalBuf(SampleRate.ir, 2), z, XLine.kr(0.0001, 0.01, 20), 0.2);

}.play

)

// multichannel test

(

{

var in, chain, n = 4;

in = WhiteNoise.ar(0.1.dup(n));

chain = FFT({LocalBuf(2048, 1)}.dup(n), in);

chain = PV_BrickWall(chain, LFNoise2.kr(2.dup(n)));

Splay.ar(IFFT(chain)) // inverse FFT

}.play;

)