Further Adventures In Pitch Correction
Roger (pitts8rh) has spurred me on to consider a more professional level of pitch correction (thanks Roger!). As I said before, my current pitch corrector works well but is a bit too "note centric" in that off-center vibrato which bleeds over into the neighboring note can drag the correction off center. And it often corrects "too well" in that it voices recorded together beat against each other. I very much like the "one knob" aspect of it, and like that the adjustment of that knob goes from off/unnoticeable, to a range of noticeable, to full quantization (I think all knobs should do something really obvious and non-redundant/overlapping).
The gist of pitch correction is this: generate a correction / error function and apply it to the pitch number. The function is obviously the same/repeats for all notes. The simplest function I've found is to use the linear note ramp (a straight line going from one note to the next) "layed down" on the x axis to form a sawtooth as the error, and subtract this from the pitch number. Low pass filtering the error slew limits the abrupt changes between notes, knocks the sharp edges off, and lowers the amplitude (strength of correction) for faster changes, and adjusting the low pass corner frequency markedly changes the correction experience. Reducing the error amplitude with an explicit fractional multiplication by, say 0.9, would actually fix the odd sounding unison "too perfect" correction.
If we want more control we could use line segments to construct the correcting waveform, but line segments are kind of hard to do without division, and division is hard to do without floats, and line segments aren't smooth anyway. A good candidate here is the type of squaring based smooth quantization I'm doing for the LED tuner brightness (I was also using this to generate glottal waves for a while).

The above is an Excel plot of the correction function generated via various logical transformations and repeated squarings (here 3, or raised to the power 8) of the note ramp. The lighter trace is the correction function multiplied by 0.9, and the darker trace is this added to the pitch number to produce the corrected pitch number from note 0 to note 1. Note that there's a broad plateau at each note center, the correction isn't "perfect" due to the 0.9 multiplication, and the transition between notes is fairly steep but smooth.
If we apply the above directly we get smooth quantization (yes, an oxymoron), not pitch correction. Pitch correction requires amplitude modulation of the correction function.

I got the above up and running on the D-Lev prototype the other night and have had a couple of opportunities to play around with it. The upper graphs show the transformations applied to the note ramp to get the correction function. Modulo multiplication to get the note fraction, XOR via full-width MSb to fold the upper half down, *2 to get full scale, repeated squaring, then backed out doing inverse functions, laid down on the x axis via subtraction of the note fraction ramp, followed by note scaling, amplitude modulation, and mixing with the pitch number.
At bottom is the signal flow with three paths. Top path is the mix, middle path generates the correction function, bottom path modulates the correction function. In the ABS_VEL block the absolute instantaneous velocity is found via subtraction of the previous pitch number sampled at 48kHz (differentiation), then 4th order low pass filtered at 15Hz to reduce noise. Bulk gain is applied via left shift. The result is slew limited in the fall direction only, giving a leaky peak hold. Finally a negation of all bits reverses the direction.
The setup of this arrangement is much more subtle than my previous one knobber - in fact, I finally broke down and made a debug parameter type that displays 8 digit hex on the LCD in order to get some observability of the modulation path inner workings. Not too surprisingly, the quantization squaring knob has the most noticeable influence, with 3 squarings around the most you might want in terms of slope between slowly played notes (if not going for a quantization effect). The gain knob functions more as threshold for how much hand movement is required to scale the correction back. The slew limit knob seems the least useful, and could perhaps be replaced with a constant. I need to try the LOG2 trick to gain up and reduce the dynamic range of the velocity, as this worked like a champ on the volume side envelope generation.
Overall, I like this better as it totally gets out of the way of vibrato, and the note-to-note transitions are less magnetic. However, there's clearly a tension between too much disengaging and too little (gain knob).