每次使用Processing and Beads运行FFT时,都会得到不同的结果

时间:2018-02-13 14:32:30

标签: java processing signal-processing fft

我正在将处理3与Beads库一起使用以分析大量样本,但每次对相同数据运行分析时,我得到的结果都非常不同。以下是样本和分析设置:

import beads.*;
import org.jaudiolibs.beads.*;

AudioContext ac;
GranularSamplePlayer sample;
Gain gain;

ShortFrameSegmenter sfs;
FFT fft;
PowerSpectrum ps;
Frequency f;
SpectralPeaks sp;
float[][] meanHarmonics;

int numPeaks = 6;

void setup() {
  size(1600, 900);
  ac = new AudioContext();
  ac.start();
  println(dataPath("") + "1.wav");
  sample = new GranularSamplePlayer(ac, SampleManager.sample(dataPath("") + "\\1.wav"));

  gain = new Gain(ac, 1, 1);

  // input chaining
  gain.addInput(sample);
  ac.out.addInput(gain);

  // setup analysis
  // break audio into more manageable chunks
  sfs = new ShortFrameSegmenter(ac);
  sfs.addInput(sample);

  // fast fourier transform to analyse the harmonic spectrum
  fft = new FFT();
  sfs.addListener(fft);

  // PowerSpectrum turns the raw FFT output into proper audio data.
  ps = new PowerSpectrum();
  fft.addListener(ps);

  // Frequency tries to determine the strongest frequency in the wave
  // which is the fundamental that determines the pitch of the sound
  f = new Frequency(44100.0f);
  ps.addListener(f);

  // Listens for harmonics
  sp = new SpectralPeaks(ac, numPeaks);
  ps.addListener(sp);

  meanHarmonics = new float[numPeaks][2];

  // initialise meanHarmonics
  for(int i = 0; i < numPeaks; i++) {
    for(int j = 0; j < 2; j++) {
      meanHarmonics[i][j] = 0;
    }
  }

  ac.out.addDependent(sfs);

  int startTime = millis();
  int loops = 0;
  float meanFrequency = 0.0;
  while(millis() - startTime < 1500) {
    loops++;
      if(loops == 1) {
       sample.start(0); 
      }
      Float inputFrequency = f.getFeatures();
      if(inputFrequency != null) {
        meanFrequency += inputFrequency;
      }
      float[][] harmonics = sp.getFeatures();
      if(harmonics != null) {
        for(int feature = 0; feature < numPeaks; feature++) {
         // harmonic must be in human audible range
         // and its amplitude must be large enough to be audible
         if(harmonics[feature][0] < 20000.0 && harmonics[feature][1] > 0.01) {
          // average out the frequencies
          meanHarmonics[feature][0] += harmonics[feature][0];
          // average out the amplitudes
          meanHarmonics[feature][1] += harmonics[feature][1]; 
         }
        }
      }
    }
    float maxAmp = 0.0;
    float freq = 0.0;
    sample.pause(true);
    meanFrequency /= loops;
    println(meanFrequency);
    for(int feature = 0; feature < numPeaks; feature++) {
      meanHarmonics[feature][0] /= loops;
      meanHarmonics[feature][1] /= loops;
      if(meanHarmonics[feature][1] > maxAmp) {
        freq = meanHarmonics[feature][0];
        maxAmp = meanHarmonics[feature][1];
      }
      println(meanHarmonics[feature][0] + " " + meanHarmonics[feature][1]);
    }
    println(freq + " " + meanFrequency);
    println();
}

我运行FFT一段时间,在此期间我将Frequency对象和SpectralPeaks功能返回的频率相加。 最后,我将累积的频率和幅度分开以获得平均值。我还试图通过找到幅度最大的频率来找到SpectralPeaks阵列中的基频。 但是每次运行我的程序时,我都会得到不同的结果,包括SpectralPeaks和Frequency(它们的值也各不相同)。 以下是一些示例值:

第一轮:

  

Spectral Peaks功能:

     

914.84863 0.040409338

     

844.96295 0.033234257

     

816.0808 0.027509697

     

664.9141 0.022158746

     

633.3232 0.019597264

     

501.93716 0.01606628

     

Spectral Peaks基本:914.84863

     

频率:1028.1572

第二次运行,同样的样本:

  

Spectral Peaks功能:

     

1023.4123 0.03913592

     

1109.2562 0.031178929

     

967.0786 0.026673868

     

721.2698 0.021666735

     

629.9294 0.018046249

     

480.82416 0.014858524

     

Spectral Peaks基础:1023.4123

     

频率:1069.3387

此外,频率返回的值通常是NaN,我不明白为什么会这样。

1 个答案:

答案 0 :(得分:0)

您的代码返回不同值的原因是因为它在不同时刻对音频进行采样和分析。一旦开始播放音频,就会在Float inputFrequency = f.getFeatures();执行时无法控制。 更好的方法是不使用millis()并将while循环替换为for loop,并使用ac.runForMillisecondsNonRealTime()。通过这种方式,您可以确切地知道您在1500毫秒内执行分析。

  //while(millis() - startTime < 1500) {
  for(int i = 0; i < numPeaks; i++) {
      ac.runForNMillisecondsNonRealTime(1500/numPeaks);      
      Float inputFrequency = f.getFeatures();
      if(inputFrequency != null) {
        meanFrequency += inputFrequency;
      }
      float[][] harmonics = sp.getFeatures();
      if(harmonics != null) {
        for(int feature = 0; feature < numPeaks; feature++) {
         // harmonic must be in human audible range
         // and its amplitude must be large enough to be audible
         if(harmonics[feature][0] < 20000.0 && harmonics[feature][1] > 0.01) {
          // average out the frequencies
          meanHarmonics[feature][0] += harmonics[feature][0];
          // average out the amplitudes
          meanHarmonics[feature][1] += harmonics[feature][1]; 
         }
        }
      }
    }