Stop a sound using the same button that plays it - objective-c

Pretty simple, I'm using one button that generates a random number and then with a switch/case, it animates an image and plays a sound. My problem is that when you press the button again, the sound that was playing before doesn't stop and the sound overlaps.
Here's the code:
- (IBAction) pushme: (id) sender{
int random = (arc4random()%10);
switch (random) {
case 0: {
[ANIMATION NUMBER 0]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound0.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
}
break;
case 1: {
[ANIMATION NUMBER 1]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound1.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
} break; //Lots more cases after this one
I know that this is not the best way to do it, declaring the same variable over and over.
but is there a way to stop it before it plays another one?

I just dicovered the answer to my own question.
What I did was
Declare SoundSystemID soundID; in the header.
Add this line before the random number gets generated: AudioServicesDisposeSystemSoundID(soundID);
Remember that if you are going to play the sound again, you will need to load the resource again after disposing of it.
Thank you guys, anyway.

Related

AVAudioPlayer makes system sound louder when played at the same time

I've already asked this question before and even set a bounty but it still remains unanswered. Please someone help me out!!
System sound becomes louder when AVAudioPlayer is initiated
I play sound effects such as button clicking sounds etc with SystemSound and background music with AVAudioPlayer. When AVAudioPlayer starts while SystemSound is being played, that particular system sound becomes like 5 times louder all of a sudden. Has anyone else experienced that? What could be the fix?
These are in SoundControl.m and I'm playing gameBG right after transition.
-(void)gameBG {
self.sharedSoundControl = [SoundControl sharedSoundControl];
if (self.sharedSoundControl.musicOff == NO) {
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"bgm" withExtension:#"mp3"] error:nil];
self.audioPlayer.numberOfLoops = -1;
self.audioPlayer.volume = 0.3f;
[self.audioPlayer play];
}}
-(void)transition {
if (self.sharedSoundControl.effectOff == NO) {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"transition" ofType:#"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}}

Objective-C exception handling

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);

When I run my app in Xcode it crashes when I press a button with sound attached to it

So am making this app where if you press a button, a sound plays but when i pressed the button the app crashed. Heres me code
In the .h file
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#interface ViewController : UIViewController {
}
-(IBAction)buttonPressedWithSound:(id)sender;
#end
nothing wrong there, But in the .m file
-(IBAction)buttonPressedWithSound:(id)sender {
int randomSoundNumber = arc4random() % 4; //random number from 0 to 3
NSLog(#"random NR = %i", randomSoundNumber);
NSString *effectTitle;
switch (randomSoundNumber) {
case 0:
effectTitle = #"Come at me BRO!";
break;
case 1:
effectTitle = #"sound2";
break;
case 2:
effectTitle = #"sound3";
break;
case 3:
effectTitle = #"sound4";
break;
default:
break;
}
SystemSoundID soundID;
NSString *soundPath = [[NSBundle mainBundle] pathForResource:effectTitle ofType:#"caf"];
NSURL *soundUrl = [NSURL fileURLWithPath:soundPath];
AudioServicesCreateSystemSoundID ((CFURLRef)CFBridgingRetain(soundUrl), &soundID);
AudioServicesPlaySystemSound(soundID);
}
#end
this line here
NSURL *soundUrl = [NSURL fileURLWithPath:soundPath];
well it said there was something wrong with it, this
2012-08-10 10:12:52.419 Sound +[1177:907] random NR = 1(lldb)
and
NSURL *soundUrl = [NSURL fileURLWithPath:soundPath];
had a green highlight and said "Thread 1: breakpoint 1.1" to the side of it.
How can i fix it and can it to play the sound without crashing
You should use the NSSound class:
NSSound *sound = [[[NSSound alloc] initWithContentsOfFile: soundPath byReference: NO] autorelease];
[sound play];
Your code logged what you asked it to and then hit a breakpoint that you set in the code. Hit the continue button.

iOS AVAudioPlayer double sound playing issue with Xcode 4.2 and ARC

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

AVAudioPlayer Won't Play Repeatedly

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.