我正在将处理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,我不明白为什么会这样。
答案 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];
}
}
}
}