cwilso / PitchDetect

Pitch detection in Web Audio using autocorrelation
https://cwilso.github.io/PitchDetect/
MIT License
1.3k stars 437 forks source link

a new algorithm #23

Closed dalatant closed 3 years ago

dalatant commented 7 years ago

While doing my thesis on pitch detection, I came up with this utterly simple technique that boosts up autocorrelation performance. The algorithm you use right now has a 30% error rate while this one gives 3.7% tested over a 1500-sample database of 4 instruments that I collected from web.

It works quite well. It may seem unstable but it is only due to high resolution in cents. The low strings of an electric guitar have a natural ±0.3hz ≈ 5cents average fluctuation in their fundamental frequency during a pluck, according to spectrogram. So this is rather normal.

Thesis is in Greek but I am preparing a website with details in English. Thanks to the Web Audio API and this demo I also managed to translate this into a web app. Thanks for sharing.

700software commented 7 years ago

I do not think that @cwilso is actively accepting pull requests at this time, seeing that this previous pull request has not yet been accepted. Might I suggest you apply your pull requests here? That is, if your work is applicable, as I know that @markmarijnissen has made quite a few changes himself.

mtree commented 7 years ago

Also, can you make it more descriptive?

cwilso commented 7 years ago

Also, I am - I've just been very busy. Will take a look over break.

On Sun, Dec 4, 2016 at 3:30 PM, Dawid Pregel notifications@github.com wrote:

Also, can you make it more descriptive?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cwilso/PitchDetect/pull/23#issuecomment-264740606, or mute the thread https://github.com/notifications/unsubscribe-auth/AAe8eVcAxWRKVM_uHSj5HU0j739mMY8Kks5rE0z9gaJpZM4Ks9Em .

dalatant commented 7 years ago

Hello again! I've been really afk.

this is how I would tag the 4 steps ```javascript // trim var r1=0, r2=SIZE-1, thres=0.2; for (var i=0; ic[d+1]) d++; // find max var maxval=-1, maxpos=-1; for (var i=d; i maxval) { maxval = c[i]; maxpos = i; } } var T0 = maxpos; // interpolation var x1=c[T0-1], x2=c[T0], x3=c[T0+1]; a = (x1 + x3 - 2*x2)/2; b = (x3 - x1)/2; if (a) T0 = T0 - b/(2*a); ```

trimming cuts the edges of the signal so that it starts and ends near zero. This is used to neutralize an inherent instability of the autocorrelation version I use.

autocorrelation is just autocorrelation. The original version.

find first dip / find max are self descriptive.

interpolation is parabolic interpolation. It helps with precision. We suppose that a parabola pass through the three points that comprise the peak. 'a' and 'b' are the unknowns from the linear equation system and b/(2a) is the "error" in the abscissa. Well x1,x2,x3 should be y1,y2,y3 because they are the ordinates.

I hope that helps.

aworld1 commented 7 years ago

I tried your version dalatant, but I had errors in two spots:

buf = buf.slice(r1,r2);

and

var c = new Array(SIZE).fill(0);

The errors were both "undefined is not a function" on my emulator, but when I ran it on chrome it worked perfectly fine. Why is it coming up with these errors? Thanks for reading!

dalatant commented 7 years ago

@aworld1 fill() is a new javascript method that gained support the past 1-2 years. slice() is quite older, but as you figured out it is a matter of where you run it.

aworld1 commented 7 years ago

@dalatant The new algorithm is also very cluttered with for loops. It is impossible to run something in the background as six for loops are repeated over and over. Is there a way to condense the code, so everything runs faster and smoother, without interrupting the accuracy of the algorithm? I would greatly appreciate it!

markmarijnissen commented 7 years ago

Haven't looked at the code, but perhaps webworker is an option?

Op vr 6 jan. 2017 06:42 schreef aworld1 notifications@github.com:

@dalatant https://github.com/dalatant The new algorithm is also very cluttered with for loops. It is impossible to run something in the background as six for loops are repeated over and over. Is there a way to condense the code, so everything runs faster and smoother, without interrupting the accuracy of the algorithm? I would greatly appreciate it!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cwilso/PitchDetect/pull/23#issuecomment-270836034, or mute the thread https://github.com/notifications/unsubscribe-auth/ABOmDfA2fh9yntMZDztRLibAXREz1NIIks5rPdRYgaJpZM4Ks9Em .

dalatant commented 7 years ago

Really where did you run it aworld1? I doubled the buffer because it was so fast in my pc that I couldn't read the indications, and I use an intel p4 that I bought in 2003. Condensing the code doesn't mean optimizing.

aworld1 commented 7 years ago

@dalatant I ran it on Intel XDK, with other code running at the same time, and it was very laggy when I spoke to the mic.

Edit: Oh my god. I edited buflen and everything worked. On every browser. Thanks @dalatant !!! I will use your algorithm.

dalatant commented 7 years ago

Also keep in mind that it could work even with the big buffer. A big candidate for the lag is the way the algorithm is recurring inside the app.

dalatant commented 6 years ago

I was so thrilled about this app but time passed. And I'm still thrilled! :p Check out my implementation

fllprbt commented 6 years ago

@dalatant, thesis for? Just curious, my BSC's dissertation was in Greece and relevant to digital sound processing. Math or CS background?

dalatant commented 6 years ago

@fllprbt I studied information and communication systems engineering in Samos, a 5yr school. Ye we had dsp and signal processing and all that painful stuff :).

MysteryPancake commented 5 years ago

This algorithm has given me far better results in all of my tests, especially for low notes. Thanks for this! I hope it gets committed at some point, because this is excellent!

qnp commented 4 years ago

Just a naïve question: Can't we just simply use a native ConvolverNode, as the autocorrelation can be expressed in terms of convolution. If we define ⦻ the correlation operator and * the convolution operator, we have: Correlation vs Convolution:

Capture d’écran 2019-10-28 à 10 49 14

Autocorrelation:

Capture d’écran 2019-10-28 à 10 49 32
dalatant commented 4 years ago

@qnp the only difference between correlation and convolution is that in convolution the 2nd signal is time-reversed. So if you convolve a signal with its reversed copy (as impulse response) that will be an autocorrelation.

I've never used ConvolverNode before, but if it can convolve two given signals then yes you can do it that way.

bcardiff commented 4 years ago

@dalatant thanks to this PR I am experiencing an improved detection on a side project of mine. Thanks x 💯** 💯!

waterplea commented 3 years ago

Any chance this PR gets merges, @cwilso? :) I have a web audio app and was looking into options to add Karaoke mode in it, googling pitch detection got me here.

Meleeman01 commented 1 year ago

question, what sort of instruments did you use to test this?

bcardiff commented 1 year ago

I use it with an harmonica

dalatant commented 1 year ago

@Meleeman01 Hmm nice question. Οnly an acoustic and an electric guitar. And also my voice. I actually don't have any other (musical) organ. Also good to know that it works on harmonica hehe.

dalatant commented 1 year ago

Well I mean... when live testing the application... If you talk about the recorded samples that I mentioned, that was: guitar, piano, clarinet and bassoon.