I found a way to accomplish this using AVAudioConverter:
let audioFileInputBuffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: UInt32(audioFile.length))!
try? audioFile.read(into: audioFileInputBuffer)
let outputFormat = AVAudioFormat(commonFormat: audioFile.fileFormat.commonFormat, sampleRate: audioFile.fileFormat.sampleRate, channels: 1, interleaved: false)!
let audioConverter = AVAudioConverter(from: audioFileInputBuffer.format, to: outputFormat)!
audioConverter.channelMap = [0]
let outputBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: UInt32(audioFile.length))!
var error: NSError?
let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in
outStatus.pointee = AVAudioConverterInputStatus.haveData
return audioFileInputBuffer
}
audioConverter.convert(to: outputBuffer, error: &error, withInputFrom: inputBlock)
if let error = error {
print("AUDIO CONVERSION ERROR: \(error.localizedDescription)")
}
var settings: [String: Any] = [:]
settings[AVFormatIDKey] = kAudioFormatLinearPCM
settings[AVAudioFileTypeKey] = kAudioFileWAVEType
settings[AVSampleRateKey] = outputBuffer.format.sampleRate
settings[AVNumberOfChannelsKey] = 1
settings[AVLinearPCMIsFloatKey] = false
let outputURL = audioURL.deletingLastPathComponent().appendingPathComponent("mono.wav")
let outputAudioFile = try? AVAudioFile(forWriting: outputURL, settings: settings, commonFormat: outputFormat.commonFormat, interleaved: false)
try? outputAudioFile?.write(from: outputBuffer)
let outputData = (try? Data(contentsOf: outputURL))!
But isn't there a simpler way to get the converted mono audio data? Going via a file is slow. I'd like to extract the audio data directly from outputBuffer
.