Difference between revisions of "Creating a live looper"

From TidalCycles userbase
Jump to: navigation, search
(Fix misleading indention.)
 
(2 intermediate revisions by one other user not shown)
Line 3: Line 3:
  
 
'''First let's start with our custom SynthDef (run this in SuperCollider)'''
 
'''First let's start with our custom SynthDef (run this in SuperCollider)'''
* tested on Tidal 1.0.7 & SuperCollider 3.10.0
+
* tested on Tidal 1.0.7 / SuperCollider 3.10.0 / Windows10
 
<source>
 
<source>
 
(
 
(
var diversions=();
+
var diversions=();
var dirt=~dirt;
+
var dirt=~dirt;
SynthDef(\rec,{
+
SynthDef(\rec,{
|buffer,duration|
+
|buffer,duration|
var line = Line.ar(dur:duration, doneAction:2);
+
var line = Line.ar(dur:duration, doneAction:2);
RecordBuf.ar(SoundIn.ar([0,1]), buffer, doneAction: Done.freeSelf, loop: 0);
+
RecordBuf.ar(SoundIn.ar([0,1]), buffer, doneAction: Done.freeSelf, loop: 0);
}).add;
+
}).add;
~diversions=diversions;
+
~diversions=diversions;
~diversions[\rec] = {
+
~diversions[\rec] = {
var seconds = 1/(~cps*~speed);
+
var seconds = 1/(~cps*~speed);
var frames = ~dirt.server.sampleRate*seconds;
+
var frames = ~dirt.server.sampleRate*seconds;
var bufferName = format("rec%",~n.asInteger).asSymbol;
+
var bufferName = format("rec%",~n.asInteger).asSymbol;
mod(~cycle,1/~speed).postln;
+
mod(~cycle,1/~speed).postln;
if(mod(~cycle,1/~speed)==0,{
+
if(mod(~cycle,1/~speed)==0,{
var buffer = Buffer.alloc(~dirt.server,frames,~numChannels);
+
var buffer = Buffer.alloc(~dirt.server,frames,~numChannels);
~dirt.soundLibrary.addBuffer(bufferName, buffer);
+
~dirt.soundLibrary.addBuffer(bufferName, buffer);
Synth(\rec,[buffer:buffer,duration:seconds]);
+
Synth(\rec,[buffer:buffer,duration:seconds]);
});
+
});
true;
+
true;
};
+
};
~dirt.orbits[0].defaultParentEvent[\diversion] = { |e| diversions[~s].value; };
+
~dirt.orbits[0].defaultParentEvent[\diversion] = { |e| diversions[~s].value; };
);
+
)
 
</source>
 
</source>
  
Line 68: Line 68:
 
]
 
]
 
</source>
 
</source>
 +
 +
'''Further hacks'''
 +
 +
By default this only records into a temporary buffer which will disappear when we close SuperCollider.  With a small addition, we can write the loop out to disk for later use.
 +
 +
To do this, add the following line below your Synth() call
 +
<source>
 +
...
 +
Synth(\rec,[buffer:buffer,duration:seconds]);
 +
s.record(duration: seconds);  // <-- add this line
 +
</source>
 +
 +
This will capture the recording to SuperCollider's recording directory, the path of which can be found by running:
 +
<source>
 +
thisProcess.platform.recordingsDir
 +
</source>
 +
 +
'''Warning!''' you could write a lot of recordings to disk if you're not careful :)

Latest revision as of 09:25, 4 August 2019

Live looping is the practice of recording and playing back of music in real-time. Below we'll create a custom instrument in SuperCollider that we can call from TidalCycles to record a loop, and then playback in the usual fashion.


First let's start with our custom SynthDef (run this in SuperCollider)

  • tested on Tidal 1.0.7 / SuperCollider 3.10.0 / Windows10
(
var diversions=();
var dirt=~dirt;
SynthDef(\rec,{
	|buffer,duration|
	var line = Line.ar(dur:duration, doneAction:2);
	RecordBuf.ar(SoundIn.ar([0,1]), buffer, doneAction: Done.freeSelf, loop: 0);
}).add;
~diversions=diversions;
~diversions[\rec] = {
	var seconds = 1/(~cps*~speed);
	var frames = ~dirt.server.sampleRate*seconds;
	var bufferName = format("rec%",~n.asInteger).asSymbol;
	mod(~cycle,1/~speed).postln;
	if(mod(~cycle,1/~speed)==0,{
		var buffer = Buffer.alloc(~dirt.server,frames,~numChannels);
		~dirt.soundLibrary.addBuffer(bufferName, buffer);
		Synth(\rec,[buffer:buffer,duration:seconds]);
	});
	true;
};
~dirt.orbits[0].defaultParentEvent[\diversion] = { |e| diversions[~s].value; };
)

Record from TidalCycles

The synthdef we created makes an instrument named 'rec' available that records into a buffer. We can call it from Tidal like this:

-- recording
d1 $ loopAt 1 $ s "rec" + n "0"

This will record into a sample named 'rec0' that we can reference in other code.

Playback

We can playback the recording as-is like this:

-- playback 
d2 $ loopAt 1 $ s "rec0"

That's it! You have a basic looper setup. From here you can start experimenting with layering, gain structures, delays, varying the speed of playback, etc.

Examples

This will play a simple melody first, then layer the recorded 4 cycle loop at half speed,

d1 $ stack [
  every 2 (fast 2) $ n "[0 3 5 7]/4" # s "tink", 
  loopAt 4 $ s "rec" + n "1",
  loopAt 8 $ s "rec1" 
  ] # gain "1.25" # room "0.6" # size "0.9"

This will play an arpeggio, recording a one cycle loop every 4 cycles, and playing back the loop at 2x speed.

d1 $ stack [
  n (arp "updown" "<c'maj'4 e'maj7'4>") # sound "notes",
  whenmod 4 3 (const $ loopAt 1 $ s "rec" + n "6") $ s "~",
  loopAt 0.5 $ s "rec6" # gain "1.25"
]

Further hacks

By default this only records into a temporary buffer which will disappear when we close SuperCollider. With a small addition, we can write the loop out to disk for later use.

To do this, add the following line below your Synth() call

 ...
 Synth(\rec,[buffer:buffer,duration:seconds]);
 s.record(duration: seconds);  // <-- add this line

This will capture the recording to SuperCollider's recording directory, the path of which can be found by running:

thisProcess.platform.recordingsDir

Warning! you could write a lot of recordings to disk if you're not careful :)