Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Swift: Music intros

Hi

I want to right an app that will take the first 15 seconds of each of my song library and play them in turn (or randomly).

I have created a MusicLibrary struct:

import Foundation
import MediaPlayer

struct MusicLibrary {
    var musicLibrary: [SongItem] = []

    let query = MPMediaQuery.songsQuery()
    var mediaCollection : MPMediaItemCollection {
        return MPMediaItemCollection(items: query.items!)
    }

    mutating func addSongs() {
        for index in 0..<mediaCollection.count {
            let mediaItem = mediaCollection.items[index]
            let songItem = SongItem(
                title: mediaItem.title!,
                album: mediaItem.albumTitle!,
                artist: mediaItem.artist!,
                artwork: mediaItem.artwork!,
                persistentID: mediaItem.persistentID,
                genre: mediaItem.genre!
            )

            musicLibrary.append(songItem)
        }
    }

    func getSong(index: Int)->SongItem {
        return musicLibrary[index]
    }

    func getSongs()->[SongItem] {
        return musicLibrary
    }

}

.. And a SongItem struct

struct SongItem {
    var title: String
    var album: String
    var artist: String
    var artwork: MPMediaItemArtwork
    var persistentID: UInt64
    var genre: String

    init(title: String, album: String, artist: String, artwork: MPMediaItemArtwork, persistentID: UInt64, genre: String) {
        self.title = title
        self.album = album
        self.artist = artist
        self.artwork = artwork
        self.persistentID = persistentID
        self.genre = genre
    }

}

This successfully has all the song info in it and I can play a song from it using the MPMusicPlayerController, using a for loop to go through each song in turn using the PersistentID of the song.

let myMusicPlayer = MPMusicPlayerController()
let songs:[SongItem] = MusicPlayer.getSongs()

for index in 0..<songs.count {
    let songToPlay: SongItem = songs[index]
    let predicate = MPMediaPropertyPredicate(value: Int(songToPlay.persistentID), forProperty: MPMediaItemPropertyPersistentID)
    let songQuery = MPMediaQuery()
    songQuery.addFilterPredicate(predicate)
    myMusicPlayer.setQueueWithItemCollection(songQuery.collections![0]) 
    myMusicPlayer.play()
}

This successfully plays each song in turn, but whenever I try and add a timer to skip to the next song after 15 seconds, nothing happens.

The closest I have got is getting the first song to stop after 15 seconds.

Adding a timer like below

var clock = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "countdown", userInfo: nil, repeats: true)

func countdown() {
        timer--
        countdownLabel.text = String(timer)
        // When the countdown hits zero we should stop the song.
        if timer==0 {
            myMusicPlayer.stop()
            clock.invalidate()
            timer = 15
        }

    }

Anyone got any ideas or point me in the right direction for reading? Any help would be wonderful.

-- A

2 Answers

Interesting project. But I'm puzzled. You say it plays successfully. But you have:

let myMusicPlayer = MPMusicPlayerController()

but then, in the next line, you say:

let songs:[SongItem] = MusicPlayer.getSongs()

Shouldn't it be myMusicPlayer.getSongs()

But even with that change, it still gets an error because MPMuscPlayerController has no getSongs() method.

I'm probably missing something. But I just copied your code into Xcode and these errors popped up.

Hi jcorum,

Thanks for taking some time on this. The MusicLibrary is basically a store for all the information about the music on your phone. You then need to pass the persistent ID of each song to the MPMusicPlayerController which plays the songs.

You could extend the MPMusicPlayerController I guess to get the songs, but I did it this way.

Note this doesn't work in the simulator as there is no music in it.