views:

363

answers:

3

Hi

I am using multiple instances of AVAudioPlayer to play multiple audio files simultaneously. I run a loop to start playing the audio files (prepareToPlay is called beforehand and the loop only makes a call to the play method)

But invariably, one of the players does not play in sync. How can I ensure that all the 4 players start playing audio simultaneously?

Thanks.

A: 

Try to set same currentTime property value for every AVAudioPlayer object.

Harri Siirak
The currentTime for all is set to 0.
lostInTransit
+1  A: 

Unfortunately, you can't. AVAudioPlayer doesn't provide any mechanism for fine-grained control of start time. The currentTime property sets the point in the file to read from, it doesn't guarantee when the AVAudioPlayer instance will start playing in system time, which is what you need to sync multiple audio streams.

When I need this behavior, I use the RemoteIO Audio Unit + the 3D Mixer Audio Unit + ExtAudioFile.

Art Gillespie
I also want to provide an option for seeking. Can you point me to some samples which would explain the use of 3D Mixer? And wouldn't it create a lag before starting to play while the audio files are being mixed?
lostInTransit
Here's Apple's sample code for the mixer AU:http://developer.apple.com/iphone/library/samplecode/iPhoneMultichannelMixerTest/index.html
Art Gillespie
As for lag/latency, the mixer doesn't introduce any additional latency. If the current session's buffer size is 128 samples, for example, you'll hear audio about 3ms after you start feeding it to the mixer's callback, just as you would if you fed it straight to the RemoteIO's callback.
Art Gillespie
A: 

This code segment of mine allows you to do this as long as you don't have to do it instantly. You can pass in the targetTime as a timestamp for when you want to hear the sounds. The trick is to make use of time-stamps and the delay functionality of NSObject. Also, it utilizes the fact that it takes way less time to change the volume of the player than it does to change the current time. Should work almost perfectly precisely.

  • (void) moveTrackPlayerTo:(double) timeInSong atTime:(double) targetTime { [trackPlayer play]; trackPlayer.volume = 0;

    double timeOrig = CFAbsoluteTimeGetCurrent(); double delay = targetTime - CFAbsoluteTimeGetCurrent(); [self performSelector:@selector(volumeTo:) withObject:[NSNumber numberWithFloat:single.GLTrackVolume] afterDelay:delay]; trackPlayer.currentTime = timeInSong - delay - (CFAbsoluteTimeGetCurrent() - timeOrig); }

  • (void) volumeTo:(NSNumber *) volNumb { trackPlayer.volume = [volNumb floatValue]; }

Tyler Sheaffer