由于进步见解而编辑了这个问题: - )
我正在创建一个正在收听音频输入的应用。 我希望它能算出峰值。 (峰值的最大频率约为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更复杂的例子。
答案 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平均值是一个比长期平均值大的特定因子,那么就有一个峰值。当短期平均值再次下降时,峰值已经过去。