How to use the loop part of a Looper as separate Buffer

Hi there!
I wish this message finds you well!

I am studying Eli Fieldsteel Line6 loop pedal emulation (Week 4: Intermediate Coding with SuperCollider – MUS 499C Spring 2021 - YouTube).

What I would like to do is to use only the loop part (the recording part) for further processing techniques (e…g: delays, time-stretches, granular synthesis, FM or any other.)

The looper SynthDef is the following:

SynthDef(\looper, {
	var mic, trig, max, ptr, loop, rec, mix;
	var xfade = \xfade.kr(0.02);
	var buf = \buf.kr(0);
	mic = SoundIn.ar(\in.ir(0));
	trig = Trig1.ar(\trig.tr(0), ControlDur.ir);
	max = Sweep.ar(trig, SampleRate.ir * \run.kr(0));
	ptr = Phasor.ar(trig, 1, 0, max, 0);
	loop = BufRd.ar(1, buf, ptr);
	rec = sum([
		mic * \reclev.kr(0).varlag(xfade,-2),
		loop * \prelev.kr(0).varlag(xfade,-2)
	]);
	rec = rec * \recAmp.kr(1).varlag(xfade,-2);
	BufWr.ar(rec, buf, ptr);
	mix = sum([
		loop * \loopAmp.kr(1).varlag(xfade,-2),
		mic * \micAmp.kr(1).varlag(xfade,-2) * 0;
	]);
	mix = mix * \mixAmp.kr(1).varlag(xfade,-2);
	Out.ar(\out.ir(0), mix!2);
}).add;

and the buffer.aloc is the following:

// ~b = Buffer.alloc(s, s.sampleRate * 13, 1); //13 seconds of maximum size for example

Then, the SynthDef for further processing:

SynthDef(\playLinearSin, {
	arg syncSigOrPar = 0, syncPar = 1, start = 1, end = 10, dur = 8, lineAmp = 1,
	buf = 0, rate = 1, atk = 0.1, rel = 1, c1 = 3, c2 = (-1), spos = 0,
	parFreq = 5, parScale = 1, minPar = 1, maxPar = 100, durPar = 10, pan = 0, amp = 1, out = 0;
	var env, sin, sig, par, sigOrpar;
	env = Env([0,1,0], [atk, rel], [c1, c2]).kr(2);

	sin = SinOsc.ar(Line.kr(start, end, dur), 0, lineAmp);

	par = Select.ar(syncPar, [LFPar.ar(parFreq), LFPar.ar(Line.kr(minPar, maxPar, durPar))]);

	sig = PlayBuf.ar(2, buf, rate, startPos: spos);

	sigOrpar = Select.ar(syncSigOrPar, [sig * sin * env, sig * sin * par * env]);
	sig = sigOrpar;
	sig = Pan2.ar(sig, pan, amp);

	Out.ar(out, sig);
}).add;

and to play this synth:

(
Synth(\playLinearSin, [\buf, ~b, \amp, 1, \rate, rrand(-12,12).midiratio, \end, 20, \rel, 8,
\parFreq, rrand(2,8), \syncSigOrPar, 0, \syncPar, 1]);
)

I know that this ~b is related to the whole Buffer allocation (the whole 13 seconds in the example)

I intend to use only the loop part, for example, to play it back, to process some effects…
How can I do that, please? any tips?

Any help will be amazing,
Thank you so much!

Hi Ivan!

One approach is to send the sound output of your looper also to a Bus and then insert this bus into your processing synths (delays, reverbs, etc). Here is a tutorial that might help:

https://depts.washington.edu/dxscdoc/Help/Tutorials/Getting-Started/11-Busses.html

2 Likes

Hi Ivan,

You can use the Buffer.copyData to copy part of a buffer (or the whole buffer) to a new buffer. You can look it up in the Buffer helpfile, here is an example from the helpfile where b is the original buffer and c is the new buffer.

b.copyData(c, dstStartAt: 4410, numSamples: 15500);

You might also want to look at the FluidBufCompose from the Flucoma tool set.

1 Like

Hi Felipe! @fmiramar
Nice to see you over here!
Thank you so much for your reply.
Yes! It worked with another Bus specifically for the loop part.
Moreover, it will give me some flexibility to work with it.

Thank you!

1 Like

Hi Thor! @Thor_Madsen

This is awesome! Thank you for your reply.
The copyData is more direct indeed.
I tested and also worked well… Thank you

Btw, I intend to work with FluCoMa as soon as possible, mainly because its audio features and spectral content analysis for music creation.

Are you working with it?
I really would like to know it a bit more (although I’m already following the FluCoMa discussion forum)

Thank you once again!

I had some more time to read your previous post, and I am actually in a very similar situation working with buffers.

Here is one take on it. This can all happen while the looper is running, I have not tested it with the looper though, might take some tweaking to avoid discontinuities.

(
~p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";
~b = Buffer.read(s, ~p);
)


(
SynthDef(\loopChunck, {|buf, startPos, duration, amp = 0.5, loop = 1, atk = 0.1, rel = 0.3, gate = 1, out = 0, fxbus|
	var sig = PlayBuf.ar(
		numChannels: 1, 
		bufnum: buf, 
		rate: 1.0, 
		trigger: Impulse.ar(duration.reciprocal), 
		startPos: startPos 
		loop: loop, 
		doneAction: 0
	);
	var env = Env.asr(atk, 1, rel).kr(2, gate);
	/// do fx processing directly here 
	Out.ar(out, sig!2 * env * amp);
	
	// ... or send to an audio bus
	Out.ar(fxbus, sig * amp * env);
}).add;
)

x = Synth(\loopChunck, [\buf, ~b, \startPos, 0, \duration, ~b.numFrames/s.sampleRate])

x.set(\gate, 0)

/// using an audio bus
// ~abus = Bus.audio(s, 1); below I am using ReplaceOut directly on the main output = 0;

SynthDef(\fx, {|bus, out = 0|
	/// Put your own synth here instead
	var sig = In.ar(bus, 1);
	sig = sig * LFPulse.kr(6).range(0, 1.0);
	Out.ar(out, sig!2);	
}).add;

x = Synth(\loopChunck, [\buf, ~b, \startPos, 1.3 * s.sampleRate, \duration, 1, \out, 0, \fxbus, ~abus]) 
// 1 second loop starting 1.3 secs in

y = Synth(\fx, [\bus, ~abus], addAction: \addToTail); // add cheap tremolo

x.set(\gate, 0);
y.free;

/// or same thing but avoiding the extra audio bus, comment out last Our.ar in \loopChunck

SynthDef(\fx, {|bus = 0, mix = 0.5| // mix in range 0-1
	/// Put your own synth here instead
	var sig = In.ar(bus, 1);
	var fx = sig * LFPulse.kr(6).range(0, 1.0);
	ReplaceOut.ar(bus, XFade2.ar(sig!2, fx!2, 2 * mix - 1));	
}).add;

x = Synth(\loopChunck, [\buf, ~b, \startPos, 1.3 * s.sampleRate, \duration, 1, \out, 0]) 
y = Synth(\fx, [\bus, 0], addAction: \addToTail); // cheap tremolo

x.set(\gate, 0);
y.free

I did some testing with Flucoma and I am using a couple of the buffer analyzing ugens in my current code. It seems pretty solid and gives you a lot more options than with built in SC ugens. I have not dealt with the machine learning part of Flucoma yet, I saw all the demos but that is about as far as I have gotten. I plan to adopt the trombone vs. oboe demo to guitar to see if I can distinguish between different playing styles - slide, half-muted strums, trills and so on. I will also see if hooking the RT Melbands directly up to a synth can produce something interesting.

2 Likes

Thank you again, Thor!
Indeed, it was one possiblity to work with loops. It worked!

I am really interested in working with spectral features and machine learning (for timbre and extended techniques as well).

Perhaps we might be in touch (when it is possible, of course) to exchange studies and implementations.

Thank you once again

Yes, the advantage of using buffers this way is that you don’t need to create new buffers or copy anything - allocating buffers and copying buffers takes a little time which can be problematic in a RT scenario, in the code above you only need to allocate the buffer once, then after that everything else is a reference to the original buffer.

About Flucoma, let’s definitely share experiences, I will post something when I get to testing it.

1 Like