class:: Qitch
summary:: constant Q transform pitch follower
related:: Classes/Tartini, Classes/Pitch
categories:: UGens>Analysis>Pitch


Description::

This alternative pitch follower works in the frequency domain rather than link::Classes/Pitch::'s time domain correlation. Tradeoffs are made between latency and frequency resolution. It is meant to provide a relatively stable resultant tracked pitch based on a harmonic template.

note::
You must load one of the auxilliary data files into a link::Classes/Buffer:: and pass the bufnum to the routine. These files take the form:

list::
## QspeckernN1024SR44100.wav
## QspeckernN2048SR44100.wav
## QspeckernN4096SR44100.wav
## QspeckernN8192SR44100.wav
## QspeckernN2048SR48000.wav
## QspeckernN4096SR48000.wav
::

Only use the one for your output sampling rate. Bigger N means more stability and resolution but longer delay and higher average CPU cost. N= 2048 is a good tradeoff if you don't want to track over 1000Hz fundamentals. The 48000 SR files are untested and provided without any promises.
::

In technical terms, this UGen calculates an FFT, applying Brown and Puckette's efficient constant Q transform on a quartertone scale, base note F3= 174.6Hz. Cross correlation search leads to the best match for a harmonic spectrum grid with falling amplitude components. A further fine tuning takes place based on instantaneous frequency estimation (rate of change of phase) for the winning FFT bin.

The algorithms are based on the following papers:

Judith C. Brown and Miller S. Puckette, 1992, emphasis::"An efficient algorithm for the calculation of a constant Q transform"::. Journal of the Acoustical Society of America. 92(5); 2698-701.

Judith C. Brown, 1992, emphasis::"Musical Fundamental Frequency Tracking Using a Pattern Recognition Method"::. Journal of the Acoustical Society of America. 92(3); 1394-402.

Judith C. Brown and Miller S. Puckette, 1993, emphasis::"A High-Resolution Fundamental Frequency Determination Based on Phase Changes of the Fourier Transform"::. Journal of the Acoustical Society of America. 94(2); 662-7.


Classmethods::

method::kr

argument::in
the audio rate input signal

argument::databufnum
you must provide the initialisation data required by Qitch. This in the form of a .wav file that must be loaded to a buffer (see examples below).  The data files should have come with this UGen.

argument::ampThreshold
Qitch outputs a 0 in strong::hasFreq:: if the input amplitude is below this threshold. Same as original link::Classes/Pitch::.

argument::algoflag
0 means use just the constant Q template pattern matcher. 1 flags the refinement based on the phase estimate.

argument::ampbufnum
you may provide an 11 component buffer with template amplitudes- see example below.

argument::minfreq
minimum output frequency in Hz

argument::maxfreq
maximum output frequency in Hz


Examples::

(use headphones!)

code::
s = Server.local;

//assumes data file is in SC home application directory; else provide full path
b = Buffer.read(s, "QspeckernN4096SR44100.wav");
//this line is absolutely essential! You must load the data required by the UGen!

b.numFrames //it's not that much data


(
a= SynthDef("testqitch",{arg infreq=440;
	var in, freq, hasFreq, out;

	in=SinOsc.ar(infreq);

	# freq, hasFreq = Qitch.kr(in, b.bufnum,0.01,1);

	Out.ar(0,[SinOsc.ar(freq,0.1),in]);
}).play(s);
)

a.set(\infreq,237);



c=Buffer.read(s,"/Volumes/data/audio/nikkisitar/warmup.wav"); //sitar test file, try anything you have on your disk

c.numFrames

( //sample tracking
SynthDef("pitchFollow1",{
	var in, amp, freq, hasFreq, out;

	in = PlayBuf.ar(1,c.bufnum, loop:1);
	amp = Amplitude.kr(in, 0.05, 0.05);

	# freq, hasFreq = Qitch.kr(in, b.bufnum, 0.1,1, -1,261, 800 );

	out = Mix.new(VarSaw.ar(freq * [0.5,1,2], 0, LFNoise1.kr(0.3,0.1,0.1), amp));

	Out.ar(0,[out,in])
}).play(s);
)


b = Buffer.read(s, "QspeckernN2048SR44100.wav"); //quicker response with this data set

d = Buffer.alloc(s,11); //make an amp template
d.setn(0, [1,0.98,0.92,0.88,0.84,0.8,0.76,0.72,1.68,1.64,1.6]); //must have 11 components

//analogous to example in the Pitch helpfile
(
SynthDef("pitchFollow1",{
	var in, amp, freq, hasFreq, out;
	in = Mix.new(SoundIn.ar([0,1]));
	amp = Amplitude.kr(in, 0.05, 0.05);
	# freq, hasFreq = Qitch.kr(in, b.bufnum, 0.02, 1, d.bufnum, 160, 880);

	//freq = Lag.kr(freq.cpsmidi.round(1).midicps, 0.05);
	out = Mix.new(VarSaw.ar(freq * [0.5,1,2], 0, LFNoise1.kr(0.3,0.1,0.1), amp));
	6.do({
		out = AllpassN.ar(out, 0.040, [0.040.rand,0.040.rand], 2)
	});
	Out.ar(0,out)
}).play(s);
)
::
