[sdiy] Tap tempo question
Mattias Rickardsson
mr at analogue.org
Sat Feb 6 23:26:45 CET 2021
How would this kind of lowpass filtered tempo measurement be used in a real
scenario?
I was interested in how it performs if one would want it to follow and
adapt to the beats tapped, and unless I misunderstood something, it results
in something like the attached sketch (if it works).
There we have a steady beat, and some tapping where the first tap comes too
early (exaggerated in order to show the principle) and the other taps in
proper timing. Tapped periods are measured, averaged by 50 % new + 50
% old, resulting in the beat positions at the bottom. When the low-pass
filtered periods are stacked up, the beats don't align or adapt to the true
beats. The initial timing error is gradually entering and never fading away.
In a pure delay this would perhaps not matter, since there are no beats and
no phases that need to align with each other, but in a sequencer or LFO or
looper of some kind I guess some other mechanism is needed where the
timings rather than the periods are analysed?
/mr
On Sat, 6 Feb 2021 at 21:47, Brian Willoughby <brianw at audiobanshee.com>
wrote:
> On Feb 3, 2021, at 13:20, Didier Leplae via Synth-diy wrote:
> > My programming skills are rudimentary at best, but I’m very interested
> in the low pass filtering concept and will look into to it. Thanks!
> >
> > On Feb 2, 2021, at 8:03 PM, Brian Willoughby wrote:
> >> On Feb 2, 2021, at 02:59, Tom Wiltshire wrote:
> >>> Averaging makes some sense where you’ve got a human tapping, and Brian
> is right that weighted averages are a good idea to give more recent times
> more importance. Rather than doing hard sums, on a PIC it makes sense to do
> this weighting by using bit shifts (so choose from weights of 1, 0.5, 0.25,
> or 0.125!!).
> >>
> >> A low-pass filter with a coefficient of 0.5 would automatically create
> that weighted series (1, 0.5, 0.25, 0.125). It wouldn't even be necessary
> to store the last four values because the filter state would already have
> them summed.
> >>
> >> It would probably be helpful to compare the latest period against the
> slowest tempo, and if it's even longer than that then just zero-out the
> filter state to reset. Of course, don't use the filter output if it's zero.
> Instead, just leave the tempo at the latest setting.
> >>
> >> Brian Willoughby
>
> Didier,
>
> You may have already found everything you need, but I had a moment to
> write, so I'll try to give some quick pointers.
>
> A single-pole lowpass filter can be implemented in code as follows:
>
> typedef float sample_t; // your setup may not use float, so adjust the
> following as needed
> sample_t a = coefficient; // coefficient is between 0 and 1
> sample_t b = 1.0 - a; // the key is that a+b produces the largest sample
> value, not more
> static sample_t output = (input * b) + (output * a);
>
> That coefficient ends up determining the corner frequency of the lowpass
> filter. Note that a + b = 1, so it's almost like a wet/dry mix of the old
> and new values. When a == 0.5, b == 0.5, you end up with the simple
> average. The average of two values would be (a + b) / 2, and if you
> multiply each input by 0.5 before adding them, then it's the same result,
> thanks to the associativity and commutativity of multiplication and
> addition. i.e. (x + y) / 2 == x/2 + y/2 == x * 0.5 + y * 0.5
>
> This may look like it's only averaging two values, but over time the
> output contains traces of old values. At any given time, the output
> contains 0.5 of the input, 0.25 of the previous input, 0.125 of the input
> before that, and so on. Depending upon whether you're handling 8-bit,
> 10-bit, 12-bit, 16-bit, or greater values for the period, the length of
> time that the average spans is extended - which is to say that the impulse
> response is approximately infinite due to the feedback, apart from
> quantization noise.
>
> Putting this into terms of Tom's suggestion, you can avoid multiplication
> ... input * b ... output * a ... by simply fixing the values of a and b at
> 0.5, and using the bit shift instruction to divide by two. This assumes
> your processor does not have a single-cycle multiply opcode (in which case
> shift and multiple might take the same time). Bit shifts are basically
> always a single cycle, and as fast as the fastest instructions. Most
> processors have a carry flag that can participate in the shift operation.
>
> So, for example, if you have an 8-bit processor, you could add 8-bit input
> and 8-bit output, giving a 9-bit sum including the carry bit, then shift
> right to bring the carry bit into the result, truncating the least
> significant bit. This helps resolution because if you shifted each input
> separately, then you'd only be adding two 7-bit numbers due to truncation.
> It's also a little faster to do one add and one bit shift, rather than two
> bit shifts and an add.
>
> The same concepts work for 16-bit and 32-bit processors, it's just that
> the registers are larger. I would build the math around the resolution of
> your timer peripheral, which might be 16-bit and might be 32-bit, depending
> upon your processor. I'm assuming that you have some sort of time
> reference, so that you can measure the time between taps of the tempo
> button. You'll want to consider the lowest tempo and the resolution of the
> timer to decide how large the values need to be.
>
> I suppose that you could also use other power-of-two coefficient pairs,
> like 0.75 and 0.25, or 0.875 and 0.125, but those would require slightly
> more code.
>
> I hope this helps. It's a lot longer than I expected it to be.
>
> Brian Willoughby
>
>
>
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at synth-diy.org
> http://synth-diy.org/mailman/listinfo/synth-diy
> Selling or trading? Use marketplace at synth-diy.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://synth-diy.org/pipermail/synth-diy/attachments/20210206/717f7c10/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: IMG_20210206_225921.jpg
Type: image/jpeg
Size: 185036 bytes
Desc: not available
URL: <http://synth-diy.org/pipermail/synth-diy/attachments/20210206/717f7c10/attachment.jpg>
More information about the Synth-diy
mailing list