2011-02-18 18 views
17

मैं आईफोन के लिए गिटार ट्यूनर ऐप बनाना चाहता हूं। मेरा लक्ष्य गिटार स्ट्रिंग द्वारा उत्पन्न ध्वनि की मौलिक आवृत्ति को ढूंढना है। मैंने आवृत्ति स्पेक्ट्रम की गणना करने के लिए ऐप्पल द्वारा प्रदान किए गए ऑरियो टच नमूने से कोड के बिट्स का उपयोग किया है और मुझे उच्चतम आयाम के साथ आवृत्ति मिलती है। यह शुद्ध ध्वनियों के लिए ठीक काम करता है (जिनके पास केवल एक आवृत्ति है) लेकिन गिटार स्ट्रिंग से ध्वनि के लिए यह गलत परिणाम उत्पन्न करता है। मैंने पढ़ा है कि यह गिटार स्ट्रिंग द्वारा उत्पन्न ओवरटोन की वजह से है जो मूलभूत से अधिक आयाम हो सकता है। मैं मौलिक आवृत्ति कैसे पा सकता हूं ताकि यह गिटार तारों के लिए काम करे? ध्वनि विश्लेषण (या सिग्नल प्रोसेसिंग) के लिए सी/सी ++/ओबीजे-सी में ओपन-सोर्स लाइब्रेरी है?गिटार स्ट्रिंग ध्वनि की मौलिक आवृत्ति कैसे प्राप्त करें?

+1

मैं संगीतकार नहीं हूं, लेकिन यदि आप ट्यूनर करने की कोशिश कर रहे हैं, तो आपको एक तार की पहचान करने की आवश्यकता क्यों है? एक समय में एक स्ट्रिंग ट्यून करना आसान नहीं होगा? – mtrw

+0

@mtrw यह वर्तनी गलती थी ... इसे "तार" के बजाय "कॉर्ड" होना चाहिए था ... मुझे गलतफहमी के लिए खेद है – Mircea

+6

तो त्रुटि को ठीक करने के लिए इसे संपादित करें! और किसी और भ्रम से बचने के लिए "स्ट्रिंग" शब्द का उपयोग करें। – Clifford

उत्तर

45

आप सिग्नल के ऑटोकोरेशन का उपयोग कर सकते हैं, जो डीएफटी के परिमाण वर्ग के विपरीत परिवर्तन है। यदि आप 44100 नमूने/एस पर नमूना कर रहे हैं, तो 82.4 हर्ट्ज मौलिक लगभग 535 नमूने हैं, जबकि 1479.98 हर्ट्ज लगभग 30 नमूने हैं। उस सीमा में चरम सकारात्मक अंतराल की तलाश करें (उदाहरण के लिए 28 से 560 तक)। सुनिश्चित करें कि आपकी खिड़की कम से कम दो मौलिक मौलिक है, जो यहां 1070 नमूने होंगे। दो की अगली शक्ति के लिए जो 2048-नमूना बफर है। बेहतर आवृत्ति संकल्प और कम पक्षपातपूर्ण अनुमान के लिए, लंबे बफर का उपयोग करें, लेकिन इतना लंबा नहीं है कि सिग्नल अब स्थिर नहीं है। यहाँ पायथन में एक उदाहरण है:

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() 

Rxx and Sxx

आउटपुट:

Average Power 
    p: 0.0410611012542 
Rxx: 0.0410611012542 
Sxx: 0.0410611012542 

शिखर अंतराल 538 है, जो 44100/538 = 81.97 हर्ट्ज है। प्रथम-पास विश्वकोश डीएफटी बिन 61 में मौलिक दिखाता है, जो 82.10 +/- 0.67 हर्ट्ज है। दूसरा पास 538 * 15 = 8070 की खिड़की की लंबाई का उपयोग करता है, इसलिए डीएफटी आवृत्तियों में स्ट्रिंग की मौलिक अवधि और हार्मोनिक्स शामिल हैं। यह कम हार्मोनिक फैलाव के साथ एक बेहतर PSD अनुमान के लिए एक उबला हुआ चक्रीय autocorrelation सक्षम बनाता है (यानी सहसंबंध समय-समय पर खिड़की के चारों ओर लपेट सकता है)।

संपादित करें: स्वत: सहसंबंध का अनुमान लगाने के लिए वेल्च विधि का उपयोग करने के लिए अपडेट किया गया। खिड़कियों को ओवरलैप करना हैमिंग विंडो के लिए क्षतिपूर्ति करता है। मैं autocorrelation unbias करने के लिए हथौड़ा खिड़की के पतला पूर्वाग्रह की भी गणना करता हूं।

संपादित करें: पावर स्पेक्ट्रल घनत्व को साफ करने के लिए चक्रीय सहसंबंध के साथ दूसरा पास जोड़ा गया। यह पास 3 गैर-ओवरलैपिंग, आयताकार खिड़कियों की लंबाई 538 * 15 = 8070 (लगभग स्थिर होने के लिए पर्याप्त छोटा) का उपयोग करता है। चक्रीय खिड़की के पतला पूर्वाग्रह के बजाय चक्रीय सहसंबंध के लिए पूर्वाग्रह स्थिर है।

+5

+1 आश्चर्यजनक रूप से समृद्ध उत्तर। – jv42

+1

क्या यह तकनीक काम करती है जब मूलभूत हार्मोनिक्स (या पूरी तरह से गायब) से छोटा होता है? – mtrw

+1

@mtrw: यदि आपके पास 2 हर्ट्ज ओवरटोन और 3 हर्ट्ज ओवरटोन है, तो त्रिकोणीय दिखने वाले परिणामी तरंगों को अभी भी हर 1 सेकेंड दोहराया जाएगा, जो एक लंबी पर्याप्त खिड़की पर स्वत: सहसंबंध शून्य शून्य 1 हर्ट्ज साइनसॉइडल सामग्री के साथ भी मिलेगा। – hotpaw2

4

एक तार में संगीत पिच ढूंढना एक ही स्ट्रिंग या एक समय में नोट के पिच का अनुमान लगाने से कहीं अधिक कठिन है। एक तार में एकाधिक नोट्स के लिए ओवरटोन सभी ओवरलैपिंग और इंटरलिविंग हो सकते हैं। और आम तारों में सभी नोट्स स्वयं एक या अधिक गैर-मौजूद निचले पॉट नोटों के लिए आवृत्तियों पर अधिक हो सकते हैं।

एकल नोट्स के लिए, ऑटोकोरेशन एक गिटार ट्यूनर्स द्वारा उपयोग की जाने वाली एक आम तकनीक है। लेकिन स्वायत्तता के साथ, आपको कुछ संभावित ऑक्टेटव अनिश्चितता से अवगत होना चाहिए, क्योंकि गिटार इनहेर्मोनिक और क्षय वाले ओवरटोन उत्पन्न कर सकते हैं जो इस प्रकार पिच अवधि से पिच अवधि तक बिल्कुल मेल नहीं खाते हैं। सेप्स्ट्रम और हार्मोनिक उत्पाद स्पेक्ट्रम गिटार और नोट के आधार पर दो अन्य पिच अनुमान विधियां हैं जिनके पास अलग-अलग समस्याएं हो सकती हैं या नहीं।

RAPT अधिक मजबूत पिच अनुमान के लिए एक प्रकाशित एल्गोरिदम प्रतीत होता है। यिन एक और है।

इसके अलावा उद्देश्य सी एएनएसआई सी का एक सुपरसेट है। इसलिए आप किसी उद्देश्य सी ऐप के भीतर पिच अनुमान के लिए किसी भी सी डीएसपी दिनचर्या का उपयोग कर सकते हैं।

+0

@eryksun आप सही हैं ... मैं "स्ट्रिंग" के लिए समानार्थी के रूप में "कॉर्ड" लिखना चाहता हूं – Mircea

+0

आपके उत्तर के लिए धन्यवाद और मुझे "तार" - "कॉर्ड" गलती के लिए खेद है – Mircea

3

libaubio (link) का उपयोग करें और खुश रहें। एक मौलिक आवृत्ति अनुमानक को लागू करने की कोशिश करने के लिए यह मेरे लिए सबसे बड़ा समय था। यदि आप इसे स्वयं करना चाहते हैं तो मैं आपको सलाह देता हूं कि आप YINFFT विधि (link)

संबंधित मुद्दे