我在用 DFT 制作简单的低通滤波器时遇到了一些麻烦。最后,我希望能够实时转换音频,但就目前而言,我什至无法做到这一点。我在这方面没有受过培训,我只知道 FFT 将波转换为频率,而 iFFT 会这样做,以及我读过的其他一些内容。老实说,我很惊讶它的效果和到目前为止一样好。无论如何,这是代码:
byte[] samples = new byte[20000000];
int spos = 0;
samples
这里用 8Bit Unsigned PCM 填充。spos
<- 样本数
int samplesize = 128;
int sampleCount = spos / samplesize;
frequencies = new System.Numerics.Complex[sampleCount][];
for (int i = 0; i < sampleCount; i++)
{
Console.WriteLine("Sample " + i + " / " + sampleCount);
frequencies[i] = new System.Numerics.Complex[samplesize];
for (int j = 0; j < samplesize; j++)
{
frequencies[i][j] = (float)(samples[i * samplesize + j] - 128) / 128.0f;
}
dft.Radix2Forward(frequencies[i], MathNet.Numerics.IntegralTransforms.FourierOptions.Default);
}
int shiftUp = 1000; //1khz
int fade = 2; //8 sample fade.
int kick = frequencies[0].Length * shiftUp / rate;
所以现在我已经为输入的 128 个样本部分计算了一堆 DFT。kick
是(我希望)DFT 中跨越 1000Hz 的样本数。IE 因为frequencies.Length / 2
包含高达rate/2
Hz 的频率幅度数据,所以frequencies[0].Length / 2 * shiftUp / (rate / 2)
=frequencies[0].Length * shiftUp / rate
应该给我正确的值
for (int i = 0; i < sampleCount; i++)
{
这是我遇到麻烦的部分。没有它,输出听起来很棒!这会跳过索引 0 和索引 64。它们都有一个复杂的 0 分量,我记得在某处读过索引 0 处的值很重要......
for (int j = 0; j < frequencies[i].Length; j++)
{
if (j == 0 || j == 64)
continue;
if (j < 64)
{
if (!(j < kick + 1))
{
frequencies[i][j] = 0;
}
}
else
{
if (!(j - 64 > 63 - kick))
{
frequencies[i][j] = 0;
}
}
}
最后它撤消了转换
dft.Radix2Inverse(frequencies[i], MathNet.Numerics.IntegralTransforms.FourierOptions.Default);
...把它扔回样本数组
for (int j=0; j<samplesize; j++)
samples[i * samplesize + j] = (byte)(frequencies[i][j].Real * 128.0f + 128.0f);
}
...将其放入文件中
BinaryWriter bw = new BinaryWriter(File.OpenWrite("sound"));
for (int i = 0; i < spos; i++)
{
bw.Write(samples[i]);
}
bw.Close();
...然后我将其导入 Audacity 以用文物谋杀我的耳朵。
光谱显示显示代码在一定程度上有效
然而,整首歌曲中都会出现这些恼人的高音噼啪声。我听说过有关吉布斯现象和窗口函数的一些信息,但我真的不知道如何在这里应用它。该fade
变量是我对窗口函数的最佳尝试:超过 1000hz 标记的所有内容在 2 个样本中消失为 0。
有任何想法吗?
谢谢!