[英]How to change sample rate properly in Avfoundation
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?
如果采样率为 44100 hz,一切正常,但如果我将采样率更改为 16000 或 8000,它根本不会产生任何声音,或者可能是一些听不见的白噪声。为什么会发生这种情况?
How can I record with different sample rate?
如何以不同的采样率进行录制?
Following code I have tried:以下代码我试过:
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)
}
}
}
As discussed here , neither AVAudioEngine
mixer nodes nor taps will do rate conversion for you.正如这里所讨论的,无论是
AVAudioEngine
混音器节点还是抽头都不会为您进行速率转换。 In fact in your case instead of throwing or logging an error, the mixer tap silently (get it?) gives you silence.事实上,在你的情况下,而不是抛出或记录错误,混音龙头默默地(明白了吗?)让你沉默。
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由于您不能使用
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.
在播放缓冲区时,有一个隐含的假设,即缓冲区的采样率与节点的输出格式相同。
If you don't do this you may hear gaps and/or pitch shifted audio.如果您不这样做,您可能会听到间隙和/或音调偏移的音频。
Like so像这样
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)
}
This solution worked for me这个解决方案对我有用
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)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.