gpt4 book ai didi

ios - 从 AvassetReader 和 vDSP_FFT 获取 iPhone mp3 频率

转载 作者:塔克拉玛干 更新时间:2023-11-02 10:19:12 25 4
gpt4 key购买 nike

我正在尝试从 iPhone/iPod 音乐库获取频率以用于 iPod 库上的频谱应用程序,帮助自己 reading-audio-samples-via-avassetreader获取音频样本,然后使用 using-the-apple-fft-and-accelerate-frameworkApple vDSP Samples ,但不知何故,我在某处错了,无法计算频率。

所以一步一步:

  • 阅读音频样本
  • 汉宁窗
  • 计算fft

这是从 iPod mp3 库获取频率的正确方法吗?

这是我的代码:

static COMPLEX_SPLIT    A;  
static FFTSetup setupReal;
static uint32_t log2n, n, nOver2;
static int32_t stride;
static float *obtainedReal;
static float scale;

+ (void)initialize
{
log2n = 10;
n = 1 << log2n;

stride = 1;
nOver2 = n / 2;
A.realp = (float *) malloc(nOver2 * sizeof(float));
A.imagp = (float *) malloc(nOver2 * sizeof(float));

obtainedReal = (float *) malloc(n * sizeof(float));
setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);
}


- (float) performAcceleratedFastFourierTransForAudioBuffer:(AudioBufferList)ioData
{
NSUInteger * sampleIn = (NSUInteger *)ioData.mBuffers[0].mData;
for (int i = 0; i < nOver2; i++) {
double multiplier = 0.5 * (1 - cos(2*M_PI*i/nOver2-1));
A.realp[i] = multiplier * sampleIn[i];
A.imagp[i] = 0;
}

memset(ioData.mBuffers[0].mData, 0, ioData.mBuffers[0].mDataByteSize);
vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD);

vDSP_zvmags(&A, 1, A.realp, 1, nOver2);

scale = (float) 1.0 / (2 * n);

vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);

vDSP_ztoc(&A, 1, (COMPLEX *)obtainedReal, 2, nOver2);

int peakIndex = 0;
for (size_t i=1; i < nOver2-1; ++i) {
if ((obtainedReal[i] > obtainedReal[i-1]) && (obtainedReal[i] > obtainedReal[i+1]))
{
peakIndex = i;
break;
}
}

//here I don't know how to calculate frequency with my data
float frequency = obtainedReal[peakIndex-1] / 44100 / n;

vDSP_destroy_fftsetup(setupReal);
free(obtainedReal);
free(A.realp);
free(A.imagp);

return frequency;
}

我得到了 1.4857571.332233 作为我的第一个频率

最佳答案

在我看来,FFT 到复数输入的转换存在问题。 vDSP_ctoz() 将实部和虚部交错的缓冲区拆分为两个缓冲区,一个是实部,一个是虚部。您对该函数的输入似乎只是已转换为 COMPLEX 的真实数据。这意味着您对 vDSP_ctoz() 的输入缓冲区只有所需长度的一半,并且正在转换超出缓冲区大小的一些垃圾数据。

您需要创建 sampleOut 的长度为 2*n 并设置所有其他值(实部),或者更好的是,您可以绕过 >vDSP_ctoz() 并直接将您的输入数据复制到 A.realp 并将 A.imagp 设置为零。 vDSP_ctoz() 仅在连接到生成交错复杂数据的源时才需要。

编辑

好吧,我认为我的第一个建议是错误的,因为 vDSP 文档说实到复就地 fft 的实际输入应该格式化为拆分复数格式,这样 imagp 包含偶数样本,realp 包含奇数样本。我没有实际使用过 vDSP 库,但我熟悉很多其他 FFT 库,但我错过了那个细节。

在调用 vDSP_zvmags(&A, 1, A.realp, 1, nOver2); 之后,您应该能够使用 A.realp 找到峰值点,A.realp 应该包含 FFT 输出的幅度平方,它是标量。如果您要进行缩放,则应在 mag2 操作之前完成,但如果您只是寻找峰值,则可能不需要。

要获得 FFT 输出表示的实际频率,请使用以下公式:

F = (i * Fs) / N,   i=0,1,...,N/2

在哪里

i 是FFT输出缓冲区的索引Fs为音频采样率N为FFT长度

因此您的计算可能如下所示:

float frequency = (peakIndex * 44100) / n;

请记住,vDSP 仅为实际输入返回输入频谱的前半部分,因为后半部分是冗余的。因此 FFT 输出表示从 0Fs/2 的频率。

另一个注意事项是,我不知道您的寻峰算法是否能很好地工作,因为 FFT 输出不会很平滑并且经常会有很多振荡。您只是在两个相邻样本较低的地方获取第一个样本。如果您只想找到一个峰值,最好只找到整个输出的最大幅度。如果你想找到多个峰值,你将不得不做一些更复杂的事情。

关于ios - 从 AvassetReader 和 vDSP_FFT 获取 iPhone mp3 频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5858494/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com