I have 6 sounds on one view.
However I want it so that I can play more than one at once, So you tap sound 1 (sound 1 is playing) then sound 2 plays. while sound 1 is still playing.
But at the moment I press sound 1 (sound 1 plays), press sound 2 (sound 2 plays, but sound 1 stops)
Here is the code for the audio part.
- (IBAction)oneSound:(id)sender; {
NSString *path = [[NSBundle mainBundle] pathForResource:#"1" ofType:#"wav"];
if (theAudio) [theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(updateVolume) userInfo:nil repeats:YES];
}
- (IBAction)twoSound:(id)sender; {
NSString *path = [[NSBundle mainBundle] pathForResource:#"2" ofType:#"wav"];
if (theAudio) [theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
volumeTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(updateVolume) userInfo:nil repeats:YES];
}
There is some important code missing, but it looks as if theAudio is a global you are using to manage the playing of your sounds. Since you destroy it whenever a sound is played whatever is currently playing will stop in preparation for the next sound.
There are several ways to fix this, one being that each sound gets its own unique AVAudioPlayer instance.
don't release the player just because it exists. release when finished playing
You should implement this in the app delegate or a property of the app delegate so that the delegate reference remains valid if you pop the view.
You should not need to do this for each voice. Each voice will initial the player with a different filename or URL. You gain this by making sure that you will release when finished playing. The other thing to take care of is releasing players if the player doesn't finish because of an interruption.
#pragma mark -
#pragma mark Audio methods
-(void)playNote:(NSInteger)noteNumber {
NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i", noteNumber ]
ofType: #"caf"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
AVAudioPlayer *playerToPrepare = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
error:nil];
[fileURL release];
[playerToPrepare prepareToPlay];
[playerToPrepare setDelegate: self];
[playerToPrepare play];
}
#pragma mark -
#pragma mark AVAudioPlayer delegate methods
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) playerThatFinished
successfully: (BOOL) completed {
if (completed) {
[playerThatFinished release];
}
}
You can declare and use:
AVAudioPlayer *theAudio1; // for file 1.wav
AVAudioPlayer *theAudio2; // for file 2.wav
...
AVAudioPlayer *theAudio6; // etc.
instead of releasing and reusing just one AVAudioPlayer.
Related
I have this code:
int ran = 1 + arc4random() % 18;
NSString *soundFileIs=[NSString stringWithFormat:#"ton%i.mp3",ran];
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *audioFile = [paths stringByAppendingPathComponent:soundFileIs];
NSData *cdata =[NSData dataWithContentsOfFile:audioFile];
audioPlayer = [[AVAudioPlayer alloc] initWithData:cdata error:nil];
audioPlayer.delegate = self;
[audioPlayer play];
When I shake device, it plays random my 18 sounds. How can I make to stop previously playing sound, and play next sound? Everything works great, just I hear 1st sound when I shake for first time, when I shake 2nd time, i hear 1st and 2nd sound playing if my 1st sound didn't stop play. Thank you.
Before playing anything, check to see if it's already playing and call stop. Your code will then be:
int ran = 1 + arc4random() % 18;
NSString *soundFileIs=[NSString stringWithFormat:#"ton%i.mp3",ran];
NSString *paths = [[NSBundle mainBundle] resourcePath];
NSString *audioFile = [paths stringByAppendingPathComponent:soundFileIs];
NSData *cdata =[NSData dataWithContentsOfFile:audioFile];
if (audioPlayer.playing)
[audioPlayer stop];
audioPlayer = [[AVAudioPlayer alloc] initWithData:cdata error:nil];
audioPlayer.delegate = self;
[audioPlayer play];
when you shake that time call
[audioPlayer stop];
first check audioplayer is playing a sound or not if not then don't call stop methord if playing then 1st call stop methord
call
if([audioPlayer playing])
[audioPlayer stop];
method on shaking the device to stop the current song.
then use this delegate method to play the next song.
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
I am playing "sound effects" in my app when buttons are clicked and such and I have been having some difficulties getting the delegates to work properly within the AVAudioPlayer class to keep the music playing after the sound. I have the framework imported and delegates set but I can not seem to get the AVAudioSession shared instance to work... I know I am missing something but can not seem to find a clear answer anywhere even within apples docs. Here is the code I am using trying to accomplish this.
#import "AVFoundation/AVAudioPlayer.h
#import "MediaPlayer/MediaPlayer.h"
#interface HomeViewController : UIViewController <AVAudioPlayerDelegate, MPMediaPlayback
> {
When a button is pushed
-(IBAction)About
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button" ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
AboutViewController *about = [[AboutViewController alloc] init];
[self presentModalViewController:about animated:YES];
NSString *path1 = [[NSBundle mainBundle] pathForResource:#"move" ofType:#"caf"];
AVAudioPlayer* theAudio1 = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path1] error:NULL];
theAudio.delegate = self;
[theAudio1 play];
}
Delegates trying to either play my sound as a "ambient noise" or just resume play after my sound happens
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
}
-(void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error
{
}
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
}
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags
{
if (flags)
{
AVAudioPlayer *audio = [[AVAudioPlayer alloc] init];
[audio setDelegate:self];
[audio play];
}
}
Now the last delegate from what I understand is the only delegate of use really in my case and what I have will not work since I need to be using the [AVAudioSession SharedInstance] like this but I can not seem to get the AVAudioSession to work!
-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withFlags:(NSUInteger)flags
{
if (flags == AVAudioSessionFlags_ResumePlay)
{
[player play];
}
}
Any help or suggestions would be greatly appreciated. I basically just need to know how to get the [AVAudio SharedInstance] so if anyone knows what class I need to import or framework I need to add to get this working it would be very much obliged!
Thanks
How to stop background music when changing views? I have no clue. If i press a button which takes me to a new view, there is new background music. But the old background music (which goes in an infinite loop) keeps on going. Please help! also sample some code please, here is mine:
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"MathMusic2" ofType:#"wav"];
AVAudioPlayer* theAudio= [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
theAudio.numberOfLoops = -1;
[super viewDidLoad];
}
I just need to know how to make the background music from the new view stop playing. And vice versa when i press the back button from the new view
Create a property for the AVAudioPlayer *theAudio so you can access the audioPlayer from any point in your class.
Header file of viewController
...
AVAudioPlayer *theAudio;
...
#property (nonatomic, retain) AVAudioPlayer *theAudio;
Implentation file of viewController
...
#synthesize theAudio;
...
- (void)viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"MathMusic2" ofType:#"wav"];
self.theAudio= [[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL]] autorelease];
theAudio.delegate = self;
[theAudio play];
theAudio.numberOfLoops = -1;
[super viewDidLoad];
}
If viewWillDisappear is called you can then just stop the audio with
- (void)viewWillDisappear
{
[theAudio stop];
}
it gaves errors in here :
"theAudio.delegate = self;" as something like assigning to id...
its yellow anyway..
still when i change view and go to another class music not stoping....
What I am doing is
-(void)viewWillAppear:(BOOL)animated{
[NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:#selector(clickEvent:) userInfo:nil repeats:YES];
}
-(void)clickEvent:(NSTimer *)aTimer{
NSDate* finishDate = [NSDate date];
if([finishDate timeIntervalSinceDate: self.startDate] > 11 && touched == NO){
NSString *mp3Path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"test.mp3"];
[self playMusicFile:mp3Path];
NSLog(#"Timer from First Page");
[aTimer invalidate];
//[touchCheckTimer release];
aTimer = nil;
}
else{
}
-(void)playMusicFile:(NSString *)mp3Path{
NSURL *mp3Url = [NSURL fileURLWithPath:mp3Path];
NSError *err;
AVAudioPlayer *audPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:mp3Url error:&err];
[self setAudioPlayer1:audPlayer];
if(audioPlayer1)
[audioPlayer1 play];
[audPlayer release];
}
Now, on pushing another view this audio file keeps playing in the background.
Please help!
Well it is very common mistake
when you are leaving the view call stop method on the AVAudioPlayer variable pointer that you used to play the audio with
I'm calling playSoundFromBundle from the code below to play sounds (aif files). I have a sound that does a single click and then a fading sound. Both sounds are in the same file. Sometimes I get two clicks and then the fade. Meaning, click, click...fade. A single click isn't what should play. I'm guessing the sound starts (click sound), gets interrupted and then restarts (full sound...click/fade) because of other processing that may be going on. It seems random when it will occur. I put the sound on its own thread to try and avoid the double clicking. Is there anything else I can do to ensure the sound plays correctly?
- (void) playSoundFromBundleThreaded:(NSArray*)arr{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *fileName = (NSString*)[arr objectAtIndex:0];
NSString *fileExt = (NSString*)[arr objectAtIndex:1];
NSError *err;
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource: fileName ofType: fileExt inDirectory:#"/"]] error: &err];
self.audioPlayer = newPlayer;
self.audioPlayer.numberOfLoops = 0;
self.audioPlayer.volume = .5;
if (self.audioPlayer == nil)
{
NSLog(#"Problem initializing Sound - %#", [err description]);
}
else
{
[self.audioPlayer play];
}
[newPlayer release];
[pool release];
}
- (void) playSoundFromBundle:(NSString*)fileName fileExtension:(NSString*)fileExt{
NSArray *arr = [NSArray arrayWithObjects:fileName, fileExt, nil];
[NSThread detachNewThreadSelector: #selector(playSoundFromBundleThreaded:) toTarget:self withObject:arr];
}
No idea if this would work, but check out the Audio Session stuff. It's intended to manage things like whether the playing of other sounds (such as by the music player) will interrupt audio from your application.