The LiSa Tutorial
by Dan Trueman

Tutorial #1: the Basics

LiSa is for sampling a live input (though it can readily be used/abused for other things as well). Let's sample something:

//a simple signal path
SinOsc sin => LiSa saveme => dac;

//give the oscillator a frequency
500 => sin.freq;

//gotta tell LiSa how much memory to allocate
5::second => saveme.duration;

//start recording
1 => saveme.record;

//hang out
1::second => now;

//stop recording
0 => saveme.record;

Yippee, we've recorded 1 second of a sine wave into a buffer. Now let's play it back:

1 => saveme.play;

1::second => now;

0 => saveme.play;

Holy cow! A sine wave! Let's make it just a little more fun; go ahead, replace the SinOsc with the adc analog-digital converter ugen and sample yourself snoring or something.

Let's say you don't want it to click:

//gotta go back to the beginning
0::ms => saveme.playPos

50::ms => saveme.rampUp;

950::ms => now;

50::ms => saveme.rampDown;

50::ms => now;

Let's say you want to transpose it:

//gotta go back to the beginning, again!
0::ms => saveme.playPos

50::ms => saveme.rampUp;

2 => saveme.rate;

950::ms => now;

50::ms => saveme.rampDown;

50::ms => now;

Now, why is it clicking?? Cause it's going through the buffer twice as fast, and running out of recorded sample. How about this:

0::ms => saveme.playPos

//tell it to loop through what we've sampled
1 => saveme.loop;

//also tell it where the loop endpoint is
1::second =>
saveme.loopEnd;

50::ms => saveme.rampUp;

2 => saveme.rate;

950::ms => now;

50::ms => saveme.rampDown;

50::ms => now;

Now, you still might hear a click, this time because as it goes across the end of what we've sampled and loops back to the beginning of the sample, there may be a discontinuity. Can we fix it? Yes we can! But we have to go back and re-record into our buffer with a nice envelope so that when playback loops over the record buffer edges it's nice and smooth. Let's start over:

//signal path and setup
SinOsc s => LiSa loopme => dac;
440. => s.freq;
0.2 => s.gain;

//alloc memory
1::second => loopme.duration;
loopme.recRamp(200::ms);

//start recording input, with 200ms ramp
loopme.record(1);

//stop recording 1 second later, start playing what was just recorded
1000::ms => now;
0 => loopme.record;

//set playback rate
1.5 => loopme.rate;
1 => loopme.loop;
1 => loopme.play;

//loop backwards and forwards
1 => loopme.bi;

while(true) {500::ms => now;}

now the internal buffer has a little ramp on either end so when you loop it there shouldn't be any clicking. This is distinct from the ramping that is created when you use rampUp() and rampDown() to start and stop playback. If you set the recRamp length to zero, you'll hear this click nicely at each end of the loop. Here's another example to belabor how all this works:

SinOsc s => LiSa loopme => dac;
440. => s.freq;
0.2 => s.gain;

//alloc memory
1::second => loopme.duration;
10::ms => loopme.recRamp;

//start recording input
1 => loopme.record;

//begin ramping down
600::ms => now;
400::ms => loopme.recRamp;

//wait for ramp to finish, then stop recording
400::ms => now;
0 => loopme.record;

//set playback rate
1.5 => loopme.rate;
1 => loopme.loop;
1 => loopme.bi;

1 => loopme.play;

while(true) {500::ms => now;}

and yet another example, illustrating some other bookkeeping issues that might come up:

SinOsc s => LiSa loopme => dac;
440. => s.freq;
0.2 => s.gain;

//alloc memory; different length this time
10::second => loopme.duration;
10::ms => loopme.recRamp;

//need to specify where the recording will end if
//we want the recRamping to work when turning
//off recording
1::second => loopme.loopEndRec;

//start recording input
1 => loopme.record;

//stop recording 1 second later, start playing what was just recorded
600::ms => now;
400::ms => loopme.recRamp;

400::ms => now;
0 => loopme.record;

//set playback rate
1.5 => loopme.rate;

//now we need to tell it where to end the looping for playback
//since the buffer size is longer than our actual desired
//loop length
1::second => loopme.loopEnd;

//now go ahead and play....
1 => loopme.loop;
1 => loopme.bi;
1 => loopme.play;

while(true) {500::ms => now;}

ok lot's of basic semi-tedious info there. Now let's look at how to handle multiple voices with LiSa.