How to Combine Audio in Swift and Programmatically Get Music From iTunes/Music Library on Mac

Carlos Mbendera
CodeX
Published in
3 min readOct 28, 2022

Unlike most things in Swift, combining audio tracks is quite a process.

A good starting point was reading Greg Cerveny’s article on the topic. However, in this short article, I would like to illustrate how I did it and combined MP3 Playlists from my Mac. Here’s the complete project.

Photo by Daniel Schludi on Unsplash

Combining Audio

Firstly, when working with media, we will want to import AVFoundation.

import AVFoundation

Secondly, based on Greg’s code, we will write an extension for AVMutableCompositionTrack that simplifies appending audio tracks.

extension AVMutableCompositionTrack {
func append(url: URL) {
let newAsset = AVURLAsset(url: url)
let range = CMTimeRangeMake(start: CMTime.zero, duration: newAsset.duration)
let end = timeRange.end
if let track = newAsset.tracks(withMediaType: AVMediaType.audio).first {
try! insertTimeRange(range, of: track, at: end)
} else{
print("ERROR - Appending")
}
}
}

Now with that done. We need to write a function that gets the audio files and exports them. Assuming you already have a list of URLs to the songs you are combining, the code should be as follows.

var arrayOfSongPaths = [URL?]()

func combineSongs(){
let composition = AVMutableComposition()
let compositionAudioTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)

for path in arrayOfSongPaths{
compositionAudioTrack!.append(url: path!)
}

//Built the path like this but you can use any path you want. Just remember to handle permissions.
let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! as NSURL
let destinationURL = documentDirectoryURL.appendingPathComponent(" resultMerge.m4a")! as URL

if let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) {
assetExport.outputFileType = AVFileType.m4a
assetExport.outputURL = destinationURL

assetExport.exportAsynchronously( completionHandler: {
//You don't NEED to write these switch cases but they strongly help to debug
switch assetExport.status {

case AVAssetExportSession.Status.failed:
print("failed \(assetExport.error)")
case AVAssetExportSession.Status.cancelled:
print("cancelled \(assetExport.error)")
case AVAssetExportSession.Status.unknown:
print("unknown\(assetExport.error)")
case AVAssetExportSession.Status.waiting:
print("waiting\(assetExport.error)")
case AVAssetExportSession.Status.exporting:
print("exporting\(assetExport.error)")

default:
print("COMPLETED YAY!!!")
NSWorkspace.shared.open(documentDirectoryURL as URL)
}

})
}//asset export end

}

Congrats. If everything compiles and runs, Finder should open, showing you a m4a with all the audio files combined.

Getting Local Music From Your Mac Music Library

Photo by Wesson Wang on Unsplash

If you may want to compile a Playlist from iTunes/Music into a single audio file. This section is for you.

Firstly, import iTunesLibrary.

import iTunesLibrary

Secondly, we want to get all the playlists in the user’s library.

let library = try! ITLibrary(apiVersion: "1.1")
let playlists = library.allPlaylists

Assuming you know the name of the playlist you want. You can get the URL location for all the songs with this function.

func getPlaylistsData(for funcPlaylistName: String?){

guard let funcPlaylistName = funcPlaylistName else{
return
}
var stuffIWant: ITLibPlaylist {
for item in playlists{
if item.name == funcPlaylistName{
return item
}
}
return playlists[0] //Just in case in the loop fails
}

for song in stuffIWant.items{
arrayOfSongPaths.append(song.location)
}
}

🎊Congrats. You are done. Cheers 🎉

--

--

Carlos Mbendera
CodeX
Writer for

CS Major,  WWDC23 Student Challenge Winner and Jazz Fusion Enthusiast writing about Swift and other rad stuff.