Exploring MusicKit: Audio Variants
Sponsor • Book

Exploring MusicKit and Apple Music API

The best book for learning MusicKit and adding Apple Music capabilities to your app.

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)

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)

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!

Sponsor • Book

Exploring MusicKit and Apple Music API

The best book for learning MusicKit and adding Apple Music capabilities to your app.

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.