Я хочу создать приложение для гитарного тюнера для Iphone. Моя цель - найти основную частоту звука, генерируемого гитарной струной. Я использовал биты кода из образца aurioTouch, предоставленного Apple, для вычисления частотного спектра, и я нахожу частоту с наибольшей амплитудой. Он отлично работает для чистых звуков (те, которые имеют только одну частоту), но для звуков с гитарной струны они порождают неправильные результаты. Я читал, что это из-за обертонов, генерируемых гитарной струной, которая может иметь более высокие амплитуды, чем фундаментальные. Как я могу найти основную частоту, чтобы она работала на гитарных струнах? Есть ли библиотека с открытым исходным кодом в C/С++/Obj-C для анализа звука (или обработки сигналов)?
Как найти основную частоту звучания гитарной струны?
Ответ 1
Вы можете использовать автокорреляцию сигнала, которая является обратным преобразованием квадрата величины DFT. Если вы отбираете выборку со скоростью 44100 выборок/с, то фундаментальная составляющая 82,4 Гц составляет около 535 выборок, тогда как 1479,98 Гц составляет около 30 образцов. Посмотрите на пиковое положительное отставание в этом диапазоне (например, от 28 до 560). Убедитесь, что у вашего окна есть как минимум два периода самого длинного фундамента, которые были бы здесь 1070. К следующей мощности два, что буфер с 2048 выборками. Для лучшего частотного разрешения и менее предвзятой оценки используйте более длинный буфер, но не так долго, что сигнал уже не является приблизительно неподвижным. Вот пример в 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 a sample of guitar playing an open string 6
# with a fundamental frequency of 82.4 Hz (in theory),
# but this sample is actually at about 81.97 Hz
g = fromstring(wave.open('dist_gtr_6.wav').readframes(-1),
dtype='int16')
g = g / float64(max(abs(g))) # normalize to +/- 1.0
mi = len(g) / 4 # start index
def welch(x, w, L, N):
# Welch method
M = len(w)
K = (len(x) - L) / (M - L)
Xsq = zeros(N/2+1) # len(N-point rfft) = N/2+1
for k in range(K):
m = k * ( M - L)
xt = w * x[m:m+M]
# use rfft for efficiency (assumes x is real-valued)
Xsq = Xsq + abs(rfft(xt, N)) ** 2
Xsq = Xsq / K
Wsq = abs(rfft(w, N)) ** 2
bias = irfft(Wsq) # for unbiasing Rxx and Sxx
p = dot(x,x) / len(x) # avg power, used as a 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 the side lobes in DFT
Xsq, bias, p = welch(x, w, L, N)
Rxx = irfft(Xsq) # acyclic autocorrelation
Rxx = Rxx / bias # unbias (bias is tapered)
mp = argmax(Rxx[28:561]) + 28 # index of 1st peak in 28 to 560
# 2nd pass: cyclic autocorrelation
N = M = L - (L % mp) # window an integer number of periods
# shortened to ~8192 for stationarity
x = g[mi:mi+K*M] # data for 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 is constant)
mp = argmax(Rxx[28:561]) + 28 # index of 1st peak in 28 to 560
Sxx = Xsq / bias[0]
Sxx[1:-1] = 2 * Sxx[1:-1] # fold the freq axis
Sxx = Sxx / N # normalize S for avg power
n0 = N / mp
np = argmax(Sxx[n0-2:n0+3]) + n0-2 # bin of the 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()
Вывод:
Average Power
p: 0.0410611012542
Rxx: 0.0410611012542
Sxx: 0.0410611012542
Пиковая отставание составляет 538, что составляет 44100/538 = 81,97 Гц. Ациклический ДПФ первого шага показывает фундаментальное значение в бункере 61, которое составляет 82,10 +/- 0,67 Гц. Второй проход использует длину окна 538 * 15 = 8070, поэтому частоты DFT включают в себя фундаментальный период и гармоники струны. Это позволяет избежать циклической автокорреляции для улучшенной оценки PSD с меньшим гармоническим разбросом (т.е. Корреляция может периодически обтекать окно).
Изменить: обновлено, чтобы использовать метод Welch для оценки автокорреляции. Перекрытие окон компенсирует окно Хэмминга. Я также вычисляю сужающееся смещение окна помех, чтобы unbias автокорреляция.
Edit: добавлен второй проход с циклической корреляцией для очистки спектральной плотности мощности. Этот проход использует 3 неперекрывающиеся прямоугольные окна длиной 538 * 15 = 8070 (достаточно короткий, чтобы быть почти неподвижным). Уклонение для циклической корреляции является константой, а не конусообразным смещением окна Хэмминга.
Ответ 2
Нахождение музыкальных смол в аккорде намного сложнее, чем оценка высоты одной струны или заметки, которую играли за раз. Обертоны для нескольких заметок в аккорде могут быть перекрывающимися и чередующимися. И все примечания в обычных аккордах могут сами быть на обертонных частотах для одной или нескольких несуществующих нижних ступенчатых заметок.
Для одиночных заметок автокорреляция является общей методикой, используемой некоторыми гитарными тюнерами. Но с автокорреляцией вы должны осознавать некоторую потенциальную неопределенность в октаве, поскольку гитары могут создавать ангармонические и разлагающиеся обертоны, которые, таким образом, точно не соответствуют периоду основного тона и тангажу. Cepstrum и Harmonic Product Spectrum - это два других метода оценки шага, которые могут иметь или не иметь разных проблем, в зависимости от гитары и примечания.
RAPT представляется одним опубликованным алгоритмом для более надежной оценки шага. YIN - это другое.
Также Objective C является надмножеством ANSI C. Таким образом, вы можете использовать любые подпрограммы C DSP, которые вы найдете для оценки шага в приложении Objective C.
Ответ 3
Используйте libaubio (ссылка) и будьте счастливы. Это было самое большое время для меня, чтобы попытаться внедрить оценочную частотную оценку. Если вы хотите сделать это самостоятельно, я советую вам следовать методу YINFFT (ссылка)