I am trying to convert AVAudioPCMBuffer
from Float32 44.1kHz to Int16 8kHz. I use AVAudioConverter
. But after the conversion I get corrupted data. When I read data every 100ms from microphone I get every 800th sample broken (first sample in the read data). Broken sample looks as follows:
broken sample
It's just one sample out of 800 but it sounds like really annoying click every 100ms. Here is a piece of my code:
...
let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16,
sampleRate: 8000,
channels: 1,
interleaved: false)!
let input = self.engine.inputNode
let bus = 0
let inputFormat = input.outputFormat(forBus: bus)
let bufferSize = inputFormat.sampleRate * 0.1 // Read every 100ms
input.installTap(onBus: bus, bufferSize: UInt32(bufferSize), format: inputFormat) { (buffer, time) -> Void in
let convertedBuffer = self.convertBuffer(buffer: buffer, from: inputFormat, to: outputFormat)
if self.isRecording {
self.inFile?.seekToEndOfFile()
let data = Data(buffer: UnsafeBufferPointer(start: convertedBuffer.int16ChannelData![0], count: Int(convertedBuffer.frameLength)))
self.inFile?.write(data)
}
...
func convertBuffer(buffer: AVAudioPCMBuffer,
from inputFormat: AVAudioFormat,
to outputFormat: AVAudioFormat) -> AVAudioPCMBuffer {
let converter = AVAudioConverter(from: inputFormat, to: outputFormat)!
let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
outStatus.pointee = .haveData
return buffer
}
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)
return convertedBuffer
}
When I write buffer without any conversion I get clear sound without corruption. If I read data every 200ms every 1600th sample will be corrupted. So it's only the first sample from every buffer I get is corrupted.
I really don't know what is wrong with my code and why it works like that. Is there any error?
P.S. I don't really care about the conversion, all I need is get 16 bit PCM 8kHz raw audio data from microphone. If anyone knows how to do that the other way I'd really appreciate your help.
Audio converters have internal state. Creating a single converter instead of one in each call to
convertBuffer
should fix the issue.