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
1000HzにまたがるDFTのサンプル数です(希望)。IEにはHzfrequencies.Length / 2
までの周波数振幅データが含まれているため、 =は正しい値を与えるはずですrate/2
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 にフェードします。
何か案は?
ありがとう!