How to read an iTunes playlist, sample code
All,
Knowing that I'm a poor musician, and yet wanting music in my game, I decided to support playing of iTunes playlists from within the game. Playing music is easy enough, and I'm sure everybody here has their own way ( I'm using QTKit ).
But getting the iTunes playlist info, while easy, is non-obvious. I figured it out, and I'm attaching a Cocoa class for your use, if anybody wants.
First, the header:
Now, the implementation:
Usage is super simple: you just create an iTunesPlaylistReader, ask it for available playlists, and then ask for the URLs of the playlist you want. You can then feed those files to whatever mechanism you've got to play them. Since I'm using QTKit, I can play any audio file quicktime supports, and that appears to support music from the iTunes music store.
One note, the file urls returned by musicURLSForPlaylist: are strings in the form of "file://localhost/path/to/file". You've got to transform that into a local file path.
Here's my MusicPlayer's way:
And, here's a shot of it in my game config:
Anyway, I hope somebody finds it useful.
Knowing that I'm a poor musician, and yet wanting music in my game, I decided to support playing of iTunes playlists from within the game. Playing music is easy enough, and I'm sure everybody here has their own way ( I'm using QTKit ).
But getting the iTunes playlist info, while easy, is non-obvious. I figured it out, and I'm attaching a Cocoa class for your use, if anybody wants.
First, the header:
Code:
//
// iTunesPlaylistReader.h
// AudioPlayer
//
// Created by Shamyl Zakariya on 8/31/05.
// Copyright 2005 Shamyl Zakariya. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface iTunesPlaylistReader : NSObject {
NSDictionary *_iTunesData;
}
/**
@return an autoreleased array of the playlists in your
iTunes library. It's just the names of the playlists.
*/
-(NSArray *) playlists;
/**
@return an autoreleased array of NSDictionaries which represent each track
in the passed in playlist. Each dictionary is the track dict
in the itunes XML, meaning it can be represented as such:
@begincode
<dict>
<key>Track ID</key><integer>36</integer>
<key>Name</key><string>The Stars of Track and Field</string>
<key>Artist</key><string>Belle & Sebastian</string>
<key>Album</key><string>If You're Feeling Sinister</string>
<key>Genre</key><string>Rock/Pop</string>
<key>Kind</key><string>MPEG audio file</string>
<key>Size</key><integer>4621294</integer>
<key>Total Time</key><integer>288182</integer>
<key>Track Number</key><integer>1</integer>
<key>Date Modified</key><date>2004-06-21T11:20:55Z</date>
<key>Date Added</key><date>2004-07-30T01:47:28Z</date>
<key>Bit Rate</key><integer>128</integer>
<key>Sample Rate</key><integer>44100</integer>
<key>Play Count</key><integer>1</integer>
<key>Play Date</key><integer>-1119524786</integer>
<key>Play Date UTC</key><date>2004-08-15T23:21:50Z</date>
<key>Artwork Count</key><integer>1</integer>
<key>Track Type</key><string>File</string>
<key>Location</key><string>file://localhost/Users/zakariya/Music/iTunes/iTunes%20Music/Belle%20&%20Sebastian/If%20You're%20Feeling%20Sinister/01%20The%20Stars%20of%20Track%20and%20Field.mp3</string>
<key>File Folder Count</key><integer>4</integer>
<key>Library Folder Count</key><integer>1</integer>
</dict>
@endcode
*/
- (NSArray *) tracksForPlaylist: (NSString *) playlist;
/**
@returns an autoreleased array of the URLS to the music files
in a given playlist. The URLS are actually NSStrings, in url syntax,
like "file://localhost/..."
They can easily be fed to NSURL and have the local path extracted.
*/
- (NSArray *) musicURLSForPlaylist: (NSString *) playlist;
@endNow, the implementation:
Code:
//
// iTunesPlaylistReader.m
// AudioPlayer
//
// Created by Shamyl Zakariya on 8/31/05.
// Copyright 2005 Shamyl Zakariya. All rights reserved.
//
#import "iTunesPlaylistReader.h"
@implementation iTunesPlaylistReader
- (id) init {
if ( (self = [super init]) )
{
NSString *home = NSHomeDirectory();
NSString *iTunesXMLPath = [home stringByAppendingPathComponent: @"Music/iTunes/iTunes Music Library.xml"];
_iTunesData = [[NSDictionary alloc] initWithContentsOfFile: iTunesXMLPath];
return self;
}
return nil;
}
-(NSArray *) playlists
{
NSArray *ignore = [NSArray arrayWithObjects: @"Library", @"Podcasts", @"Purchased Music", nil];
/*
The playlists entry is an array
*/
NSArray *playlistsArray = (NSArray *)[_iTunesData objectForKey: @"Playlists"];
NSMutableArray *playlistNames = [NSMutableArray array];
int i, nPlaylists = [playlistsArray count];
for ( i = 0; i < nPlaylists; i++ )
{
NSDictionary *playlistEntry = [playlistsArray objectAtIndex: i];
NSString *playlistName = [playlistEntry objectForKey: @"Name"];
if ( [ignore indexOfObject: playlistName] == NSNotFound )
{
[playlistNames addObject: playlistName];
}
}
return playlistNames;
}
- (NSArray *) tracksForPlaylist: (NSString *) playlistName
{
/*
First, grab the playlist entries and build an array of the track ids
*/
NSArray *playlistsArray = (NSArray *)[_iTunesData objectForKey: @"Playlists"];
NSMutableArray *trackIDs = [NSMutableArray array];
int i, nPlaylists = [playlistsArray count];
for ( i = 0; i < nPlaylists; i++ )
{
NSDictionary *playlistEntry = [playlistsArray objectAtIndex: i];
if ( [[playlistEntry objectForKey: @"Name"] isEqualToString: playlistName] )
{
NSArray *playlistItems = [playlistEntry objectForKey: @"Playlist Items"];
/* playlist items is an array of dicts */
NSEnumerator *e = [playlistItems objectEnumerator];
id obj = nil;
while ( (obj = [e nextObject]) )
{
[trackIDs addObject: [obj objectForKey: @"Track ID"]];
}
}
}
/*
Now dig up the track information
*/
NSMutableArray *tracks = [NSMutableArray array];
NSEnumerator *e = [trackIDs objectEnumerator];
id trackKey = nil;
NSDictionary *trackListing = [_iTunesData objectForKey: @"Tracks"];
while( (trackKey = [e nextObject]) )
{
NSObject *track = [trackListing objectForKey: [trackKey stringValue]];
if ( track != nil )
{
[tracks addObject: track];
}
}
return tracks;
}
- (NSArray *) musicURLSForPlaylist: (NSString *) playlist
{
NSArray *tracks = [self tracksForPlaylist: playlist];
NSMutableArray *files = [NSMutableArray array];
NSEnumerator *e = [tracks objectEnumerator];
NSDictionary *track = nil;
while ( (track = [e nextObject]) )
{
[files addObject: [track objectForKey: @"Location"]];
}
return files;
}
@endUsage is super simple: you just create an iTunesPlaylistReader, ask it for available playlists, and then ask for the URLs of the playlist you want. You can then feed those files to whatever mechanism you've got to play them. Since I'm using QTKit, I can play any audio file quicktime supports, and that appears to support music from the iTunes music store.
One note, the file urls returned by musicURLSForPlaylist: are strings in the form of "file://localhost/path/to/file". You've got to transform that into a local file path.
Here's my MusicPlayer's way:
Code:
- (void) playCurrentTrack
{
if ( _movie )
{
[_movie release];
}
NSString *fileURLString = [_urls objectAtIndex: _currentPlayingIndex ];
NSURL *fileURL = [NSURL URLWithString: fileURLString];
NSString *file = [fileURL path];
NSError *error = nil;
_movie = [[QTMovie movieWithFile: file error: &error] retain];
if ( !_movie )
{
if ( error )
{
NSLog( @"MusicPlayer::playCurrentTrack\tUnable to open file %@ error: %@", file, error );
}
else
{
NSLog( @"MusicPlayer::playCurrentTrack\tUnable to open file %@", file );
}
}
else
{
[_movie setVolume: _volume];
[_movie play];
}
}And, here's a shot of it in my game config:
Anyway, I hope somebody finds it useful.
Hey, that's pretty neat. I'm in the same boat as you too -- not a musician but I'd like to add music to my games. Giving the user the option to select an iTunes playlist sounds like a great idea.
Speaking of which, we really need a repository for code bits like this. I have on my web site a C++ class for generic handling of a high scores file that's free for people to use and I know other people have posted code bits and what not that they've written for others to use but without a central location to store all these things, it's hard to know what's out there (especially when you vaguely remember that someone a while back posted something useful that wasn't useful at the time but it is now).
Speaking of which, we really need a repository for code bits like this. I have on my web site a C++ class for generic handling of a high scores file that's free for people to use and I know other people have posted code bits and what not that they've written for others to use but without a central location to store all these things, it's hard to know what's out there (especially when you vaguely remember that someone a while back posted something useful that wasn't useful at the time but it is now).
The brains and fingers behind Malarkey Software (plus caretaker of the world's two brattiest felines).
Yes thanks for the code,
I second that, An iDG code repo would be really useful.
Malarkey on your site I found Bill, he is back!
http://www.somegames.net/flashgames/BillTheDemon.html
I second that, An iDG code repo would be really useful.
Malarkey on your site I found Bill, he is back!
http://www.somegames.net/flashgames/BillTheDemon.html
Sir, e^iπ + 1 = 0, hence God exists; reply!
Ah, I was confused for a second about what you were talking about then I realized I put a link to my del.icio.us bookmarks on my website.
The brains and fingers behind Malarkey Software (plus caretaker of the world's two brattiest felines).
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Sample Code Apple removed? | SaxMan | 12 | 5,705 |
Jan 17, 2009 05:26 PM Last Post: AnotherJake |
|
| FBO sample code posted | arekkusu | 5 | 3,972 |
Sep 20, 2006 09:23 PM Last Post: Frank C. |
|
| PBuffer & Render to Texture (read & write) | habicht | 4 | 3,426 |
Feb 7, 2005 05:33 PM Last Post: habicht |
|
| TextureRange sample | Red Marble Game | 1 | 2,612 |
Dec 9, 2004 12:04 PM Last Post: arekkusu |
|
| Does Anyone have a sample of SDL being implemented without Project Builder? | tingham | 10 | 4,057 |
Oct 7, 2003 11:42 AM Last Post: Fenris |
|

