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

5

我正在开发一个针对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个回答

18

如果你能顺手举个实际的例子,那就太幸运了。:-)

信号处理是一个复杂而深奥的领域。当你从理论上进行时,它很复杂,当你想要实践时也同样复杂。

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

当你想要理解发生了什么时,最基本的概念如下:

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

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

你可以在任一域中进行许多操作得到相同的结果。你总是可以在频域和时域之间切换。由于某些操作在特定域中是微不足道的,所以通常首先切换到所需的域,执行微不足道的操作,然后(如果必要)切换回原始域。

在频率域和时间域之间切换使用FT(傅里叶变换)。在编程中,通常使用包含2的幂次方样本数和FFT算法(快速傅里叶变换)的缓冲区的特殊情况。
另一个有趣的属性是卷积定理:FT在两个域中的函数乘积和函数卷积之间进行转换。
现在这一切与您的低通滤波器有什么关系呢?
您建议的0-80Hz低通滤波器在频率域中是一个矩形函数。您想在频率域中将其乘以输入信号。这意味着让所有低于80Hz的频率通过,并将所有其他频率设置为零。
现在您可以在频率域中完成所有操作,但出于效率原因,您希望在时间域中完成操作,以避免来回FFT。(在您的情况下,您只想获得能量,您也可以像现在计算方式一样在频率域中计算(平方和))。
要在时间域中执行低通滤波器操作,而不是FT-乘-FT,您还可以使用FT(矩形函数)进行卷积。 FT(矩形函数)是理想的低通滤波器:sinc()函数。
sinc(x) := sin(pi*x) / pi*x

这个 sinc(x) 是你的矩形函数的脉冲响应。这个具体的脉冲响应是无限的,这是不切实际的。这意味着你需要计算输入与无限数量的值的卷积。
你想要的是有限脉冲响应的滤波器:FIR。这将导致滤波器出现错误,具体来说,您将无法看到所有低于80Hz的频率具有相同的权重,并且您还将在能量中看到一些超过80Hz的频率。
这种妥协是不可避免的。
顺便说一句:当您使用FFT方法时,在执行FFT之前对输入信号进行窗口处理时,您也会间接遭受此错误。(窗口处理是指从输入中剪切出一些片段(窗口)以进行FFT。)这将对输出产生相同的负面影响,并需要与滤波函数和结果相同的妥协。
您可能想要一种FIR滤波器作为低通滤波器。其他人代码中奇怪的数字很可能是这样一个FIR滤波器的系数。
问题在于没有“最佳”折衷方案,因为折衷方案非常取决于您如何定义过滤器中的“错误”。有些人必须尽一切可能避免超过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用于信号处理。)

哇!谢谢!这真的帮了我很大的忙!我想“奖励”您我的“赏金”,但它说我只能在20小时后才能这样做,所以您很快就会看到这个了 :) .. 感谢您提供的所有帮助,这样我应该能够创造出一些东西 :) - Niek van der Steen
令人印象深刻,绝对是值得奖励的答案! - Daniel Frey
如果可以的话,我会再加50分,这太棒了! - Nick Weaver
赏金已给 :) 再次感谢 - Niek van der Steen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接