使用 Avaudioengine iOS 的低通滤波器 + 采样率转换
Posted
技术标签:
【中文标题】使用 Avaudioengine iOS 的低通滤波器 + 采样率转换【英文标题】:Low Pass filter + sample rate conversion using Avaudioengine iOS 【发布时间】:2022-01-19 17:45:42 【问题描述】:我们正在开展一个项目,该项目允许我们用 5k Hz 采样率和一些低通滤波器和高通滤波器记录来自麦克风的一些声音。
我们正在使用什么
我们为此目的使用 AvaudioEngine。
我们正在使用 AVAudioConverter 来降低采样率。
我们将 AVAudioUnitEQ 用于低通和高通滤波器。
代码
let bus = 0
let inputNode = engine.inputNode
let equalizer = AVAudioUnitEQ(numberOfBands: 2)
equalizer.bands[0].filterType = .lowPass
equalizer.bands[0].frequency = 3000
equalizer.bands[0].bypass = false
equalizer.bands[1].filterType = .highPass
equalizer.bands[1].frequency = 1000
equalizer.bands[1].bypass = false
engine.attach(equalizer) //Attach equalizer
// Connect nodes
engine.connect(inputNode, to: equalizer, format: inputNode.inputFormat(forBus: 0))
engine.connect(equalizer, to: engine.mainMixerNode, format: inputNode.inputFormat(forBus: 0))
engine.connect(engine.mainMixerNode, to: engine.outputNode, format: inputNode.inputFormat(forBus: 0))
let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
sampleRate: 5000,
channels: 1,
interleaved: false)!
// Converter to downgrade sample rate
guard let converter: AVAudioConverter = AVAudioConverter(from: inputNode.inputFormat(forBus: 0), to: outputFormat) else
print("Can't convert in to this format")
return
engine.mainMixerNode.installTap(onBus: bus, bufferSize: 2688, format: engine.mainMixerNode.outputFormat(forBus: 0)) (buffer, time) in
var newBufferAvailable = true
let inputCallback: AVAudioConverterInputBlock = inNumPackets, outStatus in
if newBufferAvailable
outStatus.pointee = .haveData
newBufferAvailable = false
return buffer
else
outStatus.pointee = .noDataNow
return nil
let convertedBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
var error: NSError?
let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
assert(status != .error)
if status == .haveData
// Process with converted buffer
engine.prepare()
do
try engine.start()
catch
print("Can't start the engine: \(error)")
问题
低通和高通滤波器不起作用。
替代方法
为了检查代码是否正常工作,我们添加了混响效果而不是低通滤波器。 混响效果(使用 AVAudioUnitReverb)使用相同的代码。
谁能帮我在应用低通滤波器时哪里做错了?
【问题讨论】:
@sbooth 我试过了,但结果是一样的。没有影响。 【参考方案1】:我认为这段代码的主要问题是 AVAudioConverter
是在调用 engine.prepare()
之前创建的,这可以并且将会改变 mainMixerNode
输出格式。除此之外,mainMixerNode
与outputNode
之间存在冗余连接,以及可能不正确的格式——mainMixerNode
被记录为“按需”自动创建并连接到输出节点。水龙头也不需要格式。
let bus = 0
let inputNode = engine.inputNode
let equalizer = AVAudioUnitEQ(numberOfBands: 2)
equalizer.bands[0].filterType = .lowPass
equalizer.bands[0].frequency = 3000
equalizer.bands[0].bypass = false
equalizer.bands[1].filterType = .highPass
equalizer.bands[1].frequency = 1000
equalizer.bands[1].bypass = false
engine.attach(equalizer) //Attach equalizer
// Connect nodes
engine.connect(inputNode, to: equalizer, format: inputNode.inputFormat(forBus: 0))
engine.connect(equalizer, to: engine.mainMixerNode, format: inputNode.inputFormat(forBus: 0))
// call before creating converter because this changes the mainMixer's output format
engine.prepare()
let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
sampleRate: 5000,
channels: 1,
interleaved: false)!
// Downsampling converter
guard let converter: AVAudioConverter = AVAudioConverter(from: engine.mainMixerNode.outputFormat(forBus: 0), to: outputFormat) else
print("Can't convert in to this format")
return
engine.mainMixerNode.installTap(onBus: bus, bufferSize: 2688, format: nil) (buffer, time) in
var newBufferAvailable = true
let inputCallback: AVAudioConverterInputBlock = inNumPackets, outStatus in
if newBufferAvailable
outStatus.pointee = .haveData
newBufferAvailable = false
return buffer
else
outStatus.pointee = .noDataNow
return nil
let convertedBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!
var error: NSError?
let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
assert(status != .error)
if status == .haveData
// Process with converted buffer
do
try engine.start()
catch
print("Can't start the engine: \(error)")
【讨论】:
谢谢它有效,我从没想过分配对象会导致问题。它节省了我的一天。 :) 我还有一个问题,低通滤波器的最佳最小值是多少?当我检查频率参数时,会出现类似 (Samplerate / 2) 的内容。你对此有什么想法吗? 恐怕我不知道 - 抱歉。 好的,谢谢你的帮助。以上是关于使用 Avaudioengine iOS 的低通滤波器 + 采样率转换的主要内容,如果未能解决你的问题,请参考以下文章