使用Processing和Beads运行FFT时每次得到不同的结果

3
我正在使用Processing 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 Frequency: 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 Frequency: 1069.3387
此外,Frequency返回的值通常为NaN,我不明白为什么会这样。

你是什么意思? - Djakninn
在panGlide中,每次输入都会改变,你可以使用random.nextFloat()函数来实现。 - gpasch
谢谢,我已将其更改为常量,但仍然得到不同的值和NaN。 - Djakninn
2
调试您的代码,并将问题缩小到一个 [mcve]。您的代码中至少有一个对随机函数的调用,这将给您不同的结果。但在您将问题缩小到[mcve]之前,帮助您将会非常困难。 - Kevin Workman
我已将代码编辑为MCV,之前的混乱很抱歉。我还删除了所有随机函数调用。我不认为我可以提供我正在使用的样本,但它是一个大约14秒的WAV文件。该算法仍然每次返回不同的值,并从频率对象中返回NaN。 - Djakninn
显示剩余2条评论
1个回答

0
你的代码返回不同的值的原因是因为它在不同的时刻对音频进行采样和分析。一旦开始播放音频,你就无法控制何时执行Float inputFrequency = f.getFeatures();。 更好的方法是不使用millis(),用for循环替换while循环,并使用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]; 
         }
        }
      }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接