如何解释 AudioBuffer 并获得力量?
Posted
技术标签:
【中文标题】如何解释 AudioBuffer 并获得力量?【英文标题】:How do I interpret an AudioBuffer and get the power? 【发布时间】:2014-08-11 22:14:40 【问题描述】:我正在尝试为我的应用制作音量计,它会在录制视频时显示。我发现很多对 ios 仪表的支持,但主要是 AVAudioPlayer
,这对我来说是没有选择的。我正在使用AVCaptureSession
进行记录,然后会得到如下所示的委托方法:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
CFRetain(sampleBuffer);
CFRetain(formatDescription);
if(connection == audioConnection)
CMBlockBufferRef blockBuffer;
AudioBufferList audioBufferList;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer,
NULL, &audioBufferList, sizeof(AudioBufferList), NULL, NULL,
kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
&blockBuffer);
SInt16 *data = audioBufferList.mBuffers[0].mData;
//Releases etc..
(只显示相关代码)
据我所知,我收到一个“样本缓冲区”,其中包含音频或视频。一旦我确认连接确实是音频,然后我从缓冲区中“提取”audioBufferList,我就坐在左边,列出一个(或多个?)audioBuffers。据我了解,实际数据表示为SInt16
,或“16 位有符号整数”,据我所知,其范围从-32,768
到32,767
。但是,如果我只是打印出这个收到的值,我会得到很多弹跳数字。当处于“沉默”状态时,我得到的值在-200
和200
之间快速反弹,而当有噪音时,我得到从-4,000
到13,000
的值,完全不正常。
正如我从阅读中了解到的那样,0
的值将代表沉默。但是,我不明白负值和正值之间的区别,也不知道它们是否能够一直向上/向下到达+-32,768
。
我相信我需要一定比例的“响度”,但一直找不到任何东西。
我已经阅读了一些关于这个问题的教程和参考资料,但对我来说没有任何意义。我遵循了一个指南(附加到上面的代码,在if
内):
float accumulator = 0;
for(int i = 0; i < audioBufferList.mBuffers[0].mDataByteSize; i++)
accumulator += data[i] * data[i];
float power = accumulator / audioBufferList.mBuffers[0].mDataByteSize;
float decibels = log10f(power);
NSLog(@"%f", decibels);
显然,这段代码应该从-1
对齐到+1
,但这并没有发生。我现在在静音时得到 6.194681
左右的值,在一些噪音时得到 7.773492
。这感觉像是正确的“范围”,但在“错误的地方”。我不能简单地从数字中减去 7 并假设我介于 -1
和 +1
之间。这应该如何工作背后应该有一些逻辑和科学,但我对数字音频的工作原理知之甚少。
有人知道这背后的逻辑吗?当-32,768
和32,767
是响亮的噪音时,0 是否总是静音?然后我可以简单地将所有负值乘以-1
以始终得到正值,然后找出它们的百分比(0 到 32767 之间)吗?不知何故,我不相信这会起作用,因为我猜负值是有原因的。我不完全确定要尝试什么。
【问题讨论】:
我建议阅读 en.wikipedia.org/wiki/Pulse-code_modulation 了解背景 @sbooth 谢谢,我从中学到了,但遗憾的是没有什么可以解决我的问题。我并不完全理解我所拥有的数据如何代表“响度”。动力'。当我现在对着麦克风说话时,我的日志中会打印出一堆数字。当我提高声音时,它们会有所不同。它们是否只代表我说话的音量,还是它们也代表其余部分,如我所说的/我的频率等?那么我怎样才能找到音量的最小值/最大值.. 数字代表整个信号——你的声音的音量、频率等。计算响度有不同的方法——最简单的可能是选择一个采样窗口(例如 1/10 秒) ) 然后计算 RMS 功率。这不是一个很好的响度估计值,但它会是一个开始。 您在这一行中缺少平方根 - float power = accumulator / audioBufferList.mBuffers[0].mDataByteSize; 你找到解决办法了吗? 【参考方案1】:您问题中的代码在几个方面有误。此代码试图从下面的文章中复制它,但您没有正确处理它从文章中的基于浮点数的代码转换为 16 位整数数学。您还循环了错误数量的值(最大 i),最终会拉入垃圾数据。所以这是各种错误。
https://www.mikeash.com/pyblog/friday-qa-2012-10-12-obtaining-and-interpreting-audio-data.html
文章中的代码是正确的。这就是它的内容,扩展了一点。这只是查看 32 位浮点缓冲区列表中的第一个缓冲区。
float accumulator = 0;
AudioBuffer buffer = bufferList->mBuffers[0];
float * data = (float *)buffer.mData;
UInt32 numSamples = buffer.mDataByteSize / sizeof(float);
for (UInt32 i = 0; i < numSamples; i++)
accumulator += data[i] * data[i];
float power = accumulator / (float)numSamples;
float decibels = 10 * log10f(power);
正如文章所说,这里的结果是分贝使用 0dB 参考。例如,0.0 是 最大值 值。例如,这与 AVAudioPlayer 的 averagePowerForChannel 返回的内容相同。
要在 16 位整数上下文中使用它,您需要 a) 适当地循环遍历每个 16 位样本,b) 将 data[i] 值从 16 位整数转换为浮点值在平方和添加到累加器之前在 [-1.0, 1.0] 范围内。
【讨论】:
谢谢。这个问题是六年前发布的,所以我无法尝试,但我很欣赏详细的回复,并假设你是正确的。以上是关于如何解释 AudioBuffer 并获得力量?的主要内容,如果未能解决你的问题,请参考以下文章