Anwill
Anwill

Reputation: 80

Looping through music

I have an app that I want to cycle through music. Basically play 15 secs of a song then move on to the next one.

I have a struct (MusicLibrary) that holds an array of song information (a struct called SongItem) including the persistentID of the songs on the iPhone. This struct is working perfectly and if I just print out the names of the songs it works. (Structs at the bottom of this post)

I then have a function (playTheSong) that uses the persistentID i have stored in the songs object with the MPMusicPlayerController - part of the MediaPlayer library.

What happens is the when the button is pressed the first song starts to play. ALL the song persistentIDs are printed to the debugger output and I am not sure why. After 15 seconds the first song stops - I added this timer in an attempt to then move onto the next song, but anything I do here doesn't work. I think it is because the loop through the song structs is executing immediately and that is my problem.

I know I am doing something really silly here, but can't put my finger on it.

Note: This will only work on a phone as the simulator doesn't have a music library.

This is my ViewController.

import UIKit
import MediaPlayer

class RunningMusicViewController: UIViewController {
    var myMusic = MusicLibrary()

    let myMusicPlayer = MPMusicPlayerController()

    var timer: Int = 15
    var clock = NSTimer()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func startMusicButton(sender: AnyObject) {

        // Get first song of our quiz and play it - Use the persistent ID.
        let songs = myMusic.getSongs()
        let totalSongs = songs.count

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

        for index in 0..<totalSongs {

            playTheSong(songs, index: index)


        }

    }


    func playTheSong(songsInQuiz: [SongItem], index:Int) {
        let songToPlay: SongItem = songsInQuiz[index]
        print("Song ID=" + String(songToPlay.persistentID))
        let predicate = MPMediaPropertyPredicate(value: Int(songToPlay.persistentID), forProperty: MPMediaItemPropertyPersistentID)
        let songQuery = MPMediaQuery()
        songQuery.addFilterPredicate(predicate)
        myMusicPlayer.setQueueWithItemCollection(songQuery.collections![0])
        myMusicPlayer.play()
    }

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

    }

}

This is the 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 the SongItem Struct

import Foundation
import MediaPlayer

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
    }

}   

Upvotes: 0

Views: 99

Answers (1)

Valentin
Valentin

Reputation: 11792

I would change the view controller to something along these lines:

import UIKit
import MediaPlayer

class RunningMusicViewController: UIViewController {
    var index = 0
    var timer: NSTimer

    let myMusic = MusicLibrary()
    let myMusicPlayer = MPMusicPlayerController()
    let numSecondsToPlay = 15.0
    let songs = myMusic.getSongs()

    @IBAction func startMusicButton(sender: AnyObject) {
        playTheSong(index: 0)
        timer = NSTimer.scheduledTimerWithTimeInterval(numSecondsToPlay, target: self, selector: "playNextSong", userInfo: nil, repeats: true)
    }


    func playTheSong(index: Int) {
        let songToPlay: SongItem = songs[index]
        print("Song ID=" + String(songToPlay.persistentID))
        let predicate = MPMediaPropertyPredicate(value: Int(songToPlay.persistentID), forProperty: MPMediaItemPropertyPersistentID)
        let songQuery = MPMediaQuery()
        songQuery.addFilterPredicate(predicate)
        myMusicPlayer.setQueueWithItemCollection(songQuery.collections![0])
        myMusicPlayer.play()
    }

    func playNextSong() {
        myMusicPlayer.stop()
        if index < songs.count {
            playTheSong(index: index)
            index += 1
        }
        else {
            timer.invalidate()
        }
    }
}

Upvotes: 1

Related Questions