Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Phone

Programming Windows Phone 7 : Pivot and Panorama - The XNA Music Classes: MediaLibrary

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
5/28/2011 3:14:35 PM
An application that wants to play music under Windows Phone 7 uses classes from the Microsoft.Xna.Framework.Media namespace. You’ll first need to access the music from the library, and for that you’ll need a new instance of MediaLibrary, the same class you use to access the photo library.

The MediaLibrary class defines several get-only properties that let you access the music library in several standard ways. These properties include:

  • Albums of type AlbumCollection, a collection of Album objects.

  • Songs of type SongCollection, a collection of Song objects.

  • Artists of type ArtistCollection, a collection of Artist objects.

  • Genres of type GenreCollection, a collection of Genre objects.

Each of these collections contains all the music in your library but arranged in different ways. (The presence of a property called Composer of type ComposerCollection would have simplified my program considerably.)

For my purposes I found the Albums property of MediaLibrary the most useful. The AlbumCollection class is a collection of items of type Album, and Album has the following get-only properties (among others):

  • Name of type string

  • Artist of type Artist

  • Songs of type SongCollection

  • HasArt of type bool

If HasArt is true, you can call two methods, GetAlbumArt and GetThumbnail, both of which return Stream objects to access a bitmap with an image of the album cover. GetAlbumArt returns a bitmap of about 200-pixels square and GetThumbnail returns a bitmap of about 100-pixels square.

The SongCollection in an Album instance contains all the tracks on the album. (In the composer-centric tradition, the use of the word song to describe these album tracks doesn’t make much sense if, for example, a track is actually a movement of a symphony, but the performer-centric prejudice of the XNA classes is something we’re forced to live with.) The Song object has several get-only properties, among them:

  • Name of type string

  • Album of type Album

  • Artist of type Artist

  • Duration of type TimeSpan.

For organizing the music library by composer and for data binding purposes, I realized that I’d need a couple new classes. My AlbumInfo class is basically a wrapper around the XNA Album class:

Example 1. Silverlight Project: MusicByComposer File: AlbumInfo.cs
using System;
using System.Windows.Media.Imaging;
using Microsoft.Xna.Framework.Media;

namespace MusicByComposer
{
public class AlbumInfo : IComparable<AlbumInfo>
{
BitmapImage albumArt;
BitmapImage thumbnailArt;

public AlbumInfo(string shortAlbumName, Album album)
{
this.ShortAlbumName = shortAlbumName;
this.Album = album;
}

public string ShortAlbumName { protected set; get; }

public Album Album { protected set; get; }

public BitmapSource AlbumArt
{
get
{
if (albumArt == null && Album.HasArt)
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(Album.GetAlbumArt());
albumArt = bitmapImage;
}
return albumArt;
}
}

public BitmapSource ThumbnailArt
{
get
{
if (thumbnailArt == null && Album.HasArt)
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(Album.GetThumbnail());
thumbnailArt = bitmapImage;
}
return thumbnailArt;
}
}

public int CompareTo(AlbumInfo albumInfo)
{
return ShortAlbumName.CompareTo(albumInfo.ShortAlbumName);
}
}
}


This AlbumInfo class has a property of type Album and adds three more properties: The ShortAlbumName property is the name of the album with the composer or composers at the beginning stripped off. (For example, “Mahler: Symphony No. 2” becomes “Symphony No. 2”.) This property is used in the CompareTo method at the bottom for sorting purposes. In the first of the two screen shots of MusicByComposer, you’ll notice that the album names are sorted.

The GetAlbumArt and GetThumbnail methods of Album return Stream objects. For binding purposes, I expose two public properties of type BitmapImage but the class only creates these objects when the properties are first accessed, and then caches them for subsequent accesses.

The next class is ComposerInfo, which consists of the composer’s name and a list of all the AlbumInfo objects containing music by that composer:

Example 2. Silverlight Project: MusicByComposer File: ComposerInfo.cs
using System;
using System.Collections.Generic;

namespace MusicByComposer
{
public class ComposerInfo
{
public ComposerInfo(string composer, List<AlbumInfo> albums)
{
Composer = composer;
albums.Sort();
Albums = albums;
}

public string Composer { protected set; get; }

public IList<AlbumInfo> Albums { protected set; get; }
}
}

Notice that the List of AlbumInfo objects is sorted in the constructor.

The MusicPresenter class is responsible for accessing the phone’s music library, obtaining all the albums, analyzing the album titles for the presence of composer names, and creating objects of type ComposerInfo and AlbumInfo. It does the main work in its instance constructor by storing the information in a dictionary with composer names used as keys that reference items of the type List<AlbumInfo>:

Example 3. Silverlight Project: MusicByComposer File: MusicPresenter.cs
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Media;

namespace MusicByComposer
{
public class MusicPresenter
{
// Static constructor
static MusicPresenter()
{
if (Current == null)
Current = new MusicPresenter();
}

// Instance constructor
public MusicPresenter()
{
// Make this class a singleton
if (MusicPresenter.Current != null)
{
this.Composers = MusicPresenter.Current.Composers;
return;
}

MediaLibrary mediaLib = new MediaLibrary();
Dictionary<string, List<AlbumInfo>> albumsByComposer =
new Dictionary<string, List<AlbumInfo>>();

foreach (Album album in mediaLib.Albums)
{
int indexOfColon = album.Name.IndexOf(':');

// Check for pathological cases
if (indexOfColon != -1 &&
// Colon at beginning of album name
(indexOfColon == 0 ||
// Colon at end of album name
indexOfColon == album.Name.Length - 1 ||
// nothing before colon
album.Name.Substring(0, indexOfColon).Trim().Length == 0 ||
// nothing after colon
album.Name.Substring(indexOfColon + 1).Trim().Length == 0))
{

indexOfColon = -1;
}

// Main logic for albums with composers
if (indexOfColon != -1)
{
string[] albumComposers =
album.Name.Substring(0, indexOfColon).Split(',');
string shortAlbumName = album.Name.Substring(indexOfColon
+ 1).Trim();
bool atLeastOneEntry = false;

foreach (string composer in albumComposers)
{
string trimmedComposer = composer.Trim();
if (trimmedComposer.Length > 0)
{
atLeastOneEntry = true;

if (!albumsByComposer.ContainsKey(trimmedComposer))
albumsByComposer.Add(trimmedComposer,
new List<AlbumInfo>());

albumsByComposer[trimmedComposer].Add(
new AlbumInfo(shortAlbumName, album));
}
}

// Another pathological case: Just commas before colon
if (!atLeastOneEntry)
{
indexOfColon = -1;
}
}

// The "Other" category is for albums without composers
if (indexOfColon == -1)
{
if (!albumsByComposer.ContainsKey("Other"))
albumsByComposer.Add("Other", new List<AlbumInfo>());

albumsByComposer["Other"].Add(new AlbumInfo(album.Name, album));
}
}

mediaLib.Dispose();

// Transfer Dictionary keys to List for sorting
List<string> composerList = new List<string>();

foreach (string composer in albumsByComposer.Keys)
composerList.Add(composer);

(composerList as List<string>).Sort();

// Construct Composers property
Composers = new List<ComposerInfo>();

foreach (string composer in composerList)
Composers.Add(new ComposerInfo(composer, albumsByComposer[composer]));

Current = this;
}

public static MusicPresenter Current { protected set; get; }

public IList<ComposerInfo> Composers { private set; get; }
}
}


Only one instance of this class is required by the program. The music library will not change while the program is running, so there’s no reason for this instance constructor to run again. For that reason, when the instance constructor is finished, it sets the static Current property equal to the instance of MusicPresenter being created. This first instance will actually be created from the static constructor at the very top of the class, and result in setting the Composers property (down at the bottom), which consists of a list of ComposerInfo objects. If the constructor is called again, it merely transfers the existing Composers property to the new instance.

Why not make MusicPresenter a static class and simplify it somewhat? Because MusicPresenter is used in data bindings in XAML files and an actual instance of a class is required for those bindings. However, code also needs to access the class and for that the static MusicPresenter.Current property is helpful.

This static constructor executes when the program first accesses the class, of course, but also when the program accesses the class again after it is revived from tombstoning. In this case, re-creating the data from the MediaLibrary is certainly easier than saving it all in isolated storage.

Other -----------------
- Programming Windows Phone 7 : Pivot and Panorama - The XNA Connection
- Programming Windows Phone 7 : Pivot and Panorama - Music by Composer
- Programming Windows Phone 7 : Pivot and Panorama - Compare and Contrast
- Programming Windows Phone 7 : Elements and Properties - Modes of Opacity
- Programming Windows Phone 7 : Elements and Properties - Non-Tiled Tile Brushes & Playing Movies
- Programming Windows Phone 7 : Items Controls - A Card File Metaphor
- Programming Windows Phone 7 : Items Controls - The DataTemplate Bar Chart
- Programming Windows Phone 7 : Items Controls - Changing the Panel
- Programming Windows Phone 7 : Items Controls - Sorting
- Items Controls : Fun with DataTemplates
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us
Popular tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 windows Phone 7 windows Phone 8
programming4us programming4us
 
programming4us
Natural Miscarriage
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Game Trailer