I'm trying to figure out how exception handling works in Objective-C. So I'm forcing an exception by performing a selector (boom) which does not exist. When I run it, the application crushes, the exception is not handled properly. Can somebody show me the proper way of handling exceptions in objective-c?
#try{
[self performSelector:#selector(boom)];
}
#catch (NSException *ex) {
NSLog(#"Error");
}
... And can somebody also show me how to handle exception for the code below. I'm using one instance variable for four different sound effects. After playing, I set the variable to nil. For some reason, the code below crushes the app at times, so I will like to handle that exception. Thanks.
- (void) playSound:(NSUInteger) number withDelay:(NSTimeInterval) delay
{
if(sound == nil)
{
NSURL* url;
switch (number)
{
case 1: url = [[NSBundle mainBundle] URLForResource:#"Shuffle" withExtension:#"caf"]; break;
case 3: url = [[NSBundle mainBundle] URLForResource:#"Clap" withExtension:#"caf"]; break;
case 4: url = [[NSBundle mainBundle] URLForResource:#"Glass" withExtension:#"caf"]; break;
case 5: url = [[NSBundle mainBundle] URLForResource:#"Knock" withExtension:#"caf"]; break;
default: break;
}
if (url != nil)
{
sound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[sound setCurrentTime:0];
[sound prepareToPlay];
[sound setVolume:1.0];
[sound performSelector:#selector(play) withObject:nil afterDelay: delay];
}
}
}
Exception Handling will not solve your problem here,
If you call - (void) playSound:(NSUInteger) number withDelay:(NSTimeInterval) delay from button press events. Multiple button presses would lead to this kind of crashes. Because you are using the same AVAudioPlayer variable *sound and that same object is used to play sounds after delays.A call from other button press could be initiating the sound player, while another one tries to play the sound.
If these are short sound clips (less than 30sec), Without using AVAudioPlayer , you better use AudioServicesPlaySystemSound,
You can write a method to delay the start of play, This will let you play multiple sound clips at the same time without any problem.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Shuffle" ofType:#"caf"];
NSURL *url = [NSURL fileURLWithPath:path];
SystemSoundID soundFileObject;
AudioServicesCreateSystemSoundID ((__bridge_retained CFURLRef) url, &soundFileObject);
AudioServicesPlaySystemSound (soundFileObject);
Related
I am having trouble getting my NSString to read my string that I have set. The play action is hooked to a UIButton OnTouchDown if it matters.
- (IBAction)play {
if (audioPlayer.playing == NO) {
urlSong = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
[audioPlayer release];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlSong error:&error];
audioPlayer.numberOfLoops = 0;
//if i set this line to stringSong = #"k"; then comment out the next line everything works fine
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
label.text = stringSong;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if ([stringSong isEqualToString:#"k"]){
label.text = #"audio stopped";
[audioPlayer stop];
}
}
When I run the code on my iPhone Xcode returns
EXC_BAD_ACCESS
on this line
if ([stringSong isEqualToString:#"k"]){
I know this is due to me trying to set the string from the url because when I plainly set my string to 'k' the code executes just fine.
If anybody is wondering the overall point of this, I am trying to have my audio buttons set to stop all other audio when this button is pressed and start the audio assigned to this button which in this case is 'k.mp3'. But if this audio is already playing just to stop playing all audio. Thank you.
You aren't retaining stringSong.
This line:
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
Should be:
stringSong = [[[urlSong lastPathComponent] stringByDeletingPathExtension] retain];
At some point this needs to be released.
I have a very simple app that I have built to test out AVAudioPlayer. I have a 16s aif file that plays just fine on my Mac. Put it in a simple app and ran on my iPhone but no sound. Sending 'play' to the object returns success and audioPlayerDidFinishPlaying comes back with success after 16 seconds. Still no sound. Have checked the sound volume on the iPhone, just fine. Have checked to make sure my AVAudioPlayer object has volume set at 1.0 - it does. Can anybody help?
Here's my code
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"Soothing" ofType:#"aif"];
NSURL *playURL = [NSURL fileURLWithPath:soundPath];
NSError *error;
self.myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:playURL error:&error];
NSLog(#"About to play sound");
self.myAudioPlayer.delegate = self;
[self.myAudioPlayer prepareToPlay];
bool success = [self.myAudioPlayer play];
if (!success) {
NSLog(#"Failed to play file");
} else NSLog(#"Looks like it succeded");
OK - got it figured out. I had not configured the AVAudioSession for my app. Did something very simple as follows (copied from Apple's example code):
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &setCategoryError];
if (setCategoryError)
NSLog(#"Error setting category! %#", setCategoryError);
Sound now plays - plus learned a lot about how to control playback through screen locks, etc., which will be valuable.
Did you check if you get anything from the error?
if(error) {
NSLog( #"%#", [error localizedDescription] );
}
Ive been beating my head up against the all trying to figure out a weird sound issue in my program. I will post the code below. As a brief description I have a function that gets passed a variable and it takes that and decides which category of sound it should play, within that function I have multiple sounds of reach category so I use an arc4random statement then run that through a switch statement. What keeps happening is that it will play two sounds from the case statement instead of just one, most times if I call it twice with my button push the second time it will play the sound from the first time and a new sound, other times it plays the same same over the top of each other but with a slight delay. I put in a breakpoint in the switch and when it double plays it only goes through the switch once which is really confusing. One thing to note is right before this I do play another sound but it uses a separate AVAudioplayer and path variable so that shouldn't be an issue as it never plays the second sound as the other sound I'm playing. I'm only calling the function once when I press the button so I'm not sure why it does this. I have tried putting the *path and *avaudioplayer variables inside the function but it won't play at all. Searching here it seems as though arc deallocs it before it gets a chance to play it. I ended up trying to put it at the top of my .m file as a global variable then just set the actual path and play the sound within the switch. The sound will play but it plays twice.. Hopefully someone can help me out. I tried putting the avaudioplayer definition as a property as well and it does the same thing. Here is my code snippet. And thanks in advance ...
in the .m file
// Just below my synthesize statements
NSString *path;
AVAudioPlayer *theSound
// My code that I call when the button is pressed
[self playVoice:#"buyVoice"];
// The playVoice function
- (void)playVoice:(NSString*)voiceNum;
if ([voiceNum isEqualToString:#"buyVoice"]) // Bought an Item Time for a voice
{
// play coin sound
[self coinSound];
// play random buy phrase and coin sound
int phraseNumber = 0;
phraseNumber = arc4random() %(3);
switch (phraseNumber)
{
case 0:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy1" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 1:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy2" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 2:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy3" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 3:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy4" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
}
}
set this code before u play the Audio sound
This will reset the player to the beginning:
[theSound setCurrentTime:0.0];
[theSound play];
try this
I have a relatively simple app that plays a sound using AVAudioPlayer, like this:
NSURL *file3 = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/ball_bounce.aiff", [[NSBundle mainBundle] resourcePath]]];
player3 = [[AVAudioPlayer alloc] initWithContentsOfURL:file3 error:nil];
[player3 prepareToPlay];
to later be called to play, like this:
[player3 play];
But this sound is called in multiple places (collisions with a bouncing ball), many times. Sometimes, the ball hits two things in quick enough succession where the sound from the first bounce is still playing when the ball collides a second time. This second bounce then does not produce a sound. How can I make it play a sound every time it collides, even if it involves paying a sound that overlaps an already playing sound?
Any help is greatly appreciated.
One way to solve this problem would to be create a new instance of AVAudioPlayer if the previous one is already playing:
if([player3 isPlaying]) {
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[player3 url]];
[newPlayer setDelegate:self];
[newPlayer play];
}
Then, in the delegate method audioPlayerDidFinishPlaying:successfully:, you should send the player the -release message:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if(player != player3) {
[player release];
}
}
This is just the way it has to be, as you do need a new source buffer for each concurrent sound playing. :(
It is an old thread but maybe someone can benefit from this answer. Creating AVAudioPlayer repeatedly can be a burden for the app and can creates lags. In this case you can use SystemSound.
NSString *pathToMySound = [[NSBundle mainBundle] pathForResource:#"yourMusic" ofType:#"mp3"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)([NSURL fileURLWithPath: pathToMySound]), &soundID);
AudioServicesPlaySystemSound(soundID);
Downside of this solution, you can't adjust the volume.
I am creating an application,in my app i am changing images for countdown.I want to play a Tick sound when one second completes(i mean when image changes).I have a 25 second long sound with repeated tick sound and within time interval of 1 second. sometimes it works fine but sometimes it's not.Now how do i sync audio with my timer.any help appreciated thanks.
record with 25 ticks?) why don't you use record with one tick? if the loudness is not your aim, you can play it using AudioServicesCreateSystemSoundID then call AudioServicesPlaySystemSound every second.
I suggest using AudioServicesCreateSystemSoundID with a sound file that is just one tick, which is about 1/16 of a second long or less, and using this in your init:
clickSound = [[self createSoundWithName:#"click"] intValue];
Here is the code to set up the sound:
- (NSNumber*) createSoundWithName: (NSString*) name {
SystemSoundID soundID = -1;
NSString *path =[[NSBundle mainBundle] pathForResource:name ofType:#"caf"];
if (path != nil) {
NSURL *url = [NSURL fileURLWithPath:path];
if (url != nil) {
OSStatus err = AudioServicesCreateSystemSoundID ((CFURLRef) url, &soundID);
if (err) NSLog (#"AudioServicesCreateSystemSoundID error %d", err);
}
}
return [NSNumber numberWithInt:soundID];
}
And here is where you play the click:
- (void) playClick {
AudioServicesPlaySystemSound (clickSound);
}