音符检测问题的音频样本
Audio samples to musical note detection issue
我正在尝试设置一个管道,允许我从音频样本中检测音符,但是我识别样本频率内容的输入层没有落在预期值上。在下面的示例中,我...
- 在 FFTW 输入缓冲器中构建我期望的 440Hz (A4) sine wave
- 应用Hamming window function
- 查找输出 bin 的前半部分以找到 4 个最高值及其频率
void GenerateSinWave(fftw_complex* outputArray, int N, double frequency, double samplingRate)
{
double sampleDurationSeconds = 1.0 / samplingRate;
for (int i = 0; i < N; ++i)
{
double sampleTime = i * sampleDurationSeconds;
outputArray[i][0] = sin(M_2_PI * frequency * sampleTime);
}
}
void HammingWindow(fftw_complex* array, int N)
{
static const double a0 = 25.0 / 46.0;
static const double a1 = 1 - a0;
for (int i = 0; i < N; ++i)
array[i][0] *= a0 - a1 * cos((M_2_PI * i) / N);
}
int main()
{
const int N = 4096;
double samplingRate = 44100;
double A4Frequency = 440;
fftw_complex in[N] = { 0 };
fftw_complex out[N] = { 0 };
fftw_plan plan = fftw_plan_dft_1d(N, 0, 0, FFTW_FORWARD, FFTW_ESTIMATE);
GenerateSinWave(in, N, A4Frequency, samplingRate);
HammingWindow(in, N);
fftw_execute_dft(plan, in, out);
// Find the 4 top values
double binHzRange = samplingRate / N;
for (int i = 0; i < 4; ++i)
{
double maxValue = 0;
int maxBin = 0;
for (int bin = 0; bin < (N/2); ++bin)
{
if (out[bin][0] > maxValue)
{
maxValue = out[bin][0];
maxBin = bin;
}
}
out[maxBin][0] = 0; // remove value for next pass
double binMidFreq = (maxBin * binHzRange) + (binHzRange / 2);
std::cout << (i + 1) << " -> Freq: " << binMidFreq << " Hz - Value: " << maxValue << "\n";
}
fftw_destroy_plan(plan);
}
我期待接近 440 或 lower/higher 谐波,但结果远非如此:
1 -> Freq: 48.4497Hz - Value: 110.263
2 -> Freq: 59.2163Hz - Value: 19.2777
3 -> Freq: 69.9829Hz - Value: 5.68717
4 -> Freq: 80.7495Hz - Value: 2.97571
此流程的灵感主要来自 this other SO answer。我觉得我对信号处理知识的缺乏可能是原因!我的sin wave generation和window功能貌似没问题,但是audio analysis和FFTW就充满了玄机...
任何关于如何改进我对 FFTW 的使用、方法信号处理或简单地编写更好的代码的见解都将受到赞赏!
编辑:固定整数除法导致 Hamming a0 参数始终为 0。结果略有变化,但仍远未达到预期的 440 Hz
我认为您误解了 GenerateSinWave
函数中的 M_2_PI
常量。 M_2_PI
是 defined 和 2.0 / PI
。
您应该改用 2 * M_PI
。
这个错误意味着您生成的信号的频率只有 45 赫兹左右。这应该接近您看到的输出频率。
同样的常量也需要在您的 HammingWindow
函数中更正。
我正在尝试设置一个管道,允许我从音频样本中检测音符,但是我识别样本频率内容的输入层没有落在预期值上。在下面的示例中,我...
- 在 FFTW 输入缓冲器中构建我期望的 440Hz (A4) sine wave
- 应用Hamming window function
- 查找输出 bin 的前半部分以找到 4 个最高值及其频率
void GenerateSinWave(fftw_complex* outputArray, int N, double frequency, double samplingRate)
{
double sampleDurationSeconds = 1.0 / samplingRate;
for (int i = 0; i < N; ++i)
{
double sampleTime = i * sampleDurationSeconds;
outputArray[i][0] = sin(M_2_PI * frequency * sampleTime);
}
}
void HammingWindow(fftw_complex* array, int N)
{
static const double a0 = 25.0 / 46.0;
static const double a1 = 1 - a0;
for (int i = 0; i < N; ++i)
array[i][0] *= a0 - a1 * cos((M_2_PI * i) / N);
}
int main()
{
const int N = 4096;
double samplingRate = 44100;
double A4Frequency = 440;
fftw_complex in[N] = { 0 };
fftw_complex out[N] = { 0 };
fftw_plan plan = fftw_plan_dft_1d(N, 0, 0, FFTW_FORWARD, FFTW_ESTIMATE);
GenerateSinWave(in, N, A4Frequency, samplingRate);
HammingWindow(in, N);
fftw_execute_dft(plan, in, out);
// Find the 4 top values
double binHzRange = samplingRate / N;
for (int i = 0; i < 4; ++i)
{
double maxValue = 0;
int maxBin = 0;
for (int bin = 0; bin < (N/2); ++bin)
{
if (out[bin][0] > maxValue)
{
maxValue = out[bin][0];
maxBin = bin;
}
}
out[maxBin][0] = 0; // remove value for next pass
double binMidFreq = (maxBin * binHzRange) + (binHzRange / 2);
std::cout << (i + 1) << " -> Freq: " << binMidFreq << " Hz - Value: " << maxValue << "\n";
}
fftw_destroy_plan(plan);
}
我期待接近 440 或 lower/higher 谐波,但结果远非如此:
1 -> Freq: 48.4497Hz - Value: 110.263
2 -> Freq: 59.2163Hz - Value: 19.2777
3 -> Freq: 69.9829Hz - Value: 5.68717
4 -> Freq: 80.7495Hz - Value: 2.97571
此流程的灵感主要来自 this other SO answer。我觉得我对信号处理知识的缺乏可能是原因!我的sin wave generation和window功能貌似没问题,但是audio analysis和FFTW就充满了玄机...
任何关于如何改进我对 FFTW 的使用、方法信号处理或简单地编写更好的代码的见解都将受到赞赏!
编辑:固定整数除法导致 Hamming a0 参数始终为 0。结果略有变化,但仍远未达到预期的 440 Hz
我认为您误解了 GenerateSinWave
函数中的 M_2_PI
常量。 M_2_PI
是 defined 和 2.0 / PI
。
您应该改用 2 * M_PI
。
这个错误意味着您生成的信号的频率只有 45 赫兹左右。这应该接近您看到的输出频率。
同样的常量也需要在您的 HammingWindow
函数中更正。