Recently (like today), I had the need to concatenate multiple MP3s into a single sound file for playback in a notification. There is a bit of Objective-C code available for demonstrating this process, but nothing in Swift. So, here’s my Swift:
func createSound(soundFiles: [String], outputFile: String) {
var startTime: CMTime = kCMTimeZero
let composition: AVMutableComposition = AVMutableComposition()
let compositionAudioTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
for fileName in soundFiles {
let sound: String = Bundle.main.path(forResource: fileName, ofType: "mp3")!
let url: URL = URL(fileURLWithPath: sound)
let avAsset: AVURLAsset = AVURLAsset(url: url)
let timeRange: CMTimeRange = CMTimeRangeMake(kCMTimeZero, avAsset.duration)
let audioTrack: AVAssetTrack = avAsset.tracks(withMediaType: AVMediaTypeAudio)[0]
try! compositionAudioTrack.insertTimeRange(timeRange, of: audioTrack, at: startTime)
startTime = CMTimeAdd(startTime, timeRange.duration)
}
let exportPath: String = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].path+"/"+outputFile+".m4a"
let export: AVAssetExportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)!
export.outputURL = URL(fileURLWithPath: exportPath)
export.outputFileType = AVFileTypeAppleM4A
export.exportAsynchronously {
if export.status == AVAssetExportSessionStatus.completed {
NSLog("All done");
}
}
}
No error checking in the “try” lines, but that is left up to you. The function (createSound) takes an Array of MP3 files (found in the application bundle) and creates a single named M4A file from the concatenated result.
Filenames provided to the function do not include the suffix (.mp3, etc.).