I'm creating an AVAudioFile for writing sound to a sound file. If the file already exists I want to move the framePosition to the end of the file, to continue writing at the end, instead of replacing the existing file.
I did some tests, trying to read the buffer from the file into a new file, with a different URL, so that it won't overwrite the original file. I'm getting a crash when I'm trying to read the buffer into the new file:
let audioFile = try AVAudioFile(forReading: [URL to existing .caf file])
let audioFrameCount = AVAudioFrameCount(UInt32(audioFile.length))
let audioBuffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: audioFrameCount)
let newAudioFile = try AVAudioFile(forWriting: [another URL], settings: self.engine.mainMixerNode.outputFormatForBus(0).settings)
try newAudioFile.readIntoBuffer(audioBuffer, frameCount: audioFrameCount!) <-- CRASHES ON THIS LINE
Crash log: Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -50'
Man, I really hate the CoreAudio crash logs. They tell me absolutely nothing!
Isn't it possible to read data into a file that's been created for writing?
UPDATE
OK, so after some suggestions I did some changes. Basically, these are the steps I'm taking:
However, the length of the new file is 0 after I have written to it.
Here's my code:
//Check if a file already exists. If so continue to record at the end of it
var audioBuffer : AVAudioPCMBuffer!
var audioFrameCount : AVAudioFrameCount!
if (NSFileManager.defaultManager().fileExistsAtPath(self.audioRecordURL.path!)) {
do {
let existingAudioFile = try AVAudioFile(forReading: self.audioRecordURL)
audioFrameCount = AVAudioFrameCount(existingAudioFile.length)
if (audioFrameCount > 0) {
audioBuffer = AVAudioPCMBuffer(PCMFormat: existingAudioFile.processingFormat, frameCapacity: audioFrameCount)
}
} catch let error as NSError {
NSLog("Error reading buffer from file %@", error.localizedDescription)
}
}
//Create a new file. This will replace the old file
do {
self.audioFile = try AVAudioFile(forWriting: self.audioRecordURL, settings: self.engine.mainMixerNode.outputFormatForBus(0).settings)
} catch let error as NSError {
NSLog("Error creating AVAudioFile %@", error.localizedDescription)
}
//Read the audio buffer from the old file into the new file
if (audioBuffer != nil) {
do {
try self.audioFile.writeFromBuffer(audioBuffer)
self.audioFile.framePosition = self.audioFile.length
} catch let error as NSError {
NSLog("Error reading buffer into file %@", error.localizedDescription)
}
}
By the way, the naming of the readIntoBuffer is extremely confusing to me. It sounds as if you should use that method to read a file into a buffer, but according to the documentation you should use it to read a buffer into a file? So why can't I use that method to add the buffer to my file? Why do I have to use writeFromBuffer?
UPDATE 2
So, I managed to solve it. Apparently I had to call readIntoBuffer to actually fill the buffer with data before I could use it. So I added this line
try existingAudioFile.readIntoBuffer(audioBuffer)
after
audioBuffer = AVAudioPCMBuffer(PCMFormat: existingAudioFile.processingFormat, frameCapacity: audioFrameCount)
Not sure if this is just a typo in the code you've provided here, and I'm not an expert in this area, but presumably you meant to have the line that crashes be:
try audioFile.readIntoBuffer(audioBuffer, frameCount: audioFrameCount!)
because it stands to reason that you can't read from a file opened for writing (newAudioFile).
And then after filling that buffer you would want to write to the new file using writeFromBuffer https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioFile_Class/#//apple_ref/occ/instm/AVAudioFile/writeFromBuffer:error:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With