AVAudioPlayer makes system sound louder when played at the same time - objective-c

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

Related

Play NSSound two times

I want to play a NSSound two times except its shorter than 10sec then i want to wait until the 10sec are done and then start the second one.
But I already have a problem playing the same NSSound twice.
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"MessageArrived" ofType:#"wav"];
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:resourcePath byReference:YES];
[sound play] //It plays the fist time
[sound play] //I get the following Error and it doesn't play a secont time
/*malloc: *** auto malloc[498]: error: GC operation on unregistered thread. Thread registered implicitly. Break on auto_zone_thread_registration_error() to debug.*/
Can someone tell me whats the reason for this error?
How can I handle this?
Is there another way i have to do this?
So after a loot of searching and trying to fix it I got the solution for my problem...
NSSound *sound = [NSSound soundNamed:#"MessageArrived"];
BOOL res = [sound play];
NSLog(#"%d", res);
[NSThread detachNewThreadSelector:#selector(playSecondSound:) toTarget:self withObject:sound];
-(void)playSecondSound:(NSSound*)sound
{
[NSThread sleepForTimeInterval:10-[sound duration]];
[sound stop];
BOOL res = [sound play];
NSLog(#"%d", res);
}
I found out that even when the sound has finished I have to call [sound stop] before starting the second.
The sound is already playing when you call the second play method, obviously a bug in garbage collection as the second play should be ignored, but it will not be an issue with what you want to achieve.
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"MessageArrived" ofType:#"wav"];
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:resourcePath byReference:YES];
[sound play];
//Will play the second time after 10.0 seconds have passed.
NSInteger wait = ([sound duration] < 10.0) ? 10.0 - [sound duration] : 0.0;
[sound performSelector:#selector(play) withObject:nil afterDelay:wait];

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.

Stop a sound using the same button that plays it

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.

Waiting until another sound is finished before playing a new one

I am developing an iPhone application that plays sounds. I do not want interrupt or play another sound, if a sound is already playing, regardless of where it was "spawned" from to play. My code is as follows:
if(distance <= 10)
{
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}
Simply, I do not want to play a new sound if one is already playing.
I do not want to queue another sound to play if one is already playing.
Is this possible?
I suggest you use the AVAudioPlayer API rather than AudioServicesPlaySystemSound. It has a delegate which you can use, which defines a method -audioPlayerDidFinishPlaying:successfully: which will tell you when your sound finishes playing. The AVPlayer class also has a -playing method which you can check to see if a sound is currently playing.
So, in other words, do this instead:
NSError *error;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundPath error:&error];
if(!player)
[self doSomethingWithError:error];
[player setDelegate:self];
[player play];