如何修正谐波产品频谱中的八度音程误差?

时间:2016-11-11 09:21:01

标签: c# fft pitch-tracking

我正在创建一个语音培训应用程序,我使用FFT将信号从时域转换到频域。在应用FFT之前,我使用blackman-harris窗口对信号进行了窗口化。然后我使用谐波产品频谱来提取基频。最低频率为F2(87.307 Hz),最高频率为C6(1046.502 Hz)。 FFT长度为8192,采样频率为44100 Hz。

为了解决八度音阶错误,我将here提到的规则应用于

     float[] array = hps.HPS(Data);
     float hpsmax_mag = float.MinValue;
     float hpsmax_index = -1;

     for (int i = 0; i < array.Length; i++)
          if (array[i] > hpsmax_mag)
              {
                 hpsmax_mag = array[i];
                 hpsmax_index = i;
              }

   // Fixing octave too high errors    
      int correctMaxBin = 1;
      int maxsearch = (int) hpsmax_index * 3 / 4;
      for (int j = 2; j < maxsearch; j++)
      {
         if (array[j] > array[correctMaxBin])
         {
             correctMaxBin = j;
         }
      }

      if (Math.Abs(correctMaxBin * 2 - hpsmax_index) < 4)
      {
          if (array[correctMaxBin] / array[(int)hpsmax_index] > 0.2)
          {
              hpsmax_index = correctMaxBin;
          }
      }

我使用锯齿波测试系统,我注意到八度音程错误仍然可见。 87.307 Hz到~190 Hz它会产生八度音高误差。 G5(783.991)向上有时它显示八度低。

以下是一些结果:输入|结果|错误

    F2 (87.307) - F4 (349.228) - 2 octaves higher
    G2 (97.999)- G4 (391.995) - 2 octaves higher
    A2 (110) - A3 (220) - an octave higher
    D3 (146.832) - D4 (mostly) (293.665) and D3 - an octave higher
    A3 (220) - A3 - Correct
    A4 (440) - A4 - Correct
    G5 (783.991) - G5 (mostly) and G4 (391.995) - an octave lower
    A5 (880) - A5 - Correct
    C6 (1046.502) - C6 - Correct

请帮我解决这个问题,因为这会严重影响系统对用户的最终反馈。

1 个答案:

答案 0 :(得分:1)

当我在MP3录音中检测到复音信号的音高和八度时,我使用了一种不同的方法。为了识别包含“音调”的谐波,我选择使用对数间隔的修改后的DFT,而不是FFT。

我还决定使用两阶段算法来检测音高,它在第二阶段的后期确定了八度音(和隐含的基频)。该算法的工作方式如下:

a)首先检测主导音符的ScalePitch - &#39; ScalePitch&#39;有12个可能的音高值:{E,F,F#,G,G#,A,A#,B,C,C#,D,D#}。在确定了音符的ScalePitch和时间宽度后,

b)然后通过检查4种可能的Octave-Candidate音符的所有谐波来计算该音符的Octave(基波)。

八度检测可能非常棘手,特别是对于缺少基波和/或其他谐波的复音信号。但是我的算法会起作用,即使缺少一些谐波也是如此。你可能想在GitHub上为PitchScope Player编译和逐步浏览我的Windows代码,看看我如何确定八度音阶。

您可能希望关注文件FundCandidCalcer.cpp中的FundCandidCalcer :: Calc_Best_Octave_Candidate()函数,以查看C ++中的Octave Detection算法。

https://github.com/CreativeDetectors/PitchScope_Player

https://en.wikipedia.org/wiki/Transcription_(music)#Pitch_detection

下图演示了Octave Detection算法,一旦确定了该音符的ScalePitch和谐波,我就开始选择正确的Octave-Candidate音符(即正确的基本音符)。

enter image description here