计算音频功率达到峰值iOS

时间:2011-06-02 09:48:57

标签: iphone audio core-audio audioqueueservices

由于进步见解而编辑了这个问题: - )

我正在创建一个正在收听音频输入的应用。 我希望它能算出峰值。 (峰值的最大频率约为10 Hz。)

经过大量搜索后,我最终使用了AudioQueue服务,因为它可以为我提供原始输入数据。 我正在使用SpeakHere示例的精简版(无回放),但我不想简单地将缓冲区写入文件系统,而是想查看单个样本数据。

认为我现在正走在正确的轨道上,但我不明白如何使用缓冲区。 我试图隔离一个样本的数据。因此,对于以下函数中的循环,这是否有意义,并且 我应该把它放在那里以获得一个样品?

void AQRecorder::MyInputBufferHandler( void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription* inPacketDesc)
{
    // AudioQueue callback function, called when an input buffers has been filled.

    AQRecorder *aqr = (AQRecorder *)inUserData;
    try {
        if (inNumPackets > 0) {
            /*          // write packets to file
            XThrowIfError(AudioFileWritePackets(aqr->mRecordFile,FALSE,inBuffer->mAudioDataByteSize,inPacketDesc,aqr->mRecordPacket,&inNumPackets,inBuffer->mAudioData),
                      "AudioFileWritePackets failed");*/

            SInt16 sample;
        for (UInt32 sampleIndex=0; sampleIndex < inNumPackets; ++sampleIndex) {


            // What do I put here to look at one sample at index sampleIndex ??


        }
        aqr->mRecordPacket += inNumPackets;
        }

    // if we're not stopping, re-enqueue the buffe so that it gets filled again
    if (aqr->IsRunning())
        XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL),
                      "AudioQueueEnqueueBuffer failed");
    } catch (CAXException e) {
    char buf[256];
    fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}

(也许我不应该删除这么多原始问题......政策是什么?)

最初我在考虑使用AurioTouch示例,但正如评论中指出的那样,使用吞吐量而我只需要输入。这也是一个比SpeakHere更复杂的例子。

2 个答案:

答案 0 :(得分:0)

您可能希望对峰值功率水平应用某种平滑,也许是IIR滤波器,例如:

x_out = 0.9 * x_old + 0.1 * x_in;
:
x_old = x_out;

我没有使用过这个功能,所以我不知道它是否会做你想做的一切。如果没有,你可以删除一个级别并使用RemoteIO音频单元,并在使用'输入回调'时捕获声音(与扬声器渴望数据时发生的渲染回调相反)

请注意,在输入回调中你必须创建自己的缓冲区,不要只是因为你得到一个缓冲区指针作为最后一个参数,这意味着它指向有效的东西。它没有。

无论如何,您可以使用一些vDSP函数来获取整个缓冲区的向量的平方(1024浮点数或任何缓冲区大小/流格式)

然后你可以自己解决这个问题

答案 1 :(得分:0)

循环遍历缓冲区中的所有样本。

    SInt16 sample;
    for (UInt32 sampleIndex=0; sampleIndex < inNumPackets; ++sampleIndex) {
        sample = buffer[sampleIndex]; // Get the power of one sample from the buffer
        aqr->AnalyseSample(sample);
    }

是一个棘手的部分:aqr指向录像机的实例。回调是一个静态函数,不能直接访问成员变量或成员函数。

为了计算峰值,我会记录长期平均值和短期平均值。如果shortTerm平均值是一个比长期平均值大的特定因子,那么就有一个峰值。当短期平均值再次下降时,峰值已经过去。