pitch.h
Pitch: finding it, and moving it.
#include <sonore/pitch.h>- 2types
- Guides: Getting started, MIDI and MPE
On this page
Design notes
PitchDetector is YIN (de Cheveigné & Kawahara, 2002): the difference function of a window against itself, normalised by its own running mean so the lag-zero trivial minimum disappears, the first dip under a threshold taken as the period, refined by a parabola through its neighbours. Chosen over plain autocorrelation because autocorrelation's octave errors are the classic tuner failure -- a rich waveform correlates almost as well with itself half a period later -- and the cumulative-mean normalisation is exactly the fix for that.
PitchShifter is the two-head delay-line shifter: a read pointer that runs slower or faster than the write pointer changes the pitch, wraps periodically, and a second head half a window behind crossfades over the wrap so it is never heard. It is the design in every classic hardware harmoniser and it is what "shimmer" is made of. Grainy on a slow sweep and slightly comb-flavoured on a wide interval, like the hardware; a phase vocoder over stft.h is the cleaner and far costlier alternative.
Included by dsp.h.
Types 2
template <int Window = 2048> class PitchDetector
Feed samples in; every hop a new estimate is ready.
Window sets the lowest detectable pitch (a period must fit in half the window: 2048 at 48 kHz reaches down to ~47 Hz) and the cost, which is the thing to know about: each analysis is Window/2 differences for every lag in range, so narrowing the range with setRange() is how a bass tuner and a vocal tuner cost different amounts. At the default range this is about a thousand multiply-adds per sample -- fine for a tuner or a monophonic tracker, not something to run per voice.
push() spreads that over the hop: each sample adds the terms of the difference function it completes, so every call costs the same and the estimate is ready on the same sample it always was. It used to do the whole analysis in the one call that ended a hop -- 0.75 ms inside a single audio block, every 1024 samples.
template <int MaxWindow = 8192> class PitchShifter
Two read heads on one delay line, half a window apart, crossfaded with equal-power sine/cosine gains so the level does not dip at the seams.
The window is the grain size: longer is smoother in pitch and blurrier in time, and 40-60 ms is where vocals and guitars sit. Latency is half of it.