Hello,
I am trying to use AVAudioFile
to save audio buffer to .wav
file. The buffer is of type [Float]
.
Currently I am able to successfully create the .wav
files and even play them, but they are blank - I cannot hear any sound.
private func saveAudioFile(using buffer: [Float]) {
let fileUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("\(UUID().uuidString).wav")
let fileSettings = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVSampleRateKey: 15600,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
guard let file = try? AVAudioFile(forWriting: fileUrl, settings: fileSettings, commonFormat: .pcmFormatInt16, interleaved: true) else {
print("Cannot create AudioFile")
return
}
guard let bufferFormat = AVAudioFormat(settings: settings) else {
print("Cannot create buffer format")
return
}
guard let outputBuffer = AVAudioPCMBuffer(pcmFormat: bufferFormat, frameCapacity: AVAudioFrameCount(buffer.count)) else {
print("Cannot create output buffer")
return
}
for i in 0..<buffer.count {
outputBuffer.int16ChannelData!.pointee[i] = Int16(buffer[i])
}
outputBuffer.frameLength = AVAudioFrameCount(buffer.count)
do {
try file.write(from: outputBuffer)
} catch {
print(error.localizedDescription)
print("Write to file failed")
}
}
Where should I be looking first for the problem? Is it format issue?
I am getting the data from the microphone with the AVAudioEngine
.
Its format is created like this:
let outputFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: Double(15600), channels: 1, interleaved: true)!
And here is the installTap
implementation with the buffer callback:
input.installTap(onBus: 0, bufferSize: AVAudioFrameCount(sampleRate*2), format: inputFormat) { (incomingBuffer, time) in
DispatchQueue.global(qos: .background).async {
let pcmBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate * 2.0))
var error: NSError? = nil
let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in
outStatus.pointee = AVAudioConverterInputStatus.haveData
return incomingBuffer
}
formatConverter.convert(to: pcmBuffer!, error: &error, withInputFrom: inputBlock)
if error != nil {
print(error!.localizedDescription)
}
else if let pcmBuffer = pcmBuffer, let channelData = pcmBuffer.int16ChannelData {
let channelDataPointer = channelData.pointee
self.buffer = stride(from: 0, to: self.windowLengthSamples, by: 1).map { Float(channelDataPointer[$0]) / 32768.0 }
onBufferUpdated(self.buffer)
}
}
}
The onBufferUpdated
is the block that provides [Float]
for the saveAudioFile
method above.
I have tried some experiements with different output formats, but that ended up with unplayable audio files.