iPhone用のギターチューナーアプリを作りたいです。私の目標は、ギターの弦によって生成される音の基本周波数を見つけることです。Apple から提供された aurioTouch サンプルのコードを使用して周波数スペクトルを計算し、振幅が最大の周波数を見つけました。純粋な音 (周波数が 1 つしかない音) ではうまく機能しますが、ギターの弦からの音では間違った結果になります。これは、ギターの弦によって生成される倍音が、基音よりも高い振幅を持つ可能性があるためであると読んだことがあります。ギターの弦で機能するように基本周波数を見つけるにはどうすればよいですか? C/C++/Obj-C に音声分析 (または信号処理) 用のオープンソース ライブラリはありますか?
3 に答える
信号の自己相関を使用できます。これは、DFT の振幅の 2 乗の逆変換です。44100 サンプル/秒でサンプリングしている場合、82.4 Hz の基本波は約 535 サンプルですが、1479.98 Hz は約 30 サンプルです。その範囲 (たとえば、28 から 560) で正のラグのピークを探します。ウィンドウが最長の基本波の少なくとも 2 周期であることを確認してください。これは、ここでは 1070 サンプルになります。2048 サンプル バッファーである次の 2 のべき乗まで。周波数分解能を向上させ、推定の偏りを少なくするには、より長いバッファーを使用しますが、信号がほぼ定常でなくなるほど長くはしません。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's 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 Hz です。最初のパスの非巡回 DFT は、ビン 61 で基本波を示します。これは 82.10 +/- 0.67 Hz です。2 番目のパスでは 538*15 = 8070 のウィンドウ長が使用されるため、DFT 周波数には弦の基本周期と高調波が含まれます。これにより、高調波拡散の少ない改善された PSD 推定のための偏りのある周期的自己相関が可能になります (つまり、相関はウィンドウを周期的にラップすることができます)。
編集:ウェルチの方法を使用して自己相関を推定するように更新されました。ウィンドウを重ねると、ハミング ウィンドウが補正されます。また、ハミング ウィンドウのテーパー バイアスを計算して、自己相関のバイアスを取り除きます。
編集: パワー スペクトル密度をクリーンアップするために、循環相関を使用した 2 番目のパスを追加しました。このパスは、長さが 538*15 = 8070 (ほぼ静止するのに十分な短さ) の 3 つのオーバーラップしない長方形のウィンドウを使用します。循環相関のバイアスは、ハミング ウィンドウのテーパー バイアスではなく定数です。
和音の音程を見つけることは、一度に演奏される 1 つの弦または音符の音程を推定するよりもはるかに困難です。コード内の複数の音の倍音は、すべて重なり合い、インターリーブしている可能性があります。また、一般的な和音のすべての音は、1 つまたは複数の存在しない低いピッチの音の倍音周波数にある場合があります。
単音の場合、自己相関は、一部のギター チューナーが使用する一般的な手法です。ただし、自己相関では、オクターブの不確実性が生じる可能性があることに注意する必要があります。ギターは、ピッチ周期ごとに正確に一致しない不協和音や減衰倍音を生成する可能性があるためです。ケプストラムとハーモニック プロダクト スペクトルは、ギターとノートに応じて、異なる問題がある場合とない場合がある他の 2 つのピッチ推定方法です。
RAPTは、よりロバストなピッチ推定のための公開されたアルゴリズムの 1 つと思われます。YINは別です。
また、Objective C は ANSI C のスーパーセットです。そのため、Objective C アプリ内でピッチを推定するために見つけた任意の C DSP ルーチンを使用できます。