【发布时间】:2017-06-16 06:25:17
【问题描述】:
我一直在使用 Rosetta Code 提供的原始 FFT 算法研究频移器。我知道要对样本信号进行频移,可以将 FFT 应用于原始音频,将每个生成的正弦波的频率乘以频移因子(用户定义),然后将正弦波加在一起。当我运行我的算法时,输出质量极低,就好像在算法中没有收集到足够的正弦波,无法在一开始就正确地再现信号。该算法在头文件中的类中实现,并在其他地方(正确)调用。
#include <complex>
#include <valarray>
typedef std::complex<double> Complex;
typedef std::valarray<Complex> CArray;
class FrequencyShifter {
float sampleRate;
public:
FrequencyShifter() {
}
void setSampleRate(float inSampleRate) {
sampleRate = inSampleRate;
}
double abs(double in0) {
if (in0>=0) return in0;
else return -in0;
}
void fft(CArray& x)
{
const size_t N = x.size();
if (N <= 1) return;
// divide
CArray even = x[std::slice(0, N/2, 2)];
CArray odd = x[std::slice(1, N/2, 2)];
// conquer
fft(even);
fft(odd);
// combine
for (size_t k = 0; k < N/2; ++k)
{
Complex t = std::polar(1.0, -2 * PI * k / N) * odd[k];
x[k ] = even[k] + t;
x[k+N/2] = even[k] - t;
}
}
double convertToReal(double im, double re) {
return sqrt(abs(im*im - re*re));
}
void processBlock(float *inBlock, const int inFramesToProcess, float scale) {
//inFramesToProcess is the amount of samples in inBlock
Complex *copy = new Complex[inFramesToProcess];
for (int frame = 0; frame<inFramesToProcess; frame++) {
copy[frame] = Complex((double)inBlock[frame], 0.0);
}
CArray data(copy, inFramesToProcess);
fft(data);
const float freqoffsets = sampleRate/inFramesToProcess;
for (float x = 0; x<data.size()/2; x++) {
for (float frame = 0; frame<inFramesToProcess; frame++) {
inBlock[(int)frame] = (float)(convertToReal(data[(int)x].imag(), data[(int)x].real())*sin(freqoffsets*x*frame*scale));
}
}
}
};
我假设问题的一部分是我只包括sampleRate/inFramesToProcess 频率来覆盖正弦波。发送更大的音频文件(因此更大的*inBlocks 和inFramesToProcesss)会使音频的颗粒感减少吗?我将如何在不仅更改参数的值或长度的情况下完成此操作?
【问题讨论】:
-
“没有输出”是什么意思?
-
@1201ProgramAlarm 当我测试
*inBlock的输出时,没有电平(音频电平为 0 或遇到其他错误)。本质上,算法中存在一些我无法检测和修复的错误。 -
convertToReal正确吗?很简单,如果inFramesToProcess是 1,data将有一个没有虚部的复数。fft不会对它做任何事情,所以当它被转换回来时,你会尝试取负数的 sqrt。重要的是,如果x.size()是奇数,fft不会对x的最后一个元素做任何事情。 -
@1201ProgramAlarm 啊,感谢您的提醒!这两件事我都没有意识到。我会尽快修复它们并更新帖子。这可能是我正在寻找的解决方法。
-
@1201ProgramAlarm 我在试图解决这两个问题时走到了死胡同。如果您能将您的回复充实为答案,我将不胜感激。