计算音频功率峰值 iOS
Posted
技术标签:
【中文标题】计算音频功率峰值 iOS【英文标题】:Counting audio power peaks iOS 【发布时间】:2011-06-02 09:48:56 【问题描述】:根据渐进的见解编辑了问题:-)
我正在创建一个正在侦听音频输入的应用。 我希望它计算峰值。 (峰值的最大频率约为 10 Hz。)
经过大量搜索,我最终使用了 AudioQueue 服务,因为它可以为我提供原始输入数据。 我正在使用 SpeakHere 示例的精简版本(不播放),但不是简单地将缓冲区写入文件系统,而是查看单个示例数据。
认为我现在走在正确的轨道上,但我不明白如何使用缓冲区。 我正在尝试隔离一个样本的数据。因此,以下函数中的 for 循环是否有意义,并且 我应该在里面放什么才能得到一个样品?
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 复杂得多的例子。
【问题讨论】:
结果如下:bit.ly/pjamzU(爆米花停止!) 【参考方案1】:您可能希望对峰值功率水平应用某种平滑,也许是 IIR 滤波器,例如:
x_out = 0.9 * x_old + 0.1 * x_in;
:
x_old = x_out;
我没有使用过这个功能,所以我不知道它是否能满足你的所有需求。如果没有,您可以降低一个级别并使用 RemoteIO 音频单元,并使用“输入回调”捕捉声音(与扬声器渴望数据时发生的渲染回调相反)
请注意,在输入回调中,您必须创建自己的缓冲区,不要仅仅因为您将缓冲区指针作为最后一个参数而认为它指向有效的东西。它没有。
无论如何,您可以使用一些 vDSP 函数来获得整个缓冲区(1024 个浮点数或任何您的缓冲区大小/流格式)的向量的平方
然后你可以自己平滑它
【讨论】:
看来我确实会使用 RemoteIO 音频单元。我正在考虑“逆向工程”AurioTouch 示例代码并使用来自示波器的数据。我认为通过这些数据,我可以找到我正在寻找的峰。 你是什么意思缓冲区指针没有指向有效的东西?这听起来令人震惊。我假设使用 AurioTouch 作为我的起点将指出这些缓冲区是如何工作的……我计划获取一个样本块并确定该块的平均(绝对)功率。有了正确的块大小,我想我应该能够找到峰值。感谢您的帮助 ***.com/questions/6039291/… 注意AurioTouch实际上实现了passThru,所以它使用了RENDER-callback。如果您只想听,请改用 INPUT-callback。 IIRC AurioTouch 中有一些错误会阻止 passthru 工作,但基本技术是声音——在渲染回调中,它从麦克风缓冲区中获取数据(如果有任何等待,第一次传递将不会有任何等待,所以注意)。对于 RENDER 回调,缓冲区是预先存在的。回调只是要求它们被填充。但对于 INPUT 回调,您需要自己制作。【参考方案2】:这将遍历缓冲区中的所有样本。
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 指向记录器的实例。回调是静态函数,不能直接访问成员变量或成员函数。
为了计算峰值,我记录了一个长期平均值和一个短期平均值。如果短期平均值比长期平均值大某个因素,则存在峰值。当短期均线再次下降时,峰值已经过去。
【讨论】:
以上是关于计算音频功率峰值 iOS的主要内容,如果未能解决你的问题,请参考以下文章