-
Notifications
You must be signed in to change notification settings - Fork 24
Home
Note: The primary documentation covering this example application is located in Lumia Developer's Library.
Music Explorer is an example application demonstrating the use of Nokia Music API together with standard Windows Phone 8 audio features to create an immersive music experience. It shows how to take advantage of Nokia Music API features such as searching for artists by name, requesting top artists and new releases, and it also shows how to launch Nokia Music application from within another application to play mix radio or show artist and product information.
Besides utilizing Nokia Music 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.
Music Explorer is compatible with Nokia Lumia Windows Phone 8 devices.
Download the XAP file and install it on your device by using the Application Deployment tool that comes with the Windows Phone 8 SDK.
Download the application solution source code and open the MusicExplorer.sln
file in the Microsoft Visual Studio Express for Windows Phone 8. Follow the instructions in README.md to install required libraries with NuGet Package Manager. Start building and running the application by hitting F5 or selecting Start Debugging from the Debug menu.
The application is visually attractive example demonstrating how to take advantage of the rich Nokia Music API in Windows Phone applications running in Nokia Lumia devices. With Nokia Music API it is possible to request information on artist by name, such as tracks, albums, and singles available for download via Nokia Music. 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 Nokia Music 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 Nokia Music 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 Nokia Music service. Genres and mixes show corresponding lists of available genres and mixes in Nokia Music 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.
Nokia Music API can also be used to launch Nokia Music app from the context of a different application. Nokia Music app can be launched for example to artist or product view or it can be launched directly to play a selected radio mix. A note symbol is shown whenever interaction with specific item takes the user into Nokia Music (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 Nokia Music service for a certain artist. It is impossible to buy products using Nokia Music API and interaction with a product takes user to Nokia Music application where the product can be bought. While in artist pivot, it is also possible to launch artist mix in Nokia Music or to listen to local tracks stored in the device. Below are screenshots of the artist pivot.
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 its 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 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.
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 Nokia Music 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.
Nokia Music 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 Nokia Music service. The API is also used to launch Nokia Music application into various states (artist, product, mix) directly from Music Explorer.
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
.
In order to use Nokia Music API, application must have an unique app ID and app token (unless using launchers only). These can be obtained by visiting API registration page and requesting credentials for Nokia Music API. WP8 application must also add reference to the actual Nokia Music API client, which in turn requires a reference to JSON.Net library to be added to the application. Instructions to add the references to the solution can be found from README.md in the project source.
Before making any requests to Nokia Music API, Music Explorer checks for Nokia Music availability in current location, resolved using Windows Phone Location API . By default, Nokia Music 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 on the top of this wiki page, 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 Nokia Music API.
using Nokia.Music.Phone;
...
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,
MusicApi.MUSIC_EXPLORER_APP_TOKEN);
}
resolver.CheckAvailability((Response<bool> response) =>
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (response.Result)
{
// Make initial requests to fill models.
App.MusicApi.Initialize(twoLetterCountryCode);
...
}
else
{
MessageBox.Show("Sorry, Nokia Music is not available in this locale.");
}
});
},
twoLetterCountryCode.ToLower());
}
}
}
In Music Explorer application the communication with Nokia Music API, with the exception of CountryResolver
usage described above, is encapsulated into MusicApi
class for easy reference. All requests to Nokia Music service are made using MusicClient
class, and therefore the next step after confirming Nokia Music availability is creating MusicClient
in Initialize
method of MusicApi
.
using Nokia.Music.Phone;
using Nokia.Music.Phone.Tasks;
using Nokia.Music.Phone.Types;
...
namespace MusicExplorer
{
...
public class MusicApi
{
// Constants
public const string MUSIC_EXPLORER_APP_ID = "music_explorer_private_app_id"; // real app id not shown here
public const string MUSIC_EXPLORER_APP_TOKEN = "music_explorer_private_app_token"; // real app token not shown here
// Members
private MusicClient client = null;
private bool initialized = false;
...
public void Initialize(string countryCode)
{
// Create a music client with correct AppId and Token/AppCode
if (countryCode ### null || countryCode.Length != 2)
{
client = new MusicClient(MUSIC_EXPLORER_APP_ID,
MUSIC_EXPLORER_APP_TOKEN);
}
else
{
client = new MusicClient(MUSIC_EXPLORER_APP_ID,
MUSIC_EXPLORER_APP_TOKEN,
countryCode.ToLower());
}
initialized = true;
}
...
}
}
Requests to Nokia Music service can be sent after creating a localized MusicClient
instance. For example the GetTopArtists
method of MusicApi
requests 10 most popular artists of Nokia Music service (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 in the wiki. 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;
}
client.GetTopArtists((ListResponse<Artist> response) =>
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Use results
if (response != null && response.Result != null && response.Result.Count > 0)
{
App.ViewModel.TopArtists.Clear();
foreach (Artist a in response.Result)
{
if (a.Thumb100Uri != null)
{
App.ViewModel.TopArtists.Add(new ArtistModel()
{
Name = a.Name,
Country = CountryCodes.CountryNameFromTwoLetter(a.Country),
Genres = a.Genres[0].Name,
ThumbUri = a.Thumb100Uri,
Id = a.Id
});
}
else
{
App.ViewModel.TopArtists.Add(new ArtistModel()
{
Name = a.Name,
Country = CountryCodes.CountryNameFromTwoLetter(a.Country),
Genres = a.Genres[0].Name,
ThumbUri = new Uri("/Assets/thumb_100_placeholder.png",
UriKind.Relative),
Id = a.Id
});
}
}
}
if (response != null && response.Error != null)
{
ShowNokiaMusicApiError();
}
HideProgressIndicator("GetTopArtists()");
});
});
ShowProgressIndicator("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>
<phone:LongListSelector x:Name="TopArtistsList" Margin="0,-38,-22,2"
ItemsSource="{Binding TopArtists}"
SelectionChanged="OnTopArtistsSelectionChanged"
toolkit:TiltEffect.IsTiltEnabled="True">
<phone:LongListSelector.ListHeaderTemplate>
<DataTemplate>
<Grid Margin="12,0,0,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="who's hot"
Style="{StaticResource PanoramaItemHeaderTextStyle}"
FontSize="65"
Grid.Row="0"/>
</Grid>
</DataTemplate>
</phone:LongListSelector.ListHeaderTemplate>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="12,2,0,4" Height="105" Width="432">
<Image Width="100" Height="100" Source="{Binding ThumbUri}"/>
<StackPanel Width="311" Margin="8,-7,0,0">
<TextBlock Text="{Binding Name}" Margin="10,0"
Style="{StaticResource PhoneTextExtraLargeStyle}"
FontSize="{StaticResource PhoneFontSizeLarge}" />
<TextBlock Text="{Binding Country}" Margin="10,-2,10,0"
Style="{StaticResource PhoneTextSubtleStyle}" />
<TextBlock Text="{Binding Genres}" Margin="10,-2,10,0"
Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
...
</phone:Panorama>
</Grid>
...
</phone:PhoneApplicationPage>
Following methods from MusicApi
show how simple it is to launch Nokia Music application into mix, product, and artist states using Nokia Music API:
using Nokia.Music.Phone;
using Nokia.Music.Phone.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();
}
...
}
}
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 = "MusicExplorerTitlePlaceholder",
ItemHeight = "110",
ItemWidth = "400"
});
}
...
public void LoadData()
{
mediaLib = new MediaLibrary();
...
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)
});
}
...
}
// 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 ### "MusicExplorerTitlePlaceholder") continue;
if (Convert.ToInt16(m.LocalTrackCount) > (totalTrackCount / totalArtistCount))
{
m.ItemHeight = "200";
m.ItemWidth = "206";
}
else
{
m.ItemHeight = "100";
m.ItemWidth = "206";
}
}
...
}
...
}
}
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>
<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,2" x:Name="LocalAudioList" ItemsSource="{Binding LocalAudio}" SelectionChanged="OnFavoriteSelectionChanged">
<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>
See the article Nokia Music API for more in-depth information on the use of Nokia Music API.