Frage

I'm a Rails developer working on my first iPhone app. When a button is pressed, I want to play a series of audio commands (.m4a files) with a varying amount of space between each command.

I was able to set up AVAudio player to play a single audio file with the following code:

ViewController.h

- (void)viewDidLoad

{
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"get_in_shower" ofType:@"m4a"]];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[player setNumberOfLoops:0];
[player prepareToPlay];

}

-(IBAction)play:(id)sender {
[player play];
}

Now I'd like to set it to loop through an array of dicts that contains the audio file name as well as the length of time to pause before the next file is played. Something like this:

pseudocode

directions = [{"file":"first", "delay":30},  {"file":"second", delay:15}]
def play(directions) {
  for (direction in directions) {
play directions["file"]
NSTimer length["delay"]
}

My question is how do I accomplish this with AVAudioPlayer. I've also read the documentation for NSTimer but am having trouble using it with AVAudioPlayer.

Thanks in advance!

War es hilfreich?

Lösung

I think that NSTimer isn’t a very good fit for what you want to achieve. What you describe is an edit list of audio clips, and what you are attempting to build using arrays and dictionaries already exists as first class API:

AVComposition and its mutable counterpart.

Because these classes inherit AVAsset, you can play instances of them using an AVPlayer. And even though AVPlayer does not have looping built in, you can use its subclass AVQueuePlayer to achieve looping by periodically checking, whether the player’s currentItem is identical to the last object in its items, and then just inserting a mutableCopy of it at the end. (It has to be a mutable copy, because for immutable classes, copy usually returns the instance itself, thus the test for identity would always evaluate to true.)

Since you don’t want to re–enqueue the last item while the player isn’t playing, you can schedule a block with the player itself. This frees you from keeping track of player state for scheduling/unscheduling timers.

So all that’s really left is

  1. Create an AVMutableComposition
  2. One by one, insert your sound clips followed by an appropriate empty time range for the pause
  3. Create an AVQueuePlayer that automatically plays the next item when its current item end
  4. Schedule a periodic block with that player in which you enqueue a mutable copy of your composition, if its currentItem is its last item.

When in doubt consult the AVFoundation Programming Guide

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top