我对信号处理几乎一无所知,目前我试图在Swift中实现一个函数,当sound pressure level增加时(例如当人类尖叫时)触发事件。
我正在使用这样的回调攻击AVAudioEngine的输入节点:
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat){
(buffer : AVAudioPCMBuffer?, when : AVAudioTime) in
let arraySize = Int(buffer.frameLength)
let samples = Array(UnsafeBufferPointer(start: buffer.floatChannelData![0], count:arraySize))
//do something with samples
let volume = 20 * log10(floatArray.reduce(0){ $0 + $1} / Float(arraySize))
if(!volume.isNaN){
print("this is the current volume: \(volume)")
}
}
将它变成浮点阵后,我试着通过计算平均值来粗略估计声压级。
但即使iPad只是坐在一个安静的房间里,这给了我很多波动的价值:
this is the current volume: -123.971
this is the current volume: -119.698
this is the current volume: -147.053
this is the current volume: -119.749
this is the current volume: -118.815
this is the current volume: -123.26
this is the current volume: -118.953
this is the current volume: -117.273
this is the current volume: -116.869
this is the current volume: -110.633
this is the current volume: -130.988
this is the current volume: -119.475
this is the current volume: -116.422
this is the current volume: -158.268
this is the current volume: -118.933
如果我在麦克风附近拍手,这个值确实会有显着增加。
所以我可以做一些事情,比如在准备阶段首先计算这些卷的平均值,并比较事件触发阶段的差异是否显着增加:
if(!volume.isNaN){
if(isInThePreparingPhase){
print("this is the current volume: \(volume)")
volumeSum += volume
volumeCount += 1
}else if(isInTheEventTriggeringPhase){
if(volume > meanVolume){
//triggers an event
}
}
}
其中averageVolume是在从准备阶段到触发事件阶段的过渡期间计算的:meanVolume = volumeSum / Float(volumeCount)
...
然而,如果我在麦克风旁播放嘈杂的音乐,似乎没有显着增加。在极少数情况下,volume
大于meanVolume
,即使环境没有明显的音量增加(人耳听到)。
那么从AVAudioPCMBuffer中提取声压级的正确方法是什么?
维基百科给出了这样的公式
p为均方根声压,p0为参考声压。
但我不知道AVAudioPCMBuffer.floatChannelData
中的浮点值代表什么。 The apple page只说
缓冲区的音频样本为浮点值。
我应该如何与他们合作?
答案 0 :(得分:3)
我认为第一步是获得声音的envelope。您可以使用简单平均来计算包络,但是您需要添加一个校正步骤(通常意味着使用abs()或square()来使所有样本都为正)
更常见的是使用简单的iir-filter而不是求平均值,具有不同的攻击和衰减常数,这里是lab。请注意,这些常数取决于采样频率,您可以使用此公式计算常数:
1 - exp(-timePerSample*2/smoothingTime)
当你有信封时,可以使用额外的滤镜对其进行平滑处理,然后比较两个信封以找到比基本电平更响的声音,这里更多complete lab。
请注意检测音频"事件"可能非常棘手,而且难以预测,确保你有很多诽谤援助!
答案 1 :(得分:3)
感谢@teadrinker的回复,我终于找到了解决这个问题的方法。我分享我的Swift代码,输出AVAudioPCMBuffer
输入的音量:
private func getVolume(from buffer: AVAudioPCMBuffer, bufferSize: Int) -> Float {
guard let channelData = buffer.floatChannelData?[0] else {
return 0
}
let channelDataArray = Array(UnsafeBufferPointer(start:channelData, count: bufferSize))
var outEnvelope = [Float]()
var envelopeState:Float = 0
let envConstantAtk:Float = 0.16
let envConstantDec:Float = 0.003
for sample in channelDataArray {
let rectified = abs(sample)
if envelopeState < rectified {
envelopeState += envConstantAtk * (rectified - envelopeState)
} else {
envelopeState += envConstantDec * (rectified - envelopeState)
}
outEnvelope.append(envelopeState)
}
// 0.007 is the low pass filter to prevent
// getting the noise entering from the microphone
if let maxVolume = outEnvelope.max(),
maxVolume > Float(0.015) {
return maxVolume
} else {
return 0.0
}
}