Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to play sound quickly upon fast button presses Xcode?

I have a soundboard it's just a screen with about 8 buttons. each individual button will have its own sound which will be played upon button press There are a couple of ways I could play the sound, such as using SystemSound or AVAudioPlayer system sound so far seems have the quickest response times, avaudioplayer is quite slow, it cant keep up if the user taps on the buttons really fast, I created an audio player for each sound which was quite messy. this is how I'm playing the sounds at the moment the .h file

@interface MainScreenViewController : UIViewController <AVAudioPlayerDelegate, UITabBarControllerDelegate> {
 AVAudioPlayer *player;
 CFURLRef  keNURL;
 SystemSoundID    keNObject;
 //KE LOUD
 CFURLRef  keLURL;
 SystemSoundID    keLObject;
 //GE NORMAL
 CFURLRef  geNURL;
 SystemSoundID    geNObject;
 //GE LOUD
 CFURLRef  geLURL;
 SystemSoundID    geLObject;
 //NA NORMAL
 CFURLRef  naNURL;
 SystemSoundID    naNObject;
 //NA LOUD
 CFURLRef  naLURL;
 SystemSoundID    naLObject;
 //RA
 CFURLRef  raURL;
 SystemSoundID    raObject;
 //DAGGA CLICK
 CFURLRef  daCURL;
 SystemSoundID    daCObject;
 //TILLI CLICK
 CFURLRef  tiCURL;
 SystemSoundID    tiCObject;
}
@property (nonatomic, retain) AVAudioPlayer *player;
@property (readwrite)    CFURLRef        keNURL;
@property (readonly)    SystemSoundID    keNObject;
@property (readwrite)    CFURLRef        keLURL;
@property (readonly)    SystemSoundID    keLObject;
@property (readwrite)    CFURLRef        geNURL;
@property (readonly)    SystemSoundID    geNObject;
@property (readwrite)    CFURLRef        geLURL;
@property (readonly)    SystemSoundID    geLObject;
@property (readwrite)    CFURLRef        naNURL;
@property (readonly)    SystemSoundID    naNObject;
@property (readwrite)    CFURLRef        naLURL;
@property (readonly)    SystemSoundID    naLObject;
@property (readwrite)    CFURLRef        raURL;
@property (readonly)    SystemSoundID    raObject;
@property (readwrite)    CFURLRef        daCURL;
@property (readonly)    SystemSoundID    daCObject;
@property (readwrite)    CFURLRef        tiCURL;
@property (readonly)    SystemSoundID    tiCObject;
}

then the actions that play the individual sounds

then the .m file, after importing the .h file and the right frame works and synthesizing all the variables, write the code for the action and this is what's in the individual actions.

-(IBAction)geSound{
 AudioServicesPlaySystemSound (self.geNObject);
}

I just wanted to know if systemsound is the way forward for me to create a soundboard. thanks especially when the user will tap on the board really fast alternating between beats. . if not what is the best way to play the sound which responds really well?

like image 593
Pavan Avatar asked Jun 27 '10 18:06

Pavan


3 Answers

Speaking from experience, AVAudioPlayer works quite well at playing multiple sounds at the same time or very quickly one after the other. The best way to use it is to just create one method that you feed in an NSString to play some sound with the name held in that NSString... in that way, you will create a new player for each sound file that you play. Be careful about releasing the allocated players though unless you know you are finished with them.

Unless you have very large sound files which might take a short second to buffer (you'll have to figure out for yourself if you can live with any latency or not), I've never had any issues with it being slow. If it's slow, you're probably doing something against Apple's recommendations in regards to decoding certain files (i.e. for multiple sounds at once, Apple recommends the CAF format since it is hardware decoded versus software decoded): http://developer.apple.com/iphone/library/documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html

Update

Here is how I encode my files with a shell script. Put this in a file called batchit.sh in it's own directory. Then place whatever .WAV files you want to encode as a .CAF file in that directory. Open up the Terminal on your Mac, cd to that directory and type sh batchit.sh and let it do it's thing. It will batch convert all the files... Here's the code:

for f in *; do
if  [ "$f" != "batchit.sh" ]
then
    /usr/bin/afconvert -f caff -d ima4 $f 
    echo "$f converted"
fi
done

Notice I didn't do anything in the audioPlayerDidFinishPlaying method which is a delegate method of AVAudioPlayer. You will need to add code to properly release the players after each is finished playing (hey, I can't do all the work for you :) so that all the memory is allocated correctly. Otherwise you will eventually run out if you indefinitely keep creating players without releasing them. Since it seems like you're having a rough day.. see below for a big hint.

That's all the help I can give though. You gotta learn & earn the rest

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {

    // do something here if you want.. you know like maybe release the old players by uncommenting the line below :)

    //[player release];

}
like image 92
iwasrobbed Avatar answered Sep 19 '22 17:09

iwasrobbed


22/03/2014 - Update: Got rid of my overly excited post (which was written a long time ago) and updated to portray a more appropriate answer.

I had to achieve fine control over audio so opted to use OpenAL. WOW is one way to sum it up. As soon as I took it upon myself to use OpenAL which required a bit of extra leg work, getting all the required methods implemented and setting everything up; I found myself with practically no noticeable latency at all. I was absolutely pleased with the excellent results.

I was able to achieve both fine control and no latency at all. I remember jumping in joy at the time when I had it working.

Here are the resources I used that helped ease the endeavor of implementing OpenAL for the first time:

  1. OpenAL on the iPhone
  2. It was because of this link this video tutorial that I was able to create an excellent sound manager singleton. This allowed me to play all the sounds that I needed from any class that I wanted with little sound management, the singleton took care of everything for me.

I humbly suggest everyone to use OpenAL if you require fine control over your audio, and more importantly if you require a low-latency on-demand audio, specially for games when you need to make sure sound is played there and then when you require and expect it to, an audio based application for example.

like image 31
Pavan Avatar answered Sep 19 '22 17:09

Pavan


Just going to add for the benefit of others, even though this is 2 years after the issue.

I've found that if they are short sounds, you would be ok (ish) on your application load. buffering all your tracks by running an instance of prepare to play for every sound (in a for loop) (then releasing - just enough for your processor to remember where the file is)

This takes away the initial loading time next time you come round to it and lets the sounds start more promptly

like image 44
James Morris Avatar answered Sep 21 '22 17:09

James Morris