Exploring MusicKit: Audio Variants
Book

Exploring Freelancing

Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!

When Apple released audio variants in 2021, like Dolby Atmos, Dolby Audio, Hi-Res Lossless, Lossless, and Lossy stereo, it wasn’t available in the Apple Music API for third-party developers nor in the MusicKit framework.

However, Apple has provided full support for accessing the audio variants with Apple Music API and MusicKit, announced during WWDC 2022!

Using Audio Variants

To use audio variants in your app, an enumeration AudioVariant in MusicKit indicates the audio quality available for a music item like a Song or an Album.

enum AudioVariant

It has the following enumeration cases. I’ve directly copied the wording from the documentation to avoid messing up any technical details:

  • case dolbyAtmos:
    Dolby Atmos is an immersive audio experience that surrounds you with sound from all sides, including above.

  • case dolbyAudio:
    Dolby Audio is a surround sound format that includes Dolby 5.1 and 7.1.

  • case highResolutionLossless:
    Hi-Res Lossless uses Apple Lossless Audio Codec (ALAC) for bit-for-bit accuracy up to 24-bit/192 kHz.

  • case lossless:
    Lossless uses Apple Lossless Audio Codec (ALAC) for bit-for-bit accuracy up to 24-bit/48 kHz.

  • case lossyStereo:
    Lossy stereo uses compression used to store sound data.

This property is also available for the MusicPlayer under the observable class State. You can access the active audio variant for the current entry and display it on the now-playing view.

Note that it is only a readable property, and you cannot set it in our app. The user provides their preference in the Music app settings that they want Dolby Atmos and/or Hi-Res Lossless, and then the app automatically switches based on the network conditions.

@available(iOS 16.0, tvOS 16.0, *)
public var audioVariant: AudioVariant? { get }


Also, AudioVariant conforms to the CaseIterable protocol so you can access all the cases as an array:

AudioVariant.allCases /// <-- [AudioVariant]

Loading as Extended Attributes

As mentioned earlier, you can get a list of audio variants for a particular song or album. To keep the response lean, the song or album by default does not have the audioVariant values. You get this extended attribute using the with(_:) method on a song or album instance.

@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
extension PartialMusicProperty where Root == Album {
  public static let audioVariants: MusicExtendedAttributeProperty<Album, [AudioVariant]>
}

@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
extension PartialMusicProperty where Root == Song {
  public static let audioVariants: MusicExtendedAttributeProperty<Song, [AudioVariant]>
}

For example, while writing this blog post, I’m listening to the song AMAZING by Rex Orange County. The album WHO CARES? has the unique identifier 1606962225. Let us see what all audio variants are available for this particular album:

let request = MusicCatalogResourceRequest<Album>(matching: \.id, equalTo: "1606962225")
let response = try await request.response()

guard let album = response.items.first else { return }

let detailedAlbum = try await album.with(.audioVariants)

print(detailedAlbum.audioVariants)

If you are using MusadoraKit, then you can simply use the album method on MCatalog with the fetch parameter for fetching the audio variants:

let album = try await MCatalog.album(id: "1606962225", fetch: .audioVariants)

print(album.audioVariants)

The console prints:

Optional([.dolbyAtmos, .lossless, .lossyStereo])

You can also use it for individual songs. For example, the song Leywole from WWDC 2022 is something I cannot get out of my mind. Try to get the audio variants for it using the song’s identifier and extended attributes:

let request = MusicCatalogResourceRequest<Song>(matching: \.id, equalTo: "1575285202")
let response = try await request.response()

guard let song = response.items.first else { return }

let detailedSong = try await song.with(.audioVariants)

print(detailedSong.audioVariants)

If you are using MusadoraKit, then you can simply use the song method on MCatalog with the fetch parameter for fetching the audio variants:

let song = try await MCatalog.song(id: "1575285202", fetch: .audioVariants)

print(song.audioVariants)

The console gives the following output:

Optional([.lossless, .lossyStereo])

Now Playing View Example

If your app has a now-playing view similar to Apple Music, you can show the audio variant on the screen so the user may know the variant of audio that is currently playing.

In your NowPlayingView, switch over the cases of the audio variants and then set the image for it accordingly:

struct NowPlayingView: View {
  @ObservedObject private var state = ApplicationMusicPlayer.shared.state

  var body: some View {
    VStack(spacing: 0) {      
      switch state.audioVariant {
        case .dolbyAtmos:
          AudioVariantImage("dolby-atmos-logo")
        case .highResolutionLossless:
          AudioVariantImage("hi-res-lossless-logo")
        case.lossless:
          AudioVariantImage("lossless-logo")
        default:
          EmptyView()
      }
    }
  }
}

struct AudioVariantImage: View {
  var name: String
  
  public init(_ name: String) {
    self.name = name
  }
  
  var body: some View {
    Image(name)
      .resizable()
      .scaledToFit()
      .frame(width: 100)
      .padding(.top, 12)
  }
}

You can replace the image names with those you have and let your users know that your app supports audio variants!

Let me know what you think of MusicKit 2.0 by tagging @rudrankriyam on Twitter! I hope you’re enjoying exploring MusicKit as much as I do!

Book

Exploring Freelancing

Navigate freelancing as a developer; find clients, manage contracts, ensure timely payment, and learn from experiences!

Written by

Rudrank Riyam

Hi, my name is Rudrank. I create apps for Apple Platforms while listening to music all day and night. Author of "Exploring MusicKit". Apple WWDC 2019 scholarship winner.