Make my background music player stop? Objective C - ios

I have several views, one of them is an "options" view, in this view there will be a button that will allow the user to click a button to "stop" the background music, or click it to turn it back on. Im pretty sure I have the general idea of how to do this, the problem is, my code isnt working and I am not sure why.
this is the code from the implementation file for the "options" class:
- (IBAction)musicIO:(id)sender {
MenuViewController *myMusicPlayer = [[MenuViewController alloc] init];
[myMusicPlayer backgroundMusicStart];
}
it calls the method in my menu code(a different class)
This is my menu code:
-(IBAction) backgroundMusicStart{
if( i != 1){
NSURL * URL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/backgroundMusic.wav", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
backgroundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:&error];
backgroundPlayer.numberOfLoops = -1;
[backgroundPlayer play];
i = 1;
NSLog(#"In start music");
}
else if ( i == 1 ) {
[backgroundPlayer stop];
i = 0;
NSLog(#"In stop music");
}
}
"i" is a globally declared variable.
The problem with the code:
it runs, NSLog outputs that it gets into both if statements fine, the problem is when it is in the [backgroundPlayer stop] bracket, it doesnt stop the music, and I cant figure out why.

You're initialising backgroundPlayer every time this method is invoked and in only one of the cases. What you should be doing is make backgroundPlayer an instance variable and act on the shared instance of it... Example follows:
// static AVPlayer *backgroundPlayer;
- (IBAction) backgroundMusicStart {
if (backgroundPlayer == nil) {
backgroundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:&error];
backgroundPlayer.numberOfLoops = -1;
}
if (i == 1) { [backgroundPlayer stop]; }
else if (i == 0) { backgroundPlayer play]; }
}

Related

Play/Pause/Stop multiple audio file which are stored locally

I have 20 audio tracks, which are stored locally in my project.
I want to play all that files sequentially . For that I have used AVQueuePlayer. Please check below code for reference.
Declaration :-
#interface ViewController ()
{
AVAudioPlayer *player;
NSMutableArray *arrPlayData;
AVPlayerItem *item;
}
#property (nonatomic, retain) AVQueuePlayer *queuePlayer;
Button Clicks as below,
-(IBAction)click_Play:(id)sender {
for (int j = 0; j < arrPlayData.count; j++) {
path =[[NSBundle mainBundle] pathForResource:[[arrPlayData objectAtIndex:j] valueForKey:#"AudioName"] ofType:#"wav"];
item = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:path]];
if (_queuePlayer == nil) {
_queuePlayer = [[AVQueuePlayer alloc] initWithPlayerItem:item];
} else{
[_queuePlayer insertItem:item afterItem:nil];
}
}
[_queuePlayer setVolume:1.0];
[_queuePlayer play];
}
Then on pause button I have written below code,
-(IBAction)click_Pause:(id)sender {
[_queuePlayer pause];
}
And on Stop button I have written below code,
-(IBAction)click_Stop:(id)sender {
[_queuePlayer removeAllItems];
}
Everything is working well, the problem I am facing is with PAUSE button. When I click on pause button it stops playing. Then again when I click on play button it plays from the same place where I pause it. Till here everything looks good. But on playing the audio queue after pausing, it plays remaining part of audio queue and then again it plays one more time the whole audio queue. Don't know how to resolve it. Why it is playing whole audio queue again?
Anyone have idea?
Thanks in advance!
whole audio queue is playing again because you are inserting item from arrPlayData every time click_Play is clicked.
So, in click_Play check count of items and handle accordingly like insert item only if count of items _queuePlayer is Zero.
#interface ViewController ()
{
BOOL FromPause;
}
-(IBAction)click_Stop:(id)sender {
[_queuePlayer removeAllItems];
}
-(IBAction)click_Pause:(id)sender {
[_queuePlayer pause];
FromPause=YES;
}
-(IBAction)click_Play:(id)sender {
for (int j = 0; j < arrPlayData.count; j++) {
path =[[NSBundle mainBundle] pathForResource:[[arrPlayData objectAtIndex:j] valueForKey:#"AudioName"] ofType:#"wav"];
item = [[AVPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:path]];
if (_queuePlayer == nil) {
_queuePlayer = [[AVQueuePlayer alloc] initWithPlayerItem:item];
} else{
if(FromPause){
//don't add again
FromPause=NO;
}
else{
[_queuePlayer insertItem:item afterItem:nil];
}
}
}
[_queuePlayer setVolume:1.0];
[_queuePlayer play];
}
Because of you are initialize AVPlayerItem again in click_Play.
Please take one bool value and insert arrPlayData if AVPlayerItem not allocated.

Error with AVAudio Player in an SKScene

I am trying to make a background music in my game with AVAudioPlayer, so I set this code at the initWithSize method of my SKScene:
//SETTING BACKGROUND MUSIC//
NSError * err = nil;
NSURL * musicFile = [[NSBundle mainBundle] URLForResource:#"Cosmic Rush" withExtension:#"m4a"];
music = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&err];
if(err)
{
NSLog(#"%#", [err userInfo]);
return;
}
[music prepareToPlay];
music.numberOfLoops = -1;
[music setVolume:0.5];
//SETTING BACKGROUND MUSIC//
Then, in another method: [music play]; However, the sound never plays, and I have tried all sort of extensions: .mp3, .caf, .mp4 etc. I have also checked people who had the same problem, but none of the solutions that solved their problems worked with mine.
there is a easier way to add background music to your scene. i use the following steps and works just as good as any other methods and it is easier.
import the #import AVFoundation; at the top of your scene.
add it as a property right after your #implementation.
AVAudioPlayer *_backgroundMusicPlayer;
then declare a method for the music
- (void)playBackgroundMusic:(NSString *)filename
{
NSError *error;
NSURL *backgroundMusicURL =
[[NSBundle mainBundle] URLForResource:filename
withExtension:nil];
_backgroundMusicPlayer =
[[AVAudioPlayer alloc]
initWithContentsOfURL:backgroundMusicURL error:&error];
_backgroundMusicPlayer.numberOfLoops = -1;
[_backgroundMusicPlayer prepareToPlay];
[_backgroundMusicPlayer play];
}
after that create a reference to that method in your -(id)initWithSize:(CGSize)size like the following
[self playBackgroundMusic:#"bgMusic.mp3"];
that should take care of the background music for you.

iOS sound on button problems on second click

I have code which plays a sound after I clicked a button. When I click this button a second time first comes a thing like a reset or so.
What I want: Every time I click the button I want to play the sound immediately without reset button.
My code:
-(IBAction)playfrosch {
if (gestartet == 0) {
gestartet = 1;
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/frosch.mp3", [[NSBundle mainBundle]resourcePath]]];
NSError *error;
audioPlayerfrosch = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayerfrosch.numberOfLoops = 0;
[audioPlayerfrosch play];
[startfrosch setTitle:#"Frosch" forState:UIControlStateNormal];
} else {
gestartet = 0;
[startfrosch setTitle:#"Nochmal?" forState:UIControlStateNormal];
}
}
I think my problems are the part after "else".
This is a logic problem. Your code only executes the sound play code if gestartet == 0.
So move the sound play code outside of the if statement. Problem solved.

AVAudioPlayer sound file location not changing / updating

*This is my first stackoverflow question so apologies if I am doing something wrong.
I am trying to create a simple sound board app. I'm having trouble getting my AVAudioPlayer on xCode 4.1 (iOS 6.1.2) to update where the sound file to play is located. I wanted to avoid having multiple audio players (audioPlayer2, audioPlayer3, etc) so I am trying to use the same audio player but instead, update where the sound file is located. I only want one sound playing at a time so multiple sounds is obviously not an issue. Here is my code:
- (IBAction)play {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
//I added the next two lines to allow me to play AVAudio with MPiPodPlayer (which I found on this site, too) simultaneously.
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start setTitle:#"Start" forState:UIControlStateNormal];
}
}
- (IBAction)play2 {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/chicken.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start2 setTitle:#"Stop" forState:UIControlStateNormal];
clicked = 1;
clicked2 = 0;
} else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start2 setTitle:#"Start" forState:UIControlStateNormal];
clicked = 0;
}
}
My IBActions are linked to UIButtons and the 'start's are UIButton references. Whenever I click on 'start' it plays 'k.mp3' fine, however if I then click on 'start2' AFTER it starts to play the 'k.mp3' file, and not the chicken file. Whichever button I click on first is what the url is set to. This is my first iPhone OS application project so I realize there are probably some embarrassing coding mistakes in there (feel free to correct me). I'd like an answer that would be applicable to multiple buttons, even for some 30 buttons so I do not have to copy and paste stop audio player 1, 2, and 3 for each button.
To summarize: I have multiple buttons that play one sound each, I would like no more than one sound playing at a time; when I click on a button it plays 1 sound and all other audio players stop. I would prefer having only one AVAudioPlayer instance for simplicity. Thanks in advance!
Check if application control goes into - (IBAction)play2
And if control goes in it and it is still not working then you might try [audioPlayer release] before
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
that might do the trick for you

Press a button it makes a sound. Hit button fast and sound playback pops and clicks

I have 6 buttons that each play an audio sample from a .caf file. If I press a button the sound plays fine, if I wait for it to end and press it again it plays fine but if I press the button fast then the sound will pop and click before playing.
I initially didn't have this popping problem when simply allocating the AVAudioPlayer each time the button is clicked but this created a memory leak with multiple allocations. So I created 6 AVAudioPlayers for each button and re-used it, this got rid of the memory leak but now the samples click/pop when overwritten.
I have tried lots of different ways to stop this happening from setting the volume to 0, stopping the AVAudioPlayer instance before playing the next sample etc but cant find the correct way to repeatedly play the same sample sound with fast button presses and stop the popping.
I do have the AVAudioPlayer property as retain in the .h and use autorelease in the alloc statement.
Any help please?
** Edit: found a solution, its not pretty but it works.
Basically I created 10 AVAudioPlayers that autorelease and if one [myPlayer1 isPlaying] then I use the next one.
e.g.
BOOL done = NO;
if(![self.audioPlayer0 isPlaying] && done == NO) {
self.audioPlayer0 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer0 play];
done = YES;
}
if(![self.audioPlayer1 isPlaying] && done == NO) {
self.audioPlayer1 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer1 play];
done = YES;
}
if(![self.audioPlayer2 isPlaying] && done == NO) {
self.audioPlayer2 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer2 play];
done = YES;
}
if(![self.audioPlayer3 isPlaying] && done == NO) {
self.audioPlayer3 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer3 play];
done = YES;
}
if(![self.audioPlayer4 isPlaying] && done == NO) {
self.audioPlayer4 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer4 play];
done = YES;
}
if(![self.audioPlayer5 isPlaying] && done == NO) {
self.audioPlayer5 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer5 play];
done = YES;
}
if(![self.audioPlayer6 isPlaying] && done == NO) {
self.audioPlayer6 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer6 play];
done = YES;
}
if(![self.audioPlayer7 isPlaying] && done == NO) {
self.audioPlayer7 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer7 play];
done = YES;
}
if(![self.audioPlayer8 isPlaying] && done == NO) {
self.audioPlayer8 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer8 play];
done = YES;
}
if(![self.audioPlayer9 isPlaying] && done == NO) {
self.audioPlayer9 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[audioPlayer9 play];
}
Why remember all ten audio players instead of dynamically creating them?
In your new solution, what you're effectively doing is looping through all the audio players to find one that isn't playing. Why not do the same thing in an array?
NSMutableArray *playerHolder = [[NSMutableArray alloc] init];
int maxNumberOfBuffers = 10;
for (int i=0; i<maxNumberOfBuffers; i++)
{
AVAudioPlayer *audioPlayer;
[playerHolder addObject:audioPlayer];
}
Then, simply look through the array when trying to play something:
for (int i=0; i<playerHolder.count; i++)
{
if (![[playerHolder objectAtIndex:i] isPlaying])
{
AVAudioPlayer *freePlayer = [playerHolder objectAtIndex:i];
freePlayer = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
[freePlayer play];
}
}
In theory, that should achieve the same thing as your solution, without the clutter.
I can't be sure, but the problem probably occurs because you are truncating the wave at a non zero-crossing, which causes a vertical portion in the waveform (nasty harmonics, click/pop). You need to fade the waveform instead of cutting it out. Look into raised cosine smoothing/shaping.

Resources