Hi,
I’m interested in implementing a new(ish) pitch tracking algorithm called “Bitstream Autocorrelation”. There’s a C++ library available so I could do it as a plugin, but the algorithm is relatively simple so I’m interested in whether it could work in pure SCLang too.
I’ll try to give a brief explanation:
- Take an input signal and call
.sign
on it. This turns anything positive into a 1 and anything negative into a -1 - Record that signal into a buffer (the size of the buffer determines the lowest frequency that it’s possible to detect, at a cost of increased latency)
- Compare the
.sign
of the incoming signal with what’s stored in the buffer using a sliding window. Instead of a traditional autocorrelation though (which uses multiply and sum), instead we compare them with.bitXor
. With this, an exact match between two square wave patterms would result in a value of all 0s for the window. - Count the total 0s and 1s for each sliding window from the step above. A low value (around 0) indicates the starting point of a new period so we require some kind of thresholding in this step.
- The distance between these valleys give an indication of the pitch.
There’s a Python 2 implementation here and the actual algorithm is maybe 20 lines or so.
I’m still not great at writing my own synths but this is what I tried so far:
({
var freq, hasFreq;
~sig = SinOsc.ar(430) + SinOsc.ar(LFTri.ar(4, mul: 50, add: 440));
~delayed = DelayN.ar(~sig, 1, 1);
~xors = (~sig.sign).bitXor((~delayed.sign));
#freq, hasFreq = Pitch.kr(~xors);
freq.poll;
SinOsc.ar(freq);
}.play)
My issue is that the DelayN
stops working after filling up once. I think I need something else to make a continuous sliding window.
Any advice would be appreciated, even if it’s that I should write it as a plugin instead.