PolyPitch Polyphonic pitch tracker


PolyPitch.ar(input, maxvoices=4,levelcompressionfactor=(-0.1),mixleftterm=4.0,torprec=0.0000001,cancellationweight=1.0,polyphonyestimategamma=0.66)


Polyphonic pitch tracker implementing:

Anssi Klapuri (2008) Multipitch analysis of polyphonic music and speech signals using an auditory model. IEEE Transactions on Audio, Speech, and Language Processing 16(2): 255-266


The UGen returns an array of outputs in the format:


[numberofvoicesdetected, frequency in Hz of voice 1, salience of voice 1, frequency of voice 2, salience of voice 2, ...]


The parameter set-up is quite delicate, but some parameters from the paper are made available. The UGen requires sampling rate of 44100, and 64 sample blocksize. 


The current codebase uses libsamplerate internally (http://www.mega-nerd.com/SRC/), by Erik de Castro Lopo. The FFT implementation is also currently based on Mac specific Accelerate library code. 


input - input signal

maxvoices -Maximum polyphony tracked. 

levelcompressionfactor -Equation (5) in the paper, this value is v-1

mixleftterm -Sets relative weight of left term in equation (10), that is, stigma in equation (11). Klapuri notes that high values here are fine for non-drum signals, but drum signals may require more noise robust frontend via a lower mixleftterm.   

torprec - Precision of search in Algorithm 1 (p. 260)

cancellationweight -d in Table 1, p.261

polyphonyestimategamma -gamma in equation (17)




(

{


var in, tracked;


//in = Mix(SinOsc.ar([440,990,775],0,0.1)); 

in = Mix(Saw.ar([440,990,775],0.1));

//in= SoundIn.ar; 


tracked=PolyPitch.kr(in,6,-0.1,10.0);


tracked.poll; 


//Out.ar(0,Pan2.ar(in)); 

}.play

)






(

{


var in, tracked;


in= SoundIn.ar; 


tracked=PolyPitch.kr(in,6,-0.1,10.0);


SendReply.kr(Impulse.kr(44100/2048),'polyparam',tracked); 


}.play

)



(


SynthDef(\ppsine,{arg amp=0.0, freq= 440,pan=0.0; 

Out.ar(0,Pan2.ar(Saw.ar(freq.lag(0.01),amp.lag(0.01)),pan))

}).add; 

)


(

b = Array.fill(6,{Synth(\ppsine)})

)



(

var count= 0; 


o.remove; 


o = OSCresponder(nil, 'polyparam', { |t, r, msg| 


var numvoices = msg[3]; 

count= (count+1)%1; 

if(count==0) {

msg.postln;

6.do{|i| var index = 4+(i*2); 

if(i<numvoices) {

b[i].set(\freq,msg[index]*4,\amp,0.2); //*(msg[index+1])

}

{

b[i].set(\amp,0.0); 

}

};

}

}).add;


)


c = {(SoundIn.ar*0.5)!2}.play


c.free;