Classes (extension) | UGens > FFT | UGens > Analysis

PV_ExtractRepeat : PV_ChainUGen : WidthFirstUGen : UGen : AbstractFunction : Object
ExtensionExtension

extract a repeating loop out from audio

Description

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.

Class Methods

PV_ExtractRepeat.new(buffer, loopbuf, loopdur, memorytime: 30, which: 0, ffthop: 0.5, thresh: 1)

Arguments:

array

The array of input signals.

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.

Inherited class methods

Instance Methods

Inherited instance methods

Examples

First a toy example with synthetic material; then an example reading a WAV file from disk (you'll have to find one, and also find its bpm).

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

This unit is (c) Dan Stowell, 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