PV_ExtractRepeat extract a repeating loop out from audio
PV_ExtractRepeat(chain, loopbuf, loopdur, memorytime, which=0, ffthop=0.5, thresh=1)
If you have a signal that consists of some fixed looping audio (e.g. a beat) plus some varying content (e.g. singing), this UGen uses a simple binary-masking technique to try and separate the looping bit from the non-looping bit. The quality of the separation is quite rough, but useful in some circumstances.
Note that this unit estimates the loop characteristics online in real time, meaning it takes a few times through the loop before the separation really kicks in. This means that at any point, any novel element is included in the nonrepeating part, even if it's really a loop that's starting.
You must know the loop duration - this unit will not estimate it for you.
chain - an fft chain
loopbuf - a buffer where data about the loop is calculated/stored. num frames should be enough to hold the loop (you'll get a warning if not), num channels should be (fftsize/2 + 1).
loopdur - duration in seconds of the bit you want extracted. (You can change the loop duration on-the-fly but you'll get some unhelpful results while the unit settles in to the new loop duration.)
memorytime - how quickly (in seconds) the recursive estimation converges
which - set to 0 to extract the loop, set to 1 to extract everything else
ffthop - this should match the hop size used in the FFT. typically 0.5.
thresh - threshold for allocating bins to repeating/nonrepeating. Default is 1, and raising it means more gets allocated to the repeating part.
Example
In this example we create definite looping and non-looping stuff using some synthetic material, but you might find it more interesting to use DiskIn to read in some dance music...
s.boot
// Create audio containing repeating and varying components, merged in the same channel:
(
x = {
var trigs, looplen = 2, loopy, varying;
trigs = Impulse.kr(6/looplen) + Impulse.kr(4/looplen);
loopy = BPF.ar(WhiteNoise.ar * EnvGen.ar(Env.perc(0.01, 0.3), trigs), LFCub.kr(1/looplen).exprange(100, 5000));
varying = Pulse.ar(LFNoise0.kr(6/looplen).exprange(100, 500).cpsmidi.round.midicps) * 0.1;
(loopy + varying).dup
}.play;
)
// Now the thing that will attempt to separate them out again (inc a buffer for it to use):
~loopbuf = Buffer.alloc(s, 200, 513);
(
y = { |which=1, active=1|
var son = In.ar(0);
var chain = FFT(LocalBuf(1024), son);
chain = PV_ExtractRepeat(chain, ~loopbuf, 2, memorytime:30, which:which);
ReplaceOut.ar(0, Select.ar(active, [son, IFFT(chain)]).dup);
}.play(x, addAction: \addAfter);
)
y.set(\which, 0) // focus on the nonrepeating bit
y.set(\which, 1) // focus on the repeating bit
y.set(\active, 0) // back to normal
y.set(\active, 1) // filter it again
y.free;
x.free;
//////////////////////////////////////
// With music:
~track = "~/tmpwavs/Postal Service - Such Great Heights.mp3.2.wav".standardizePath; ~bpm=116.6;
~track = "~/tmpwavs/Amy Winehouse - Rehab.mp3.wav".standardizePath; ~bpm=145.1;
~looplen = 480/~bpm;
b = Buffer.cueSoundFile(s, ~track, 0, 2);
x = { DiskIn.ar(2, b) }.play;
// Now the thing that will attempt to separate them out again (inc a buffer for it to use):
~loopbuf = Buffer.alloc(s, 1000, 513);
(
y = { |which=1, active=1, thresh=1|
var son = In.ar(0);
var chain = FFT(LocalBuf(1024), son);
chain = PV_ExtractRepeat(chain, ~loopbuf, ~looplen, memorytime:30, which:which, thresh:thresh);
ReplaceOut.ar(0, Select.ar(active, [son, IFFT(chain)]).dup);
}.play(x, addAction: \addAfter);
)
y.set(\which, 0) // focus on the nonrepeating bit
y.set(\which, 1) // focus on the repeating bit
y.set(\active, 0) // back to normal
y.set(\active, 1) // filter it again
y.set(\which, 0, \thresh, 1.5) // trying a higher threshold
y.free;
x.free;
b.close
Based on the technique presented in this paper (but different - adapted for online estimation and with some other little differences):
Zafar Rafii and Bryan Pardo. "A Simple Music/Voice Separation Method based on the Extraction of the Repeating Musical Structure," 36th International Conference on Acoustics, Speech and Signal Processing (ICASSP 2011), Prague, Czech Republic, May 22-27, 2011.
http://www.cs.northwestern.edu/~zra446/research.html