如何在Avfoundation中正确更改采样率 [英] How to change sample rate properly in Avfoundation

查看:172
本文介绍了如何在Avfoundation中正确更改采样率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经完成了这个简单的程序.它的作用是只记录并同时播放缓冲区.如果采样率是44100 Hz,一切正常,但是如果我将采样率更改为16000或8000,则它根本不会发出任何声音,或者可能会产生一些白噪声,这是不可审计的.为什么会这样?

I have done this simple program. what it does is it just record and play back the buffers simultaneously. Everything works fine if the sample rate is 44100 hz but if I change the sample rate to 16000 or 8000, it doesn't producing any sound at all or may be some white noise which is not audiable.Why is this happening?

如何记录不同的采样率?

How can I record with different sample rate?

以下我尝试过的代码:

import UIKit
import AVFoundation

class ViewController: UIViewController  {

var engine = AVAudioEngine()
let player = AVAudioPlayerNode()
let audioSession = AVAudioSession.sharedInstance()
let newSrc:UnsafeMutablePointer<Float>! = nil
override func viewDidLoad() {
super.viewDidLoad()



let audioSession = AVAudioSession.sharedInstance()
print(audioSession.sampleRate) // here it prints 44100 hz. because it still using the internal mic.
do {

    try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .allowBluetooth)
    try audioSession.setMode(AVAudioSessionModeDefault)
    try audioSession.setActive(true)

} catch {
}
print(audioSession.sampleRate) // here it will print 16000 hz if my bluetooth earbuds is connected, if not it will be 44100 hz.

let input = engine.inputNode
let bus = 0
let mixer = AVAudioMixerNode() // creating mixer as it is needed to set audio format

engine.attach(mixer)
engine.attach(player)
engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0))

let inputFormat = input.inputFormat(forBus: bus)

engine.connect(player, to: engine.mainMixerNode, format: input.inputFormat(forBus: 0))

let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100.0, channels: 1, interleaved: false)

mixer.installTap(onBus: bus, bufferSize: 1024, format: fmt) { (buffer, time) -> Void in

    print(buffer.format)
    print(buffer.floatChannelData)
    print(buffer.format.streamDescription.pointee.mBytesPerFrame)
    self.player.scheduleBuffer(buffer)
    if self.player.isPlaying {
        print("true")
    }
}


engine.prepare()
do{
    try! engine.start()
    player.play()
} catch {
    print(error)
}
}

}

推荐答案

在此处讨论AVAudioEngine混合器节点和分接头都不会为您进行费率转换.实际上,在您的情况下,调音器无声地敲打(明白吗?)可以使您保持沉默,而不是引发或记录错误.

As discussed here, neither AVAudioEngine mixer nodes nor taps will do rate conversion for you. In fact in your case instead of throwing or logging an error, the mixer tap silently (get it?) gives you silence.

由于不能使用AVAudioMixerNode进行费率转换,因此可以将其替换为方便的AVAudioConverter,请确保设置AVAudioPlayerNode的正确输出格式,因为

Since you can't use an AVAudioMixerNode for rate conversion, you can replace it with the convenient AVAudioConverter, making sure to set the correct output format of the AVAudioPlayerNode because

在播放缓冲区时,有一个隐含的假设,即缓冲区处于同一位置 采样率作为节点的输出格式.

When playing buffers, there is an implicit assumption that the buffers are at the same sample rate as the node's output format.

如果不这样做,您可能会听到间隙和/或音高变化的音频.

If you don't do this you may hear gaps and/or pitch shifted audio.

像这样

let input = engine.inputNode
let bus = 0
let inputFormat = input.inputFormat(forBus: bus)

engine.attach(player)

let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)!
engine.connect(player, to: engine.mainMixerNode, format: fmt)

let converter = AVAudioConverter(from: inputFormat, to: fmt)!

input.installTap(onBus: bus, bufferSize: 1024, format: inputFormat) { (buffer, time) -> Void in
    let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
        outStatus.pointee = AVAudioConverterInputStatus.haveData
        return buffer
    }

    let convertedBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: AVAudioFrameCount(fmt.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!

    var error: NSError? = nil
    let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
    assert(status != .error)

    print(convertedBuffer.format)
    print(convertedBuffer.floatChannelData)
    print(convertedBuffer.format.streamDescription.pointee.mBytesPerFrame)
    self.player.scheduleBuffer(convertedBuffer)
}

这篇关于如何在Avfoundation中正确更改采样率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆