【问题标题】:AVAudioEngine downsample issueAVAudioEngine 下采样问题
【发布时间】:2017-01-28 10:59:32
【问题描述】:

我在对从麦克风获取的音频进行下采样时遇到问题。我正在使用 AVAudioEngine 通过以下代码从麦克风中获取样本:

assert(self.engine.inputNode != nil)
let input = self.engine.inputNode!

let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)    
let mixer = AVAudioMixerNode()
engine.attach(mixer)
engine.connect(input, to: mixer, format: input.inputFormat(forBus: 0))

do {
    try engine.start()

    mixer.installTap(onBus: 0, bufferSize: 1024, format: audioFormat, block: {
            (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
        //some code here
    })

} catch let error {
    print(error.localizedDescription)
}

此代码在 iPhone 5s 上运行良好,因为麦克风输入为 8000Hz,并且缓冲区充满了来自麦克风的数据。

问题是我希望能够从 iPhone 6s(及更高版本)录制麦克风以 16000Hz 录制。奇怪的是,如果我将混合器节点与引擎主混合器节点连接(使用以下代码):

engine.connect(mixer, to: mainMixer, format: audioFormat)

这确实有效,我得到的缓冲区格式为 8000Hz,声音完全下采样,唯一的问题是声音也来自我不想要的扬声器(如果我不想要连接它缓冲区是空的)。

有谁知道如何解决这个问题?

非常感谢任何帮助、输入或想法。

【问题讨论】:

    标签: swift audio core-audio swift3 avaudioengine


    【解决方案1】:

    另一种方法,在 Swift 5

    中使用 AVAudioConverter
    let engine = AVAudioEngine()
    
    
    func setup() {
    
        let input = engine.inputNode
        let bus = 0
        let inputFormat = input.outputFormat(forBus: bus )
        guard let outputFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: true), let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else{
            return
        }
    
        input.installTap(onBus: bus, bufferSize: 1024, format: inputFormat) { (buffer, time) -> Void 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
                }
            }
    
            if 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)
    
                // 8kHz buffers
                print(convertedBuffer.format)
            }
        }
        do {
            try engine.start()
        } catch { print(error) }
    }
    

    【讨论】:

    • 接受的方法只给了我空缓冲区。转换器的解决方案对我有用,谢谢!
    • 嗨哥们,你能帮我解决我的问题吗:stackoverflow.com/questions/66971504/…
    • 刚看到。修复了崩溃,然后您通过设备获得了 48000。你可以通过转换得到44100
    【解决方案2】:

    我发现唯一能改变采样率的是

    AVAudioSettings.sharedInstance().setPreferredSampleRate(...)
    

    不幸的是,虽然 8000、12000、16000、22050、44100 似乎都有效,但无法保证您将获得所需的采样率。

    以下操作无效:

    1. 在分接 engine.inputNode 中设置我的自定义格式。 (例外)
    2. 使用我的自定义格式添加混音器并点击它。 (例外)
    3. 添加一个混音器,将其与 inputNode 的格式连接,将混音器连接到具有我自定义格式的主混音器,然后删除 outputNode 的输入,以免将音频发送到扬声器并获得即时反馈。 (有效,但全为零)
    4. 在 AVAudioEngine 中根本不使用我的自定义格式,而是使用 AVAudioConverter 从我的 Tap 中的硬件速率转换。 [未设置缓冲区长度,无法判断结果是否正确]

    【讨论】:

    • @matt 答案似乎有四次都是相关的,而且由于我在解决问题的过程中遇到了所有四个问题,我认为这有助于避免其他人的麻烦。那么我应该怎么做呢?选择一个地方回答它并在其他地方放一个链接?
    • 对我不起作用,你能帮忙吗? stackoverflow.com/questions/66971504/…
    【解决方案3】:

    我通过简单地将混音器音量更改为 0 解决了这个问题。

    mixer.volume = 0
    

    这使我能够利用引擎主混音器的强大功能将任何采样率重新采样到我想要的采样率,并且不会听到直接从扬声器发出的麦克风反馈回路。如果有人需要对此进行任何澄清,请告诉我。

    这是我现在的代码:

    assert(self.engine.inputNode != nil)
    let input = self.engine.inputNode!
    
    let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)    
    let mixer = AVAudioMixerNode()
    engine.attach(mixer)
    engine.connect(input, to: mixer, format: input.inputFormat(forBus: 0))
    mixer.volume = 0
    engine.connect(mixer, to: mainMixer, format: audioFormat)
    
    do {
        try engine.start()
    
        mixer.installTap(onBus: 0, bufferSize: 1024, format: audioFormat, block: {
            (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
            //some code here
        })
    
    } catch let error {
        print(error.localizedDescription)
    }
    

    【讨论】:

    • 你在哪里定义“mainMixer”?
    • 很久以前我写了这段代码,但我 95% 确定那是 AVAudioEngines 主混音器节点。
    • 如果我使用此代码,它会在缓冲区中为我提供全零。你知道我做错了什么吗?我正在使用麦克风输入采样率为 44100Hz 的 iPhone 7。
    • @RobertVeringa 很奇怪,你是在真实设备上运行还是在模拟器上运行?因为它不适用于模拟器。您还可以测试我的问题中的第一个代码,看看您是否可以通过扬声器听到任何声音。此外,您可以尝试将 AudioFormat 更改为 input.inputFormat(forBus: 0) 以查看缓冲区中是否有任何数据。
    • 感谢您的回复。我必须将音频引擎的首选采样率配置为 16000Hz 并将其下采样到 8000Hz
    猜你喜欢
    • 2013-03-27
    • 2022-01-23
    • 2021-12-25
    • 1970-01-01
    • 2020-03-05
    • 2016-11-06
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多