Looper


05 February 2013

For the DEIND instruments, we want to test and explore not only cutting edge technology but also get an idea and understanding about old techniques to electronic music.

To start this, I built a very basic looper in SuperCollider. Basically, it is a simple example on how to combine writing to a buffer and then directly playing it back. With a fixed loop length, it is possible to turn recording on and off and adjust recording amplitude as well as overdub amplitude.

As you might notice, the intention was to keep the interface clean and have it to be flexibly adjusted for needs that will come up over the course of the project. In this design, it is e.g. very easy to expand the looper to several channels that operate individually.

To show the looper’s possibilities, I wanted to record a short snippet; unfortunately I was carried away (several times), so the snippet had to be cut and is still 8 minutes long…

Source code below and on sccode.org.

s.boot;
(
q = ();
q.length = 16; // 16 seconds == 8 bars @ 120bpm
q.numFrames = q.length * s.sampleRate; 
q.looperInBus = Bus.audio(s);

Spec.add(\switch,     [0, 1, \lin, 1, 0]);
Spec.add(\recLevel,   \db);
Spec.add(\preLevel,   \db);
Spec.add(\playbackRate, \rate);
Spec.add(\recEnable,  \switch);
Spec.add(\recCuePoint,  [0, q.length]);
Spec.add(\playCuePoint, \recCuePoint);
Spec.add(\resetRec, \switch);
Spec.add(\resetPlay,\switch);
)

NdefMixer(s)

(
Ndef(\clicktrack, {
 Mix([
 SinOsc.ar(440) * Decay.ar(Impulse.ar(2), 0.1, 0.2), 
 SinOsc.ar(880) * Decay.ar(Impulse.ar(0.5), 0.1, 0.2)
 ]);
})
)

(
Ndef(\oneTrackLooper, { // A looper for one track, mono.
 var in = Ndef(\input).ar; // your input

 var buffer = LocalBuf.newFrom(0!q.numFrames); // stores loop
 var recEnable = \recEnable.kr(0).lag2(0.01);
 var recLevel  = \recLevel .kr(0).dbamp;
 var preLevel  = \preLevel .kr(0).dbamp;
 // converts from samples to seconds
 var playCuePoint = \playCuePoint.kr(0) * s.sampleRate; 
 var resetRec  =  \resetRec.tr(1);
 var resetPlay = \resetPlay.tr(1);
 var playRate = \playbackRate.kr(1);
 
 // recording
 RecordBuf.ar(
 in, 
 buffer, 
 loop: 1, 
 recLevel: recLevel * recEnable,
 preLevel: preLevel,
 trigger:  resetRec
 );

 // playing back
 PlayBuf.ar(
 1,
 buffer, 
 rate:   playRate, 
 trigger:  resetPlay, 
 startPos: playCuePoint, 
 loop: 1
 );


})

)


// something to loop
(
Ndef(\input, {
 SoundIn.ar(0);
})
)