बीट डिटेक्शन और एफएफटी


13

मैं एक प्लेटफ़ॉर्मर गेम पर काम कर रहा हूं जिसमें बीट डिटेक्शन वाला संगीत शामिल है। मैं वर्तमान में एक ऐतिहासिक नमूने से अधिक होने पर धड़कन का पता लगा रहा हूं। यह रॉक की तरह संगीत की शैलियों के साथ अच्छी तरह से काम नहीं करता है, जिसमें एक बहुत स्थिर आयाम है।

इसलिए मैंने आगे देखा और पाया कि एल्गोरिदम एफएफटी का उपयोग करके कई बैंडों में ध्वनि को विभाजित कर रहा था ... फिर मुझे कॉली-टके एफएफटी एल्गोरिथ्म मिला

एकमात्र समस्या यह है कि मैं ऑडियो के लिए काफी नया हूं और मुझे पता नहीं है कि सिग्नल को कई सिग्नल में विभाजित करने के लिए इसका उपयोग कैसे करें।

तो मेरा सवाल है:

सिग्नल को कई बैंड में विभाजित करने के लिए आप एफएफटी का उपयोग कैसे करते हैं?

इसके अलावा रुचि रखने वालों के लिए, यह c # में मेरा एल्गोरिथ्म है:

// C = threshold, N = size of history buffer / 1024
    public void PlaceBeatMarkers(float C, int N)
    {
        List<float> instantEnergyList = new List<float>();
        short[] samples = soundData.Samples;

        float timePerSample = 1 / (float)soundData.SampleRate;
        int sampleIndex = 0;
        int nextSamples = 1024;

        // Calculate instant energy for every 1024 samples.
        while (sampleIndex + nextSamples < samples.Length)
        {

            float instantEnergy = 0;

            for (int i = 0; i < nextSamples; i++)
            {
                instantEnergy += Math.Abs((float)samples[sampleIndex + i]);
            }

            instantEnergy /= nextSamples;
            instantEnergyList.Add(instantEnergy);

            if(sampleIndex + nextSamples >= samples.Length)
                nextSamples = samples.Length - sampleIndex - 1;

            sampleIndex += nextSamples;
        }


        int index = N;
        int numInBuffer = index;
        float historyBuffer = 0;

        //Fill the history buffer with n * instant energy
        for (int i = 0; i < index; i++)
        {
            historyBuffer += instantEnergyList[i];
        }

        // If instantEnergy / samples in buffer < instantEnergy for the next sample then add beatmarker.
        while (index + 1 < instantEnergyList.Count)
        {
            if(instantEnergyList[index + 1] > (historyBuffer / numInBuffer) * C)
                beatMarkers.Add((index + 1) * 1024 * timePerSample); 
            historyBuffer -= instantEnergyList[index - numInBuffer];
            historyBuffer += instantEnergyList[index + 1];
            index++;
        }
    }

मुझे लगता है कि एक अच्छा प्रारंभिक बिंदु है विकिपीडिया की एफएफटी और डीएसपी प्रविष्टियां। बीट डिटेक्शन एंट्री विरल है, लेकिन gamedev.net पर एक लेख के
टोबीस किन्ज़लर

जवाबों:


14

ठीक है, यदि आपका इनपुट संकेत वास्तविक है (जैसा कि प्रत्येक नमूना एक वास्तविक संख्या है), तो स्पेक्ट्रम सममित और जटिल होगा। समरूपता को छोड़कर, आमतौर पर एफएफटी एल्गोरिदम आपको स्पेक्ट्रम के केवल सकारात्मक आधे हिस्से को वापस देकर परिणाम पैक करते हैं। प्रत्येक बैंड का वास्तविक हिस्सा सम नमूनों में होता है और विषम नमूनों में काल्पनिक भाग। या कभी-कभी वास्तविक भागों को प्रतिक्रिया के पहले भाग में और दूसरे भाग में काल्पनिक भागों को एक साथ पैक किया जाता है।

सूत्रों में, यदि X [k] = FFT (x [n]), तो आप इसे एक वेक्टर i [n] = x [n] देते हैं, और एक आउटपुट ओ [m] प्राप्त करते हैं, फिर

X[k] = o[2k] + j·o[2k+1]

(हालाँकि कभी-कभी आपको X [k] = o [k] + j · o [k + K / 2] मिलता है, जहाँ K आपकी खिड़की की लंबाई, आपके उदाहरण में 1024) है। वैसे, j काल्पनिक इकाई है, sqrt (-1)।

एक बैंड के परिमाण की गणना इस बैंड के उत्पाद की जड़ के रूप में की जाती है, जिसके जटिल संयुग्म होते हैं:

|X[k]| = sqrt( X[k] · X[k]* )

और ऊर्जा को परिमाण के वर्ग के रूप में परिभाषित किया गया है।

यदि हम a = o [2k] और b = o [2k + 1] कहते हैं, तो हम प्राप्त करते हैं

X[k] = a + j·b

इसलिये

E[k] = |X[k]|^2 = (a+j·b)·(a-j·b) = a·a + b·b

पूरी बात को अनियंत्रित करना, अगर आपको FFT एल्गोरिदम से आउटपुट के रूप में o [m] मिला है, बैंड k में ऊर्जा है:

E[k] = o[2k] · o[2k] + o[2k+1] · o[2k+1]

(नोट: मैंने संयुग्मन संचालक के साथ भ्रम से बचने के लिए प्रतीक का प्रयोग सामान्य के बजाय गुणा करने के लिए किया है)

बैंड के की आवृत्ति, 44.1Khz का एक नमूना आवृत्ति और 1024 नमूनों की एक खिड़की मानती है, है

freq(k) = k / 1024 * 44100 [Hz]

इसलिए, उदाहरण के लिए, आपका पहला बैंड k = 0 0 Hz का प्रतिनिधित्व करता है, k = 1 43 Hz है, और अंतिम एक k = 511 22KHz (Nyquist आवृत्ति) है।

मुझे उम्मीद है कि यह आपके सवाल का जवाब देता है कि एफएफटी का उपयोग करके आपको प्रति बैंड सिग्नल की ऊर्जा कैसे मिलती है।

परिशिष्ट : टिप्पणी में आपके प्रश्न का उत्तर देना, और यह मान लेना कि आप प्रश्न में पोस्ट किए गए लिंक से कोड का उपयोग कर रहे हैं (सी में कॉली-टके एल्गोरिथ्म): मान लें कि आपके पास शॉर्ट इन्ट्स के वेक्टर के रूप में आपका इनपुट डेटा है:

// len is 1024 in this example.  It MUST be a power of 2
// centerFreq is given in Hz, for example 43.0
double EnergyForBand( short *input, int len, double centerFreq)
{
  int i;
  int band;
  complex *xin;
  complex *xout;
  double magnitude;
  double samplingFreq = 44100.0; 

  // 1. Get the input as a vector of complex samples
  xin = (complex *)malloc(sizeof(struct complex_t) * len);

  for (i=0;i<len;i++) {
    xin[i].re = (double)input[i];
    xin[i].im = 0;
  }

  // 2. Transform the signal
  xout = FFT_simple(xin, len);

  // 3. Find the band ( Note: floor(x+0.5) = round(x) )
  band = (int) floor(centerFreq * len / samplingFreq + 0.5); 

  // 4. Get the magnitude
  magnitude = complex_magnitude( xout[band] );

  // 5. Don't leak memory
  free( xin );
  free( xout );

  // 6. Return energy
  return magnitude * magnitude;
}

मेरा C थोड़ा कठोर है (मैं आजकल C ++ में ज्यादातर कोडिंग करता हूं), लेकिन मुझे उम्मीद है कि मैंने इस कोड के साथ कोई बड़ी गलती नहीं की है। बेशक यदि आप अन्य बैंड की ऊर्जा में रुचि रखते थे, तो इससे कोई मतलब नहीं है कि उनमें से प्रत्येक के लिए पूरी खिड़की को बदलना, यह सीपीयू समय की बर्बादी होगी। उस स्थिति में एक बार परिवर्तन करें और उन सभी मूल्यों को प्राप्त करें जिनकी आपको xout से आवश्यकता है।


ओह, मैंने आपके द्वारा लिंक किए गए कोड पर एक नज़र डाली, यह पहले से ही आपको "जटिल" रूप में परिणाम देता है और यहां तक ​​कि आपको एक जटिल संख्या के परिमाण की गणना करने के लिए एक फ़ंक्शन भी प्रदान करता है। फिर आपको केवल आउटपुट वेक्टर के प्रत्येक तत्व के लिए उस परिमाण के वर्ग की गणना करनी होगी, परिणामों को छांटने की चिंता करने की आवश्यकता नहीं है।
सेजय

एक उदाहरण के रूप में यदि मेरे पास विंडो 0-1024 से सभी 1024 नमूने हैं और मैंने उन्हें वास्तविक मूल्यों के रूप में प्राप्त किया है, तो कोई जटिल हिस्सा नहीं है। और मैं आवृत्ति बैंड 43 हर्ट्ज पर वहां की ऊर्जा की गणना करना चाहता हूं। फिर मैं इसे कैसे एकीकृत करूंगा? (मुझे केवल वास्तविक हिस्से की आवश्यकता है, पश्च भाग की) यदि आप इसे कुछ छद्मकोड में कर सकते हैं तो मैं आपकी गहराई में हमेशा के लिए रहूंगा और फिर मैं वास्तव में इस अवधारणा को थोड़ा समझ सकता हूं :)
क्विंसी

मेरे द्वारा लिखा गया कोड आपके द्वारा लिंक किए गए सी लाइब्रेरी का उपयोग कर रहा है, जिसमें पहले से ही एक "जटिल" संरचना है। यह मेरे सवाल में वर्णित अलिखित बनाता है (और कोड को दर्शाता है कि)
CeeJay


0

मैंने ऐसा नहीं किया है या इसके बारे में खुद नहीं पढ़ा है, लेकिन मेरा पहला शॉट कुछ इस तरह है:

सबसे पहले, आपको एफएफटी के साथ समय पर निर्भर स्पेक्ट्रम पाने के लिए एक विंडो फ़ंक्शन लागू करना होगा। हरा आमतौर पर कम आवृत्तियों में निहित होता है, इसलिए इनमें से कुछ आवृत्तियों की सादगी पर एक बड़ी समय खिड़की के साथ एक और एफएफटी लागू करें (सादगी के लिए केवल 1 से शुरू होता है जैसे कि 100 हर्ट्ज और देखें कि क्या यह पर्याप्त विश्वसनीय है)। इस स्पेक्ट्रम में चोटी का पता लगाएं और यह आवृत्ति बीट के लिए एक अनुमान है।


इसका वास्तव में बीट डिटेक्शन नहीं है, लेकिन मुझे यह समझने में परेशानी हो रही है कि एफएफटी का काम कैसा है। मैं प्रॉसेसिंग और चीजों की ओर संकेत करने के लिए वास्तव में नया हूं: "एफएफटी के साथ समय पर निर्भर स्पेक्ट्रम पाने के लिए एक विंडो फ़ंक्शन लागू करें" मेरे लिए कोई मतलब नहीं है। वैसे भी धन्यवाद :)
Quincy
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.