AVAudioEngine 下采样问题
AVAudioEngine downsample issue
我在对从麦克风获取的音频进行下采样时遇到问题。我正在使用 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 5 秒内运行良好,因为麦克风输入为 8000Hz,并且缓冲区中充满了来自麦克风的数据。
问题是我希望能够从 iPhone 6 秒(及以上)录制麦克风以 16000Hz 录制的内容。奇怪的是,如果我将 mixernode 与引擎 mainmixernode 连接(使用以下代码):
engine.connect(mixer, to: mainMixer, format: audioFormat)
这确实有效,我得到的缓冲区具有 8000Hz 的格式,并且声音经过完美的降采样,唯一的问题是声音也来自我不想要的扬声器(如果我不想要'连接它缓冲区是空的)。
有谁知道如何解决这个问题?
非常感谢任何帮助、意见或想法。
我通过简单地将混音器音量更改为 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)
}
我发现唯一可以改变采样率的方法是
AVAudioSettings.sharedInstance().setPreferredSampleRate(...)
遗憾的是,虽然 8000、12000、16000、22050、44100 似乎都有效,但无法保证您会获得所需的采样率。
以下无效:
- 点击关闭设置我的自定义格式 engine.inputNode。 (例外)
- 使用我的自定义格式添加混音器并点击它。 (例外)
- 添加一个混音器,将其与输入节点的格式连接,将混音器连接到主混音器以我的自定义格式,然后移除输出节点的输入,以免将音频发送到扬声器并获得即时反馈。 (有效,但全部为零)
- 在 AVAudioEngine 中完全没有使用我的自定义格式,而是使用 AVAudioConverter 从我的水龙头中的硬件速率进行转换。 [未设置缓冲区长度,无法判断结果是否正确]
另一种方法,AVAudioConverter
in Swift 5
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) }
}
我在对从麦克风获取的音频进行下采样时遇到问题。我正在使用 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 5 秒内运行良好,因为麦克风输入为 8000Hz,并且缓冲区中充满了来自麦克风的数据。
问题是我希望能够从 iPhone 6 秒(及以上)录制麦克风以 16000Hz 录制的内容。奇怪的是,如果我将 mixernode 与引擎 mainmixernode 连接(使用以下代码):
engine.connect(mixer, to: mainMixer, format: audioFormat)
这确实有效,我得到的缓冲区具有 8000Hz 的格式,并且声音经过完美的降采样,唯一的问题是声音也来自我不想要的扬声器(如果我不想要'连接它缓冲区是空的)。
有谁知道如何解决这个问题?
非常感谢任何帮助、意见或想法。
我通过简单地将混音器音量更改为 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)
}
我发现唯一可以改变采样率的方法是
AVAudioSettings.sharedInstance().setPreferredSampleRate(...)
遗憾的是,虽然 8000、12000、16000、22050、44100 似乎都有效,但无法保证您会获得所需的采样率。
以下无效:
- 点击关闭设置我的自定义格式 engine.inputNode。 (例外)
- 使用我的自定义格式添加混音器并点击它。 (例外)
- 添加一个混音器,将其与输入节点的格式连接,将混音器连接到主混音器以我的自定义格式,然后移除输出节点的输入,以免将音频发送到扬声器并获得即时反馈。 (有效,但全部为零)
- 在 AVAudioEngine 中完全没有使用我的自定义格式,而是使用 AVAudioConverter 从我的水龙头中的硬件速率进行转换。 [未设置缓冲区长度,无法判断结果是否正确]
另一种方法,AVAudioConverter
in Swift 5
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) }
}