Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop setting up several AVAudioPlayers with playAtTime() in a for loop

When selecting a row the following code sets up a set of AVAudioPlayers to playback at a certain date (in this case, 50 players playing in the interval of 1 second). Since I want the whole process to restart when touching again I need to break the setup in the for loop since it takes a few seconds to setup the players.

Apart from that, each player is being removed after finishing playback using the audioDidFinishPlaying delegate method of AVAudioPlayerDelegate. I did not include this in the code since it is not relevant to the question.

I've tried using a flag inside the for loop to check whether setup is allowed but that doesn't work.

var players: [AVAudioPlayer] = []
var loadError: NSError?

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

  // Removes the players that have been setup already.
  players.removeAll()

  // The for loop from the previous row selection should be stopped here.
  for i in 0..<50 {
    do {
      let player = try AVAudioPlayer(contentsOfURL: soundUrls[i])
      players += [player]

      // The process of setting these up takes a few seconds, I need to break it.
      print("Firing timer")   
      player.playAtTime(player.deviceCurrentTime + NSTimeInterval(i))

    } catch let error as NSError {
      loadError = error
    }
  }
}

What happens is, that the setup triggered by the previous row selection will continue until it is finished and only then the new for loop starts. I need to break it earlier.

I can't figure out how to tackle this. Maybe by removing the processes from the main thread(How?)? Any help much appreciated!

like image 394
nontomatic Avatar asked Oct 04 '16 09:10

nontomatic


1 Answers

I'm a little bit confused about your statement of the problem, but I'll try to give a suggestion anyway. You say that you set up the players when selecting a row, but the code to set them up is in cellForRowAtIndexPath. So it's set up and playing starts when a cell is returned and displayed in your table view.

What exactly are you trying to achieve? You have a table view with a number of rows, and whenever you tap on a cell the fifty sounds have to start playing one after the other (1 second apart). If you tap the same cell again they should stop and restart, is that it?

Then what I would do is set up the 50 players in viewDidLoad of your TableViewController. Use prepareToPlay(). Start them when needed.

Then if you need to restart them, just cycle through them, check if they are still playing using isPlaying. Pause them if needed, set the current time to 0 and call playAtTime again. Don't remove the players in audioDidFinishPlaying. Because then you'd have to recreate them. Just reset them so they're available for immediate playback again.

By the way, if you're going to do more with audio and want more control and better performance I highly recommend the excellent frameworks The Amazing Audio Engine 2, or AudioKit

like image 192
FilipD Avatar answered Nov 14 '22 22:11

FilipD