Velocity Preciosity
For the last couple of weeks I've been revisiting the volume hand velocity sensing for what seems like the 100x time. I've finally been able to resolve several long-standing issues and misunderstandings on my part. Meet the new velocity (bottom) - somewhat different than the old velocity (top) - and now an entirely rational construct with no hand-waving necessary to explain how it works:
First off, a bit of history. Long ago I tried differentiation to detect velocity from position. This makes sense from a calculus standpoint, but it of course unacceptably gains up high frequency noise because differentiator gain is infinite at infinite frequency. I thought to follow it by a second order low-pass filter set high enough, but then hit on using a 10Hz 2nd order band-pass filter, which is essentially a 1st order high-pass followed by 1st order low-pass. This worked well and certainly tamed any high frequency noise, but wasn't entirely linear with velocity, was rather complex, and suffered from integrator wind-up. This was followed by a LOG2 function which only accepts unsigned input, so the velocity feeding it had to be rectified. The output was offset by the kloc value to gain up the far field, with this velocity detector placed in parallel with the volume knee. I see now that all of these decisions were sub-optimal (that's engineer-ese for "mistakes were made").
After the failures of the differentiator trials, the next logical step would have been to try a simple 1st order high-pass filter. It would be linear in velocity if operating below the cutoff, and setting the cutoff to something reasonable would limit low frequency gain down (and thus limit high frequency gain up by minimizing the post multiplication strength) and minimize the accumulator wind-down time, but I suppose I was too spooked by the previous differentiation noise to even consider it. Anyway, this is the more correct solution over 2nd order band-pass.
The more I looked at the LOG2 function the more I realized that it's basically just an enormous gain-up. It takes an integer input and necessarily outputs a 5.27 fixed point number, so any input greater than 1 will give at least 1 << 27 as an output, and I don't believe the LOG2 curve itself comes meaningfully into play. I remember initially trying square root (which yields a similarly large 16.16 result) but LOG2 worked better, and it was going down this false path that probably led me more astray than anything else - I couldn't really explain or entirely justify it to myself, and at some point just stopped thinking about it. Pure gain (multiplication) actually works just fine and it accommodates signed I/O as well to give bi-directional velocity.
Any filter output multiplied up and combined with the input and then limited will suffer from accumulator wind-up, where the filter continues to function while the output is otherwise pegged. I played with a spreadsheet sim for several days trying to eliminate it, and discovered that setting the cutoff frequency higher during output saturation went a long way towards minimizing it, but it audibly glitched when limiting so I had to remove it. I believe the right way to do all this is to use division to work backwards from the gain-up, but I don't have sufficient cycles remaining on the volume field thread.
So the velocity unit now uses a 40Hz first order high pass filter to detect velocity, and the velocity is now applied bidirectionally rather than just for the attack, so it can also be used to more quickly drive the volume to zero. The day before yesterday I thought to position the velocity unit before the knee unit rather than in parallel with it, and after playing it for a while think it's a keeper. The following knee gains up attack and decay, and this - along with the higher cutoff frequency and bidirectional velocity - tend to hide the filter wind-up, so higher velocity settings don't cause large attacks to rail at max volume for a noticeable period, followed by a weird decay (having an RC exponential decay go through the EXP2 function at the end gives who knows what). Limiting the high-pass filter input to [-98:0] dB gives a nice range in the field (you don't want significant subsonic operation) and also prevents saturation of the filter output.
I considered having the velocity unit be the only input the envelope generator, but the knee provides the lion's share of attack sharpness, so it must somehow also be an input to the envelope generator, and can't bypass it.
So we can use the velocity to drive the volume level up through the knee and back down again, which seems like a good thing in practice. Having the drop before all this adds even more to low volume velocity gain, which I thought might be problematic but it doesn't seem to be. I think it's best to have all of these units in series if at all possible, as the simpler processing may feel more intuitive to control with the hand.
[EDIT] You can listen to the new velocity (followed by a fairly sharp knee) in the trumpet_Bb preset here: https://d-lev.com/audio/2023-09-17_velocity.mp3