audio - How to find the fundamental frequency of a guitar string sound? -


i want build guitar tuner app iphone. goal find fundamental frequency of sound generated guitar string. have used bits of code auriotouch sample provided apple calculate frequency spectrum , find frequency highest amplitude . works fine pure sounds (the ones have 1 frequency) sounds guitar string produces wrong results. have read because of overtones generate guitar string might have higher amplitudes fundamental one. how can find fundamental frequency works guitar strings? there open-source library in c/c++/obj-c sound analyzing (or signal processing)?

you can use signal's autocorrelation, inverse transform of magnitude squared of dft. if you're sampling @ 44100 samples/s, 82.4 hz fundamental 535 samples, whereas 1479.98 hz 30 samples. peak positive lag in range (e.g. 28 560). make sure window @ least 2 periods of longest fundamental, 1070 samples here. next power of 2 that's 2048-sample buffer. better frequency resolution , less biased estimate, use longer buffer, not long signal no longer approximately stationary. here's example in python:

from pylab import * import wave  fs = 44100.0   # sample rate k = 3          # number of windows l = 8192       # 1st pass window overlap, 50% m = 16384      # 1st pass window length n = 32768      # 1st pass dft lenth: acyclic correlation  # load sample of guitar playing open string 6 # fundamental frequency of 82.4 hz (in theory), # sample @ 81.97 hz g = fromstring(wave.open('dist_gtr_6.wav').readframes(-1),                dtype='int16') g = g / float64(max(abs(g)))    # normalize +/- 1.0 mi = len(g) / 4                 # start index  def welch(x, w, l, n):     # welch's method     m = len(w)     k = (len(x) - l) / (m - l)     xsq = zeros(n/2+1)                  # len(n-point rfft) = n/2+1     k in range(k):         m = k * ( m - l)         xt = w * x[m:m+m]         # use rfft efficiency (assumes x real-valued)         xsq = xsq + abs(rfft(xt, n)) ** 2     xsq = xsq / k     wsq = abs(rfft(w, n)) ** 2     bias = irfft(wsq)                   # unbiasing rxx , sxx     p = dot(x,x) / len(x)               # avg power, used check     return xsq, bias, p  # first pass: acyclic autocorrelation x = g[mi:mi + k*m - (k-1)*l]        # len(x) = 32768 w = hamming(m)                      # hamming[m] = 0.54 - 0.46*cos(2*pi*m/m)                                     # reduces side lobes in dft xsq, bias, p = welch(x, w, l, n) rxx = irfft(xsq)                    # acyclic autocorrelation rxx = rxx / bias                    # unbias (bias tapered) mp = argmax(rxx[28:561]) + 28       # index of 1st peak in 28 560  # 2nd pass: cyclic autocorrelation n = m = l - (l % mp)                # window integer number of periods                                     # shortened ~8192 stationarity x = g[mi:mi+k*m]                    # data k windows w = ones(m); l = 0                  # rectangular, non-overlaping xsq, bias, p = welch(x, w, l, n) rxx = irfft(xsq)                    # cyclic autocorrelation rxx = rxx / bias                    # unbias (bias constant) mp = argmax(rxx[28:561]) + 28       # index of 1st peak in 28 560  sxx = xsq / bias[0] sxx[1:-1] = 2 * sxx[1:-1]           # fold freq axis sxx = sxx / n                       # normalize s avg power n0 = n / mp np = argmax(sxx[n0-2:n0+3]) + n0-2  # bin of nearest peak power  # check print "\naverage power" print "  p:", p print "rxx:", rxx[0]                # should equal dot product, p print "sxx:", sum(sxx), '\n'        # should equal rxx[0]  figure().subplots_adjust(hspace=0.5) subplot2grid((2,1), (0,0)) title('autocorrelation, r$_{xx}$'); xlabel('lags') mr = r_[:3 * mp] plot(rxx[mr]); plot(mp, rxx[mp], 'ro') xticks(mp/2 * r_[1:6]) grid(); axis('tight'); ylim(1.25*min(rxx), 1.25*max(rxx))  subplot2grid((2,1), (1,0)) title('power spectral density, s$_{xx}$'); xlabel('frequency (hz)') fr = r_[:5 * np]; f = fs * fr / n;  vlines(f, 0, sxx[fr], colors='b', linewidth=2) xticks((fs * np/n  * r_[1:5]).round(3)) grid(); axis('tight'); ylim(0,1.25*max(sxx[fr])) show() 

rxx , sxx

output:

average power   p: 0.0410611012542 rxx: 0.0410611012542 sxx: 0.0410611012542  

the peak lag 538, 44100/538 = 81.97 hz. first-pass acyclic dft shows fundamental @ bin 61, 82.10 +/- 0.67 hz. 2nd pass uses window length of 538*15 = 8070, dft frequencies include fundamental period , harmonics of string. enables ubiased cyclic autocorrelation improved psd estimate less harmonic spreading (i.e. correlation can wrap around window periodically).

edit: updated use welch's method estimate autocorrelation. overlapping windows compensates hamming window. calculate tapered bias of hamming window unbias autocorrelation.

edit: added 2nd pass cyclic correlation clean power spectral density. pass uses 3 non-overlapping, rectangular windows length 538*15 = 8070 (short enough stationary). bias cyclic correlation constant, instead of hamming window's tapered bias.


Comments

Popular posts from this blog

apache - Add omitted ? to URLs -

redirect - bbPress Forum - rewrite to wwww.mysite prohibits login -

php - How can I stop spam on my custom forum/blog? -