MixRadio Developers - MixRadio .Net SDK Example Music Explorer

MixRadio Example: “Music Explorer”

Music Explorer is an example application demonstrating the use of the MixRadio API together with standard Windows Phone 8 audio features to create an immersive music experience.

It shows how to take advantage of MixRadio API features such as searching for artists by name, requesting top artists and new releases, and it also shows how to launch MixRadio application from within another application to play mix radio or show artist and product information.

Besides utilizing MixRadio API features, the app integrates with the local music in the device in a number of educated ways. Favourites are ordered according to the most played artist in the device, recommended list is ordered by how many times an artist is found to be similar to your favourites, and you can also play the local songs of your favourite artist.

Building the application

Clone the application solution source code and open the MusicExplorer.sln file in the Visual Studio. Start building and running the application by hitting F5 or selecting Start Debugging from the Debug menu.

Design

The application is a visually attractive example demonstrating how to take advantage of the rich MixRadio API in Windows Phone applications running in Lumia devices. With MixRadio API it is possible to request information on artist by name, such as tracks, albums, and singles available for download via MixRadio. It is also possible to request lists of latest releases and top artists, or even top artists in a certain genre. Genre lists and the radio mix lists are also available through MixRadio API.

The main panorama of the application contains six items: favourites, recommended, what’s new, who’s hot, genres, and mixes. Favourites shows 20 most played artists in the device and the artist information is retrieved using MixRadio API. Recommended shows artists which are found to be similar to your favourites and the list is ordered by how many times an artist is found to be similar to your favourites. What’s new and who’s hot simply show 10 latest products and 10 top artists in MixRadio service. Genres and mixes show corresponding lists of available genres and mixes in MixRadio service. All the lists are country specific, and for this reason locationing services are used to obtain device’s current location. The main panorama of the application is shown in full in the picture below.

The MixRadio API can also be used to launch MixRadio from the context of a different application. MixRadio app can be launched for example to show an artist or product view or it can be launched directly to play a specific mix. A note symbol is shown whenever interaction with specific item takes the user into MixRadio (see for example the list of “what’s new” above).

Another main component of the user interface is the artist pivot. Artist pivot can be used to find out what kind of products are available in MixRadio service for a certain artist. It is not possible to download products using MixRadio API and interaction with a product takes user to MixRadio application where the product can be downloaded. While in artist pivot, it is also possible to launch artist mix in MixRadio or to listen to local tracks stored in the device. Below are screenshots of the artist pivot.

Architecture overview

Architecture breakdown

User interface

User interface of the application consists of MainPage, ArtistPivotPage, TopArtistsForGenrePage, MixesPage, and informational AboutPage, all derived from PhoneApplicationPage. MainPage contains the main panorama featuring favourites, recommended, top artists, latest releases, genres list, and mixes list panorama items. TopArtistsForGenrePage is reached by selecting a genre from the MainPage and it features, as it’s name suggests, top artists for that particular genre. Correspondingly MixesPage is reached by selecting a mix group from the MainPage and it features the mixes in that particular mix group. ArtistPivotPage is reached by selecting an artist from either MainPage or TopArtistsForGenrePage and its five pivot items feature artist details, tracks, albums, and singles available for download, as well as similar artists for that particular artist.

Windows Phone Location API

Windows Phone Location APIs under the namespace Windows.Devices.Geolocation are used to determine the phone’s current location. To be able to use location services the application must have ID_CAP_LOCATION capability specified in WMAppManifest.xml file.

Maps API

Windows Phone 8 Maps APIs offer map related services (Microsoft.Phone.Maps.Services). ReverseGeocodeQuery is used to obtain a location specific country code for initializing MixRadio connection to current location. To be able to use the Maps APIs the application must have ID_CAP_MAP capability specified in WMAppManifest.xml file.

MixRadio API

The MixRadio API is used to get locale-dependent and up-to-date information on most popular artists and new releases, available genres and mix lists. Searches for artists by name are made in order to link locally stored tracks in the device correctly to the artists available in MixRadio service. The API is also used to launch MixRadio into various states (artist, product, mix) directly from Music Explorer.

XNA Media API

Media APIs in namespace Microsoft.Xna.Framework.Media, especially classes MediaLibrary and MediaPlayer, are used to get a list of tracks stored locally in device with artist and play count information, as well as to shuffle and play locally available tracks of an artist in ArtistPivotPage. These features require ID_CAP_MEDIALIB_AUDIO and ID_CAP_MEDIALIB_PLAYBACK capabilities to be specified in WMAppManifest.xml.

Using Nokia MixRadio

Prerequisites

In order to use the MixRadio API, the application must have an unique Client ID (unless using launchers only). These can be obtained by visiting the registration page and requesting credentials. Windows Phone 8 applications must also add a reference to the actual MixRadio API client. Instructions to add the references to the solution can be found in the Quick Start guide.

Localizing the API

Before making any requests to the API, Music Explorer checks for MixRadio availability in current location, resolved using Windows Phone Location API . By default, the MixRadio API uses (and checks) phone Region settings with each API call made. This allows users to see the relevant, and partly localized, country specific information. This can be seen in the image of main panorama in the Design section, showing genres and mixes available in Finland, as well as Finland’s most popular artists at the moment. These lists would contain different items if another valid country code (such as de for Germany or gb for United Kingdom) was used to initialize the API.

using Nokia.Music;
 
...
  
namespace MusicExplorer 
    {     
    ...  
    
    public partial class MainPage : PhoneApplicationPage     
    {         
        ...
 
        private CountryResolver resolver = null;
 
        ...
 
        private void ReverseGeocodeQuery_QueryCompleted(             
            object sender,              
            QueryCompletedEventArgs<IList<MapLocation>> e)         
        {             
            if (e.Error == null)             
            {                 
                if (e.Result.Count > 0)                 
                {                     
                    MapAddress address = e.Result[0].Information.Address;                     
                    string twoLetterCountryCode =                          
                        CountryCodes.TwoLetterFromThreeLetter(address.CountryCode);                     
                    InitializeNokiaMusicApi(twoLetterCountryCode);                 
                }             
            }         
        }         
 
        private void InitializeNokiaMusicApi(string twoLetterCountryCode)         
        {
            if (resolver == null)
            {
                resolver = new CountryResolver(MusicApi.MUSIC_EXPLORER_APP_ID);
            }

            if (twoLetterCountryCode != null)
            {
                if (!resolver.CheckAvailabilityAsync(twoLetterCountryCode.ToLower()))
                {
                    MessageBox.Show("Sorry, Nokia MixRadio is not available in this locale.");
                    twoLetterCountryCode = null;
                }
            }

            // If country code is null, phone region settings are used
            App.MusicApi.Initialize(twoLetterCountryCode);
        
            ...
        }     
    } 
}

Creating the client

In the Music Explorer application, the communication with the MixRadio API, with the exception of CountryResolver usage described above, is encapsulated into MusicApi class for easy reference. All requests to the MixRadio service are made using MusicClient class, and therefore the next step after confirming MixRadio availability is creating the MusicClient in the Initialize method of MusicApi.

using Nokia.Music; 
using Nokia.Music.Tasks; 
using Nokia.Music.Types;
 
... 
 
namespace MusicExplorer 
{     
    ...
      
    public class MusicApi     
    {         
        // Constants         
        public const string MUSIC_EXPLORER_CLIENT_ID = "music_explorer_private_client_id"; // real client id not shown here

        // Members         
        private MusicClient client = null;         
        private bool initialized = false;
         
        ...
 
        public void Initialize(string countryCode)         
        { 
            // Create a music client with correct ClientId
            if (countryCode == null || countryCode.Length != 2)
            {
                client = new MusicClient(MUSIC_EXPLORER_CLIENT_ID);
            }
            else
            {
                client = new MusicClient(MUSIC_EXPLORER_CLIENT_ID, countryCode.ToLower());
            }
            initialized = true;   
        }
         
        ...     
    } 
}

Making requests

Requests to the MixRadio service can be sent after creating a localized MusicClient instance. For example the GetTopArtistsAsync method of MusicApi requests 10 most popular artists from MixRadio (in the country the MusicClient was initialized with) and populates the TopArtists of the MainViewModel accordingly. As the process with other requests (new releases, genres, etc.) is almost identical to requesting 10 most popular artists, they are not described here. See the ​project source for exact implementation reference.

namespace MusicExplorer 
{
     
    ...
      
    public class MusicApi     
    {         
        ...
          
        // Members         
        private MusicClient client = null;         
        private bool initialized = false;
         
        ...
          
        public void GetTopArtists()
        {
            if (!initialized)
            {
                return;
            }

            ShowProgressIndicator("GetTopArtists()");

            ListResponse<Artist> response = await client.GetTopArtistsAsync();
            if (response != null && response.Result != null && response.Result.Count > 0)
            {
                App.ViewModel.TopArtists.Clear();

                // Insert a place holder for title text
                App.ViewModel.TopArtists.Add(new ArtistModel()
                {
                    Name = "TitlePlaceholderwho's hot",
                    ItemHeight = "110",
                    ItemWidth = "450"
                });

                foreach (Artist a in response.Result)
                {
                    App.ViewModel.TopArtists.Add(new ArtistModel()
                    {
                        Name = a.Name,
                        Country = CountryCodes.CountryNameFromTwoLetter(a.Country),
                        Genres = a.Genres[0].Name,
                        Thumb100Uri = a.Thumb100Uri,
                        Thumb200Uri = a.Thumb200Uri,
                        Thumb320Uri = a.Thumb320Uri,
                        Id = a.Id,
                        ItemWidth = "205",
                        ItemHeight = "205"
                    });
                }
            }

            if (response != null && response.Error != null)
            {
                ShowNokiaMusicApiError();
            }

            HideProgressIndicator("GetTopArtists()");
        }
      
        ...     
    } 
}

The top artists can then be shown in panorama on MainPage (data context is set in the constructor of the MainPage):

namespace MusicExplorer 
{     
    ...
      
    public partial class MainPage : PhoneApplicationPage     
    {         
        ...
          
        public MainPage()         
        {             
            ...             
            DataContext = App.ViewModel;             
            ...         
        }
                  
        ...     
    } 
}
<phone:PhoneApplicationPage x:Class="MusicExplorer.MainPage"     
    ...>
       
    ...
      
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!--Panorama control-->
        <phone:Panorama SelectionChanged="Panorama_SelectionChanged">

            ...
                
            <!--Who's Hot Item-->
            <phone:PanoramaItem Margin="0,0,0,30">
                <Grid>
                    <ListBox Margin="0,-38,-22,0" x:Name="TopArtistsList" ItemsSource="{Binding TopArtists}" SelectionChanged="OnTopArtistsSelectionChanged">
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <toolkit:WrapPanel/>
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>

                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <controls:TileItem Height="{Binding ItemHeight}"
                                                   Width="{Binding ItemWidth}"
                                                   ItemWidth="{Binding ItemWidth}"
                                                   PrimaryText="{Binding Name}"
                                                   SecondaryText="{Binding Country}"
                                                   Image="{Binding ThumbUri}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Grid>
            </phone:PanoramaItem>   
            
            ...
         
         </phone:Panorama>               
    </Grid>
        
    ...
      
</phone:PhoneApplicationPage>

MixRadio launchers

The following methods from MusicApi show how simple it is to launch MixRadio into mix, product, and artist states using the MixRadio launchers:

using Nokia.Music;
using Nokia.Music.Tasks;
 
... 
 
namespace MusicExplorer 
{     
    ...
       
    public class MusicApi     
    {         
        ...
          
        public void LaunchMix(string id)         
        {             
            ...
              
            PlayMixTask task = new PlayMixTask();             
            task.MixId = id;             
            task.Show();         
        }
          
        public void LaunchArtistMix(string artistName)         
        {             
             ...
              
             PlayMixTask task = new PlayMixTask();             
             task.ArtistName = artistName;             
             task.Show();         
        }
          
        public void LaunchProduct(string id)         
        {             
            ...
              
            ShowProductTask task = new ShowProductTask();             
            task.ProductId = id;             
            task.Show();         
        }
          
        public void LaunchArtist(string id)         
        {             
            ...
              
            ShowArtistTask task = new ShowArtistTask();             
            task.ArtistId = id;             
            task.Show();         
        }
         
        ...     
    } 
}

Building a favourites list

The list of artists in MainPage’s Favourites view is made in LoadData method of MainViewModel. Comments in the code describe the steps taken to build the list:

using Microsoft.Xna.Framework.Media;
 
... 
 
namespace MusicExplorer.Models 
{     
    ... 
     
    public class MainViewModel : INotifyPropertyChanged     
    {         
        ... 
 
        public ObservableCollection<ArtistModel> LocalAudio { get; private set; } 
 
        ... 
 
        MediaLibrary mediaLib = null; // For accessing local artists and songs 
 
        ...
        
        public MainViewModel()         
        {             
            LocalAudio = new ObservableCollection<ArtistModel>();
             
            ...
              
            // Insert a place holder for title text             
            LocalAudio.Add(new ArtistModel() {                  
                Name = "TitlePlaceholder",                  
                ItemHeight = "110",                  
                ItemWidth = "450"              
            });

            ...         
        }
          
        ...
         
        public void LoadData()
        {
            mediaLib = new MediaLibrary();
            int totalTrackCount = 0;
            int totalArtistCount = 0;

            foreach (Artist a in mediaLib.Artists)
            {
                if (a.Songs.Count <= 0) continue; // Skip artists without tracks
                string artist = a.Name;
                int trackCount = a.Songs.Count;
                int playCount = 0;

                // Check the play count of artist's tracks
                foreach (Song s in a.Songs)
                {
                    playCount += s.PlayCount;
                }

                // Insert artist before less played artists...
                bool artistAdded = false;
                for (int i = 1; i < LocalAudio.Count; i++) // Index 0 reserved for title item
                {
                    if (Convert.ToInt16(LocalAudio[i].PlayCount) < playCount)
                    {
                        this.LocalAudio.Insert(i, new ArtistModel()
                        {
                            Name = artist,
                            LocalTrackCount = Convert.ToString(trackCount),
                            PlayCount = Convert.ToString(playCount)
                        });
                        artistAdded = true;
                        break;
                    }
                }

                // ...Or add artist to the end of the list if it's least played
                if (artistAdded == false)
                {
                    this.LocalAudio.Add(new ArtistModel()
                    {
                        Name = artist,
                        LocalTrackCount = Convert.ToString(trackCount),
                        PlayCount = Convert.ToString(playCount)
                    });
                }

                totalTrackCount += trackCount;
                totalArtistCount++;
            }

            // Continue with only the top 20 favourite artists
            int removeIndex = App.ViewModel.LocalAudio.Count - 1;
            while (removeIndex > 20)
            {
                App.ViewModel.LocalAudio.RemoveAt(removeIndex);
                removeIndex--;
            }

            // Divide local artists into two "size categories"
            foreach (ArtistModel m in App.ViewModel.LocalAudio)
            {
                if (m.Name.Contains("TitlePlaceholder")) continue;
                if (Convert.ToInt16(m.LocalTrackCount) > (totalTrackCount / totalArtistCount))
                {
                    m.ItemHeight = "205";
                    m.ItemWidth = "205";
                }
                else
                {
                    m.ItemHeight = "102";
                    m.ItemWidth = "205";
                }
            }

            if (LocalAudio.Count <= 1) // There's always the favourites title
            {
                NoFavouritesVisibility = Visibility.Visible;
            }
            else
            {
                NoFavouritesVisibility = Visibility.Collapsed;
            }

            this.IsDataLoaded = true;
        }
     
        ...     
    } 
}

…and to show the list of favourites on MainPage, the MainPage.xaml needs the following:

<phone:PhoneApplicationPage x:Class="MusicExplorer.MainPage"     
    ...>

    ...
      
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">

        <!--Panorama control-->
        <phone:Panorama SelectionChanged="Panorama_SelectionChanged">
  
            ...              

            <!--Favourites Item-->
            <phone:PanoramaItem Margin="0,0,0,30">
                <Grid>
                    <TextBlock Margin="12,68,0,0" FontSize="24" TextWrapping="Wrap"
                               Text="No local songs available for creating favourites list. Favourites list shows 20 artists with the most played songs."
                               HorizontalAlignment="Center" Visibility="{Binding NoFavouritesVisibility}"></TextBlock>

                    <ListBox Margin="0,-38,-22,0" x:Name="LocalAudioList" ItemsSource="{Binding LocalAudio}" SelectionChanged="OnFavoriteSelectionChanged" IsHitTestVisible="False">
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <toolkit:WrapPanel/>
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>

                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <controls:FlipableItem Height="{Binding ItemHeight}"
                                                       Width="{Binding ItemWidth}"
                                                       ItemWidth="{Binding ItemWidth}"
                                                       FrontPrimaryText="{Binding Name}"
                                                       FrontSecondaryText="{Binding LocalTrackCount}"
                                                       BackImage="{Binding ThumbUri}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </Grid>
            </phone:PanoramaItem>
              
            ...
          
        </phone:Panorama>              
    </Grid>
    
    ...
  
</phone:PhoneApplicationPage>

Downloads

This example application is hosted in GitHub, where you can check the latest activities, report issues, browse source, ask questions or even contribute to the project yourself.

Contribute to this article

Want to edit or suggest changes to this content? You can edit and submit changes to this article using GitHub.