-->

Playing multiple sounds at once?

2020-07-20 05:17发布

问题:

I have 6 sounds on one view.

However I want it so that I can play more than one at once, So you tap sound 1 (sound 1 is playing) then sound 2 plays. while sound 1 is still playing.

But at the moment I press sound 1 (sound 1 plays), press sound 2 (sound 2 plays, but sound 1 stops)

Here is the code for the audio part.

- (IBAction)oneSound:(id)sender; {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"wav"];
    if (theAudio) [theAudio release];
    theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
    theAudio.delegate = self;
    [theAudio play];   
    volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(updateVolume) userInfo:nil repeats:YES];
}

- (IBAction)twoSound:(id)sender; {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"2" ofType:@"wav"];
    if (theAudio) [theAudio release];
    theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
    theAudio.delegate = self;
    [theAudio play];   
    volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(updateVolume) userInfo:nil repeats:YES];
}

回答1:

There is some important code missing, but it looks as if theAudio is a global you are using to manage the playing of your sounds. Since you destroy it whenever a sound is played whatever is currently playing will stop in preparation for the next sound.

There are several ways to fix this, one being that each sound gets its own unique AVAudioPlayer instance.



回答2:

don't release the player just because it exists. release when finished playing

You should implement this in the app delegate or a property of the app delegate so that the delegate reference remains valid if you pop the view.

You should not need to do this for each voice. Each voice will initial the player with a different filename or URL. You gain this by making sure that you will release when finished playing. The other thing to take care of is releasing players if the player doesn't finish because of an interruption.

#pragma mark -
#pragma mark Audio methods

-(void)playNote:(NSInteger)noteNumber {

    NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%i", noteNumber ]
                                    ofType: @"caf"];

    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

    AVAudioPlayer *playerToPrepare = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
                                                                            error:nil];

    [fileURL release];

    [playerToPrepare prepareToPlay];
    [playerToPrepare setDelegate: self];

    [playerToPrepare play];

}

#pragma mark -
#pragma mark AVAudioPlayer delegate methods

- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) playerThatFinished
                        successfully: (BOOL) completed {
    if (completed) {
        [playerThatFinished release];
    }
}


回答3:

You can declare and use:

AVAudioPlayer *theAudio1;    // for file 1.wav
AVAudioPlayer *theAudio2;    // for file 2.wav
...
AVAudioPlayer *theAudio6;    // etc.

instead of releasing and reusing just one AVAudioPlayer.