iTunes minus the player: hack your Apple beats
Dodge the shareware sledgehammer
Mac Secrets QTMovie, the principal class inside the QTKit framework, isn't just for playing movies.
A while back, I provided source code for a program that browsed your iTunes library, showing all available albums and songs. You may remember that this worked by using classes inside Apple's undocumented iLifeMediaBrowser framework. One class, ILMediaBrowserAudioPlayer, was used to actually handle the playing of iTunes tracks.
Internally, ILMediaBrowserAudioPlayer is able to play files such as AIFF and MP3 using the QTMovie class. It's a little know aspect of QTMovie that's totally happy with audio files. If you call the movieFileTypes class method, QTMovie will try and convince you that it can only handle movies - but it's lying.
There are a huge number of shareware Mac applications that let you listen to your favourite iTunes tracks without bringing the iTunes player up on screen. But behind the scenes, the vast majority of them use iTunes to play each song, using AppleScript or some other means to communicate with the player application. This is like using a sledgehammer to crack a nut and completely unnecessary.
To create a new instance of QTMovie for playing audio, just allocate and initialise it like this:
QTMovie *_player = [[QTMovie movieWithFile: path error: nil] retain];
I'm assuming here that "path" is a string containing the full path of your audio file. Notice, the all-important retain call: If you don't retain your QTMovie instance, it will stick around long enough for you to configure it and then silently bow out as soon as you try to play the file. Result: silence!
Once you've initialised a QTMovie instance as above, you only need to call the familiar play method to start your audio playing. If you need to know when the track is finished, just listen out for QTMovieDidEndNotification notifications. In the ILMediaBrowserAudioPlayer class referred to earlier, Apple use this mechanism to sequentially play through the tracks in an album when using the iLife Media Browser.
Retrieve artwork and DRM status, along with the album and artist information
The QTMovie class exports a slew of undocumented methods that can be used to provide information on the file currently loaded. Some of these are shown below:
- (NSString *) copyright; - (NSString *) author; - (NSString *) artist; - (NSString *) information; // possibly NSDictionary ? - (NSString *) comments; - (NSString *) album; - (NSString *) genre;
Obviously, not all of these methods are going to return a sensible value. If you've loaded some random sound file, it may not contain any useful metadata at all. But if you're accessing an AIFF or M4P file from iTunes, chances are it contains at least copyright, artist, and album information. Be aware that the above methods are not too friendly. If the info doesn't exist, you will get nil returned rather than an empty string, so be prepared for this when using them.
One of the coolest undocumented QTMovie features is the albumArtworkMovie method. This returns a one-frame movie that corresponds to the album artwork - assuming that there is artwork. Again, this is most likely with tracks that you've ripped using iTunes.
To demonstrate the use of this method in the accompanying demo program at the end, I added a QTMovieView control to the program window. By setting the background fill color of this control to have an opacity of 0.0, it effectively disappears, only appearing when there is some artwork to show. This is accomplished through the following line of code:
// Display snazzy album artwork - if any.... [_movieView setMovie: [_player albumArtworkMovie]];
If there is no artwork, then the albumArtworkMovie method returns nil, which is used as the argument to setMovie: making the control disappear. If you wanted to retrieve an NSImage for the artwork rather than a movie object, you could probably do something like this:
NSImage * artwork = [[_player albumArtworkMovie] currentFrameImage];
Again, nil will be returned if the audio file has no associated artwork.
Perusing the source code, you'll notice I've used another method called isDRMAuthorized. This determines whether the computer is authorised to play the current file. Internally, it calls another method, isDRMProtected, which will tell you whether or not the current file is protected.
Still on the subject of DRM, there are a couple of other interesting methods, canDRMInteractWithUser and setCanDRMInteractWithUser. With user interaction disabled, you'll simply get an error returned if you try to play an unauthorised file.
As ever, the usual caveats apply: This article uses undocumented interfaces, and consequently, if you use them in commercial applications, large hairy warts will grow all over your body and you'll die. Also, this article is intended for Apple Mac developers and won't make any sense to you if you're not a developer! Source code of the demo application can be downloaded from here. ®