Question

I am creating a iPhone game for iOS 7. I have a class called sharedResources that contains copies of certain data that are used over and over again in the game including a sound effect that is like 4 seconds long.

So I am creating the sound effect like this:

    filePathTD = [[NSBundle mainBundle]
                 pathForResource:@"towerDamage" ofType:@"aiff"];
    fileURLTD = [NSURL fileURLWithPath:filePathTD];

    towerDamge = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURLTD
                                                    error:&error];
    if (error)
        NSLog(@"Error: %@", [error localizedDescription]);

Then calling it somewhere else like this:

[towerDamage play];

My problem is the sound effect is long compared to how fast I want to call it. So when I call it while it is already playing it does not play simultaneously since it is already in use and I only have one copy.

So I ask: what would be the best way to play a sound effect more than once at the same time without using too much memory?

I am aware I can make multiple copies but if I make a copy for every character that needs it I might have 30 copies when I might only need 5 max. What I am thinking of is to only make like 5 copies and only use the ones that aren't currently in use. BUT since I am new to iOS development I am unsure if there is a better way to accomplish this task besides this hack?

Was it helpful?

Solution

Using prepareToPlay on the AVAudioPlayer instance will preload the sound file. Maybe you could load some reasonable number of them into an array and then cycle through them as needed. If you needed more than the number allocated then you choose at that time to load a new one into memory, or start the first one in the list playing again. A more complicated system could store up more or less sounds in the array based on factors or what's happening in the app.

Maybe something like this? (I've left out error checks and what not for the sake of brevity)

  //setup the managing class to be
//<AVAudioPlayerDelegate>

///--- instance variables or properties
int nextIndexToPlayInArrayOfSounds = 0;
NSMutableArray *arrayOfSounds = [NSMutableArray array];
int numberOfSoundsNeeded = 10;


//make a method to setup the sounds
for (int i = 0; i < numberOfSoundsNeeded; i++) {

    AVAudioPlayer *mySound = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"soundNameOnDisk"] withExtension:@"aiff"] error:NULL];
    mySound.delegate = self;
    [arrayOfSounds addObject:mySound];
    [mySound prepareToPlay];


}

//make a method to play a sound
//and then play the next sound in the list, or if past the end of the array, or play the first one
AVAudioPlayer *nextSoundToPlay;

if (numberOfSoundsNeeded > nextIndexToPlayInArrayOfSounds) {
    nextIndexToPlayInArrayOfSounds++;
}else{
    nextIndexToPlayInArrayOfSounds = 0;
}

//obviously I'm skipping error checking and nil pointers, etc
nextSoundToPlay = [arrayOfSounds objectAtIndex:nextIndexToPlayInArrayOfSounds ];
[nextSoundToPlay playAtTime:0];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top