如何在 Avfoundation 中正确更改采样率
How to change sample rate properly in Avfoundation
我已经完成了这个简单的程序。它所做的只是同时记录和回放缓冲区。如果采样率为 44100 赫兹,一切正常,但如果我将采样率更改为 16000 或 8000,它根本不会产生任何声音,或者可能是一些不是 audiable.Why 的白噪声,这是否正在发生?
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)
}
}
}
与discussed here一样,AVAudioEngine
混合器节点和分路器都不会为您进行速率转换。事实上,在你的情况下,而不是抛出或记录错误,混合龙头静静地(明白了吗?)让你沉默。
由于您不能使用 AVAudioMixerNode
进行速率转换,您可以将其替换为方便的 AVAudioConverter
,确保设置正确的 AVAudioPlayerNode
输出格式,因为
When playing buffers, there is an implicit assumption that the buffers are at the same
sample rate as the node's output format.
如果不这样做,您可能会听到间隙 and/or 音调偏移的音频。
像这样
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)
}
这个解决方案对我有用
let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)!
inputNode.installTap(onBus: 0, bufferSize: 1024, format: fmt) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}
我已经完成了这个简单的程序。它所做的只是同时记录和回放缓冲区。如果采样率为 44100 赫兹,一切正常,但如果我将采样率更改为 16000 或 8000,它根本不会产生任何声音,或者可能是一些不是 audiable.Why 的白噪声,这是否正在发生?
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)
}
}
}
与discussed here一样,AVAudioEngine
混合器节点和分路器都不会为您进行速率转换。事实上,在你的情况下,而不是抛出或记录错误,混合龙头静静地(明白了吗?)让你沉默。
由于您不能使用 AVAudioMixerNode
进行速率转换,您可以将其替换为方便的 AVAudioConverter
,确保设置正确的 AVAudioPlayerNode
输出格式,因为
When playing buffers, there is an implicit assumption that the buffers are at the same sample rate as the node's output format.
如果不这样做,您可能会听到间隙 and/or 音调偏移的音频。
像这样
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)
}
这个解决方案对我有用
let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)!
inputNode.installTap(onBus: 0, bufferSize: 1024, format: fmt) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
self.recognitionRequest?.append(buffer)
}