3

I'm building an iOS app with cocos2d 2, and I'm using SimpleAudioEngine to play some effects.

Is there a way to sequence multiple sounds to be played after the previous sound is complete?

For example in my code:

[[SimpleAudioEngine sharedEngine] playEffect:@"yay.wav"];
[[SimpleAudioEngine sharedEngine] playEffect:@"youDidIt.wav"];

When this code is run, yay.wav and youDidIt.wav play at the exact same time, over each other.

I want yay.wav to play and once complete, youDidIt.wav to play.

If not with SimpleAudioEngine, is there a way with AudioToolbox, or something else?

Thank you!

== UPDATE ==

I think I'm going to go with this method using AVFoundation:

AVPlayerItem *sound1 = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"yay" ofType:@"wav"]]];
AVPlayerItem *sound2 = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"YouDidIt" ofType:@"wav"]]];    
AVQueuePlayer *player = [[AVQueuePlayer alloc] initWithItems: [NSArray arrayWithObjects:sound1, sound2,  nil]];
[player play];
Guru
  • 21,652
  • 10
  • 63
  • 102
Corey
  • 2,453
  • 4
  • 35
  • 63

2 Answers2

0

The easy way would be getting the track duration using -[CDSoundSource durationInSeconds] and then schedule the second effect playing after a proper delay:

[[SimpleAudioEngine sharedEngine] performSelector:@selector(playEffect:) withObject:@"youDidIt.wav" afterDelay:duration];

An easier way to get the audio duration would be patching SimpleAudioManager and add a method that queries its CDSoundEngine (a static global) for the audio duration:

- (float)soundDuration {
    return [_engine bufferDurationInSeconds:_soundId];
}

The second approach would be polling on the status of the audio engine and wait for it to stop playing.

    alGetSourcei(sourceId, AL_SOURCE_STATE, &state);
    if (state == AL_PLAYING) {
      ...

The sourceId is the ALuint returned by playEffect.

sergio
  • 68,819
  • 11
  • 102
  • 123
0

It's simple, tested with Cocos2D 2.1:

  1. Creates a property durationInSeconds on SimpleAudioEngine.h :

    @property (readonly) float durationInSeconds;
    
  2. Synthesize them :

    @synthesize durationInSeconds;
    
  3. Modify playEffect like this :

    -(ALuint) playEffect:(NSString*) filePath pitch:(Float32) pitch pan:(Float32) pan gain:(Float32) gain {
        int soundId = [bufferManager bufferForFile:filePath create:YES];
        if (soundId != kCDNoBuffer) {
            durationInSeconds = [soundEngine bufferDurationInSeconds:soundId];
            return [soundEngine playSound:soundId sourceGroupId:0 pitch:pitch pan:pan gain:gain loop:false];
        } else {
            return CD_MUTE;
        }
    }
    
  4. As you can see, I inserted durationInSeconds value directly from soundEngine bufferDurationInSeconds from the result of bufferManager.

  5. Now, only ask for the value [SimpleAudioEngine sharedEngine].durationInSeconds and you've got the float duration in seconds of this sound.

  6. Put a timer this seconds and after this, play the next iteration of your sound or put the flag OFF or something.

marzapower
  • 5,531
  • 7
  • 38
  • 76