سؤال

I am trying to play sounds in a specific order. I managed to do that, but there is tiny delay between the sounds. The sounds recorded in a way they will fits to each other, so the user will not able to notice that the music had changed.

at bottom line, there is a delay between the sounds that I must to avoid..

I don't wont to gather all the sounds to one long sound because I need to start different sounds at different times.

Maybe there is a better way then using AVAudioPlayer ?

Here is my code:

-(id)init {
     self = [super init];
     if (self) {
       gameMusicSounds = @[gamePlaySound1,gamePlaySound2,gamePlaySound3,gamePlaySound4,gamePlaySound5,gamePlaySound6,gamePlaySound7,gamePlaySound8,gamePlaySound9,gamePlaySound10];
     }
     return self;
 }

-(void)gameMusicNew {

     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     currentMusicToPlay = [[defaults objectForKey:CURRENT_GAME_MUSIC] intValue];

     if (currentMusicToPlay >= [gameMusicSounds count]){
         currentMusicToPlay = 0;
     }

     NSString * music = [[NSBundle mainBundle] pathForResource:[gameMusicSounds objectAtIndex:currentMusicToPlay] ofType:@"mp3"];
     self.backgroundMusic = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
     self.backgroundMusic.numberOfLoops = 1;
     self.backgroundMusic.delegate = self;
     [self.backgroundMusic play];

     currentMusicToPlay ++;
     [defaults setObject:[NSString stringWithFormat:@"%i",currentMusicToPlay] forKey:CURRENT_GAME_MUSIC];
     [defaults synchronize];

}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    [self gameMusicNew];
}

----update-----

I want to share with all of you the final code I wrote, since I didn't actually find a lot of stuff on web in this subject.

Basically I have group of sounds I need to play one by another, and when they finished, I need to start all over again. The reason I don't use one long mp3 file, is that sometimes, if a user go back to the app and he is in a middle of a game, I want him to keep from the last music he was listening to.

so here is the code:

 - (id)init {
    self = [super init];
    if (self) {
       gameMusicSounds = @[gamePlaySound1,gamePlaySound2,gamePlaySound3,gamePlaySound4,gamePlaySound5,gamePlaySound6,gamePlaySound7,gamePlaySound8,gamePlaySound9,gamePlaySound10];
    }
    return self;
 }

-(void)gameMusicNew{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString * isGameOver =[defaults objectForKey:IS_GAME_OVER];
    currentMusic = [[defaults objectForKey:CURRENT_GAME_MUSIC] intValue];

    if([isGameOver isEqualToString:@"YES"] || currentMusic >= [gameMusicSounds count]){
         currentMusic = 0;
         [defaults setObject:[NSString stringWithFormat:@"%i",currentMusic] forKey:CURRENT_GAME_MUSIC];
         [defaults synchronize];
    }

    NSMutableArray* songs = [NSMutableArray arrayWithCapacity:[gameMusicSounds count]];

    NSURL* url = [[NSBundle mainBundle] URLForResource:[gameMusicSounds objectAtIndex:currentMusic] withExtension:@"mp3"];
    AVPlayerItem* item = [[AVPlayerItem alloc] initWithURL:url];
    [songs addObject:item];

    self.queue = [AVQueuePlayer queuePlayerWithItems:songs];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(playerItemDidReachEnd:)
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:[self.queue currentItem]];

     [self.queue play];

     [self addNextMusic];
}

-(void)addNextMusic{

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    currentMusic = [[defaults objectForKey:CURRENT_GAME_MUSIC] intValue];

    int nextMusic = currentMusic + 1;
    if(nextMusic >= [gameMusicSounds count]){
        nextMusic = 0;
    }

    NSURL* url = [[NSBundle mainBundle] URLForResource:[gameMusicSounds objectAtIndex:nextMusic] withExtension:@"mp3"];
    AVPlayerItem* item = [[AVPlayerItem alloc] initWithURL:url];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(playerItemDidReachEnd:)
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:item];
    [self.queue insertItem:item afterItem:nil]; 
}

- (void)playerItemDidReachEnd:(NSNotification *)notification {

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    currentMusic = [[defaults objectForKey:CURRENT_GAME_MUSIC] intValue];

    currentMusic++;
    if(currentMusic >= [gameMusicSounds count]){
       currentMusic = 0;
    }

    [defaults setObject:[NSString stringWithFormat:@"%i",currentMusic] forKey:CURRENT_GAME_MUSIC];
    [defaults synchronize];

    [self addNextMusic];
}

-(void)stopGameMusic{
    [self.queue removeAllItems];
}

Hope it will be useful to someone.

هل كانت مفيدة؟

المحلول

You can do this using an AVQueuePlayer. It accepts multiple sounds and just plays them off in order.

To use it, create an array of AVPlayerItem objects (use initWithURL: to create each AVPlayerItem pointing to your sound) and then just add the array and play.

Here is actual code from one of my apps. It does exactly what you describe, and it is as if all the "songs" were one long "song":

NSMutableArray* songs = [NSMutableArray arrayWithCapacity:self.tiles.count];
for (NSString* fnam in self.songsSorted) {
    NSURL* url = [[NSBundle mainBundle] URLForResource:fnam withExtension:@"m4a" subdirectory:@"Songs"];
    AVPlayerItem* item = [[AVPlayerItem alloc] initWithURL:url];
    [songs addObject:item];
}
self.queue = [AVQueuePlayer queuePlayerWithItems:songs];
[self.queue play];
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top