【问题标题】:Low Pass Audio Filter, calculating RMS on iOS低通音频滤波器,在 iOS 上计算 RMS
【发布时间】:2013-03-18 14:52:15
【问题描述】:

我正在开发一款适用于 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(“强度”)(例如)。因此,我需要一个低通滤波器。

我已经在谷歌上搜索了很长时间,但我的问题是我找不到任何明显的帖子、教程或解决方案。几乎每个听起来有点像我的问题都有一段随机的代码,其中包含糟糕或缺少 cmets,所以我无法弄清楚所有幻数在那里做了什么,以及它们的含义..

有人能把我推向正确的方向吗?请注意,在我的情况下,我确实想了解代码,而不仅仅是使用工作示例。

谢谢

【问题讨论】:

    标签: ios core-audio measurement lowpass-filter


    【解决方案1】:

    如果你能用一个可行的例子跑掉,你会很幸运。 :-)

    信号处理是一个复杂而深入的领域。理论上做起来很复杂,实际做起来也很复杂。

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

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

    频域和时域:频域是指频率间隔,例如 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。这将导致您的过滤器出现错误,具体而言,您不会看到所有频率

    这种妥协是不可避免的。

    顺便说一句:当您使用 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 的 Wikipedia 页面。

    我承认,以上内容不足以设计和实现您自己的过滤器。但它应该为您提供足够的背景知识和入门指南。

    不要被有时奇怪的数学吓到。

    想法:可视化过滤器工作情况的一种方法是在应用过滤器并查看频谱后进行 FFT。仅通过查看 RMS 值很难判断过滤器是否正常工作。您的 iPad 有足够的处理能力来执行此操作。

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

    【讨论】:

    • 哇!谢谢!这对我很有帮助!我想“奖励”你我的“赏金”,但它说我只能在 20 小时内做到这一点,所以你很快就会看到它的到来 :) .. 感谢所有帮助,这样我应该可以创造一些东西:)
    • 令人印象深刻,当然是一个值得赏金的答案!
    • 如果可以的话,我会在这个答案中再添加 50 个,这太棒了!
    • 赏金 :) 再次感谢
    猜你喜欢
    • 2014-03-14
    • 1970-01-01
    • 2014-11-18
    • 2015-01-03
    • 2019-06-04
    • 2017-09-10
    • 2021-03-08
    • 1970-01-01
    • 2011-06-02
    相关资源
    最近更新 更多