gpt4 book ai didi

ios - iOS Accelerate框架中vDSP_ctoz的数据应该是什么格式

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:01:17 37 4
gpt4 key购买 nike

我正在尝试显示适用于 iOS 的频谱分析仪,但两周后卡住了。我几乎阅读了此处有关 FFT 和 Accelerate Frameworks 的所有帖子,并从 Apple 下载了 aurioTouch2 示例。

我想我了解 FFT 的机制(20 年前在 Uni 做过)并且是一个相当有经验的 iOS 程序员,但我遇到了瓶颈。

我正在使用 AudioUnit 播放 mp3、m4a 和 wav 文件,并且效果很好。我已将渲染回调附加到 AUGraph,我可以将波形绘制到音乐中。波形与音乐相得益彰。

Waveform image

当我从 0 .. 1 范围内的浮点形式的渲染回调中获取数据并尝试通过 FFT 代码(我自己的或 aurioTouch2 的 FFTBufferManager.mm)传递它时,我得到了一些并非完全错误的东西,但也不正确。或例如这是一个 440Hz 正弦波:

40Khz sine wave

峰值为 -6.1306,然后是 -24。 -31., -35.那些接近尾声的值大约是 -63。

“黑贝蒂”的 gif 动画:

Animated gif for "Black Betty

我从渲染回调中收到的格式:

AudioStreamBasicDescription outputFileFormat;
outputFileFormat.mSampleRate = 44100;
outputFileFormat.mFormatID = kAudioFormatLinearPCM;
outputFileFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
outputFileFormat.mBitsPerChannel = 32;
outputFileFormat.mChannelsPerFrame = 2;
outputFileFormat.mFramesPerPacket = 1;
outputFileFormat.mBytesPerFrame = outputFileFormat.mBitsPerChannel / 8;
outputFileFormat.mBytesPerPacket = outputFileFormat.mBytesPerFrame;

在查看 aurioTouch2 示例时,他们似乎正在以带符号的 int 格式接收数据,然后运行 ​​AudioConverter 将其转换为 Float。它们的格式很难破译,但使用了宏:

    drawFormat.SetAUCanonical(2, false);
drawFormat.mSampleRate = 44100;

XThrowIfError(AudioConverterNew(&thruFormat, &drawFormat, &audioConverter), "couldn't setup AudioConverter");

在渲染回调中,他们将数据从 AudioBufferList 复制到 mAudioBuffer (Float32*) 并将其传递给调用 vDSP_ctoz 的 CalculateFFT 方法

    //Generate a split complex vector from the real data
vDSP_ctoz((COMPLEX *)mAudioBuffer, 2, &mDspSplitComplex, 1, mFFTLength);

我想这就是我的问题所在。 vDSP_ctoz 需要什么格式?它被转换为 (COMPLEX*) 但我无法在将 mAudioBuffer 数据放入 (COMPLEX*) 格式的 aurioTouch2 代码中找到任何地方。那么必须以这种格式来自 Render Callback 吗?

typedef struct DSPComplex {
float real;
float imag;
} DSPComplex;
typedef DSPComplex COMPLEX;

如果我此时没有正确的格式(或理解格式),那么调试其余部分就没有意义了。

如有任何帮助,我们将不胜感激。

我正在使用的来自 AurioTouch2 的代码:

Boolean FFTBufferManager::ComputeFFTFloat(Float32 *outFFTData)
{
if (HasNewAudioData())
{
// Added after Hotpaw2 comment.
UInt32 windowSize = mFFTLength;
Float32 *window = (float *) malloc(windowSize * sizeof(float));

memset(window, 0, windowSize * sizeof(float));

vDSP_hann_window(window, windowSize, 0);

vDSP_vmul( mAudioBuffer, 1, window, 1, mAudioBuffer, 1, mFFTLength);

// Added after Hotpaw2 comment.
DSPComplex *audioBufferComplex = new DSPComplex[mFFTLength];

for (int i=0; i < mFFTLength; i++)
{
audioBufferComplex[i].real = mAudioBuffer[i];
audioBufferComplex[i].imag = 0.0f;
}

//Generate a split complex vector from the real data
vDSP_ctoz((COMPLEX *)audioBufferComplex, 2, &mDspSplitComplex, 1, mFFTLength);

//Take the fft and scale appropriately
vDSP_fft_zrip(mSpectrumAnalysis, &mDspSplitComplex, 1, mLog2N, kFFTDirection_Forward);
vDSP_vsmul(mDspSplitComplex.realp, 1, &mFFTNormFactor, mDspSplitComplex.realp, 1, mFFTLength);
vDSP_vsmul(mDspSplitComplex.imagp, 1, &mFFTNormFactor, mDspSplitComplex.imagp, 1, mFFTLength);

//Zero out the nyquist value
mDspSplitComplex.imagp[0] = 0.0;

//Convert the fft data to dB
vDSP_zvmags(&mDspSplitComplex, 1, outFFTData, 1, mFFTLength);

//In order to avoid taking log10 of zero, an adjusting factor is added in to make the minimum value equal -128dB
vDSP_vsadd( outFFTData, 1, &mAdjust0DB, outFFTData, 1, mFFTLength);
Float32 one = 1;
vDSP_vdbcon(outFFTData, 1, &one, outFFTData, 1, mFFTLength, 0);

free( audioBufferComplex);
free( window);

OSAtomicDecrement32Barrier(&mHasAudioData);
OSAtomicIncrement32Barrier(&mNeedsAudioData);
mAudioBufferCurrentIndex = 0;
return true;
}
else if (mNeedsAudioData == 0)
OSAtomicIncrement32Barrier(&mNeedsAudioData);

return false;
}

阅读下面的答案后,我尝试将其添加到方法的顶部:

    DSPComplex *audioBufferComplex = new DSPComplex[mFFTLength];

for (int i=0; i < mFFTLength; i++)
{
audioBufferComplex[i].real = mAudioBuffer[i];
audioBufferComplex[i].imag = 0.0f;
}

//Generate a split complex vector from the real data
vDSP_ctoz((COMPLEX *)audioBufferComplex, 2, &mDspSplitComplex, 1, mFFTLength);

我得到的结果是这样的:

After Adding above code

我现在正在渲染最后的 5 个结果,它们是后面褪色的。

添加汉恩窗后:

enter image description here

应用 hann 窗口后现在看起来好多了(感谢 hotpaw2)。不担心镜像。

我现在的主要问题是使用一首真正的歌曲,它看起来不像其他频谱分析仪。无论我播放什么音乐,一切都总是在左边被推高。应用窗口后,它似乎更合拍了。

Black Betty

最佳答案

AU 渲染回调仅返回所需复杂输入的实部。要使用复数 FFT,您需要自己用零填充相同数量的虚部,并根据需要复制实部的元素。

关于ios - iOS Accelerate框架中vDSP_ctoz的数据应该是什么格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22585341/

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