低通音频滤波器,在iOS上计算RMS

时间:2013-03-18 14:52:16

标签: ios core-audio measurement lowpass-filter

我正在开发适用于iPad的应用程序,我想分析我正在播放的视频中的音频。使用MTAudioProcessingTap一切顺利。 目前我有一些测试代码来测试/测量左右声道的音量。这一切都很顺利:

void process(MTAudioProcessingTapRef tap, CMItemCount numberFrames,
         MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
         CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
    OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut,
                                                  flagsOut, NULL, numberFramesOut);

    if (err)
        NSLog(@"Error from GetSourceAudio: %ld", err);

    float leftVolume, rightVolume;

    for (CMItemCount i = 0; i < bufferListInOut->mNumberBuffers; i++)
    {
        AudioBuffer *pBuffer = &bufferListInOut->mBuffers[i];
        int cSamples = numberFrames * pBuffer->mNumberChannels;

        float *pData = (float *)pBuffer->mData;

        float rms = 0.0f;

        for (int j = 0; j < cSamples; j++)
        {
            rms += pData[j] * pData[j];

        }

        if (cSamples > 0)
        {
            rms = sqrtf(rms / cSamples);
        }

        if (0 == i)
        {
            leftVolume = rms;
        }

        if (1 == i || (0 == i && 1 == bufferListInOut->mNumberBuffers))
        {
            rightVolume = rms;
        }
    }

    NSLog(@"Left / Right Volume: %f / %f", leftVolume, rightVolume);
}

但是就本应用而言,我希望它只是测量0-80Hz范围内的RMS(“强度”)(例如)。因此,我需要一个低通滤波器。

我已经谷歌搜索很长一段时间了,但我的问题是我找不到任何明显的帖子,教程或解决方案。几乎所有听起来都像我一样的问题都有一段随机的代码片段,其中有蹩脚或缺乏评论,所以我无法弄清楚所有神奇的数字在那里做什么,以及它们的含义......

有人能把我推向正确的方向吗?请注意,在我的情况下,我执行想要理解代码,而不仅仅是使用工作样本。

由于

1 个答案:

答案 0 :(得分:17)

如果你能用一个有效的例子,你会很幸运。 : - )

信号处理是一个复杂而深刻的领域。当你理论上这样做时很复杂,而且当你想要实际做它时它也很复杂。

您想要一个低通滤波器。有许多选择具有不同的优点和缺点。

当您想要了解正在发生的事情时,您需要处理的最基本概念:

频域和时域:频域是指您所谈论的频率间隔,例如0..80Hz。时域是正常时间,或者例如您在采样缓冲区中的单个样本值。上面的代码计算了时域中的RMS。

基本规则:频域和时域完全等效。

您可以在任一域中执行许多操作,但结果相同。您始终可以在频域和时域之间切换。由于某些操作在某个域中是微不足道的,因此首先切换到所需域,执行简单操作,然后切换回原始域(如果需要)通常很有用。

使用 FT(傅立叶变换)在频域和时域之间切换。以编程方式通常使用缓冲区的特殊情况,其中包含两个样本的幂和 FFT 算法(快速傅里叶变换)。

另一个有趣的属性是卷积定理:FT在一个域中的函数乘法和另一个域上的函数卷积之间进行转换。

现在这与你的低通滤波器有什么关系呢?

您建议的低通滤波器0-80Hz,是频域中的矩形函数。您希望将其乘以频域中的输入。这意味着让所有频率部分低于80Hz并将所有其他部分设置为零。

现在你可以在频域中做到这一切,这很容易,但出于效率原因,你想在时域中做到这一点,以避免来回的FFT。 (在你的情况下,你只想拥有你可以在频域中计算的能量,就像现在一样(平方和)。)

要在时域中进行低通滤波器,而不是FT-multiply-FT,您还可以使用FT(矩形函数)进行卷积。 FT(矩形函数)是理想的低通滤波器:sinc()函数。

sinc(x) := sin(pi*x) / pi*x

此sinc(x)是矩形函数的脉冲响应。这种具体的脉冲响应是无限的,这是不切实际的。这意味着您需要使用无限数量的值来计算输入的卷积。

你想要的是一个带有有限脉冲响应的滤波器 FIR 。这将导致过滤器出错,具体地说,您将看不到所有频率&lt; 80Hz,相同的重量,你也会看到你的能量超过80Hz的一些频率。

这种妥协是不可避免的。

顺便说一句:当您使用FFT方法时,您可以在没有任何错误的情况下应用完美的矩形函数,在进行FFT之前窗口化输入信号时,也会间接地遇到此错误。 (窗口意味着切断输入的部分(窗口)以进行FFT。)这将对输出产生相同的负面影响,并且需要与过滤功能和结果相同的妥协。

您可能需要某种FIR滤波器作为低通滤波器。而你在其他代码中看到的奇怪数字很可能就是这种FIR滤波器的系数。

问题在于没有“最佳”的优势。妥协,因为折衷很大程度上取决于你如何定义错误&#39;在过滤器中。有些人必须以任何方式避免超过82 Hz的频率部分(在您的示例中),因此他们需要非常陡峭的滤波器边缘。这通常会在80Hz边界附近产生大的伪影,然后需要接受。其他人很好,一些能量来自频率高达120Hz并且保持在120Hz以下10%以下,以减少80Hz边界附近的伪影(更软的低通滤波器)。

这里涵盖了整个主题: https://ccrma.stanford.edu/~jos/sasp/FIR_Digital_Filter_Design.html

或者如果你想从一开始就开始: https://ccrma.stanford.edu/~jos/sasp/sasp.html

另请参阅FIR过滤器和sinc的维基百科页面。

我承认,上述内容不足以设计和实施您自己的过滤器。但它应该给你足够的背景和指针来开始。

并且不会被有时奇怪的数学所拖延。

想法:在您应用滤波器并查看频谱后,可以直观地了解滤波器工作情况的一种方法是进行FFT。通过仅查看RMS值来判断过滤器是否正常工作将非常困难。您的iPad具有足够的处理能力来实现这一目标。

(我刚看到信号处理也有http://dsp.stackexchange.com。)