I am trying to make an audio controller, but the stop button doesn't work. But I don't know why. How is this caused and how can I solve it?
.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface myprojectViewController : UIViewController {
AVAudioPlayer* theAudio;
}
- (IBAction)start:(id)sender;
- (IBAction)stop:(id)sender;
#end
.m
- (IBAction)start:(id)sender{
NSString *path = [[NSBundle mainBundle] pathForResource:#"LE" ofType:#"wav"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
}
- (IBAction)stop:(id)sender{
[theAudio stop];
}
'theAudio' is a local variable in your start() method. You've declared it as a local variable, so it is out of scope in your stop() method, and you have an invalid reference. You need to use the class variable 'theAudio. Change :
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
to
self.theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
Related
I am trying to play a sound on the click of a button. But when I run the app it crashes and I get Thread 1 : signal SIGABRT.
This is my code:
.h file
#import <AVFoundation/AVFoundation.h>
#interface HljodViewController : UIViewController <AVAudioPlayerDelegate>{
}
-(IBAction)playsound;
.m file
-(IBAction)playsound {
NSString *path = [[NSBundle mainBundle] pathForResource:#"Geese_4" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.numberOfLoops = 1;
[theAudio play];
}
No one can tell you how to solve your issue if you don't capture the NSError. I suggest you do the following:
NSError *outError = nil;
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&outError];
if (outError)
{
NSLog(#"%#", [outError localizedDescription]);
}
... // continue on to happy time
try this:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:#"yourfile" ofType:#"mp3"];
NSError *error;
AVAudioPlayer *sound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[sound play];
When I press a button, then press another one, the sounds overlap. How can I fix that so the first sound stops when another one is pressed?
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio setDelegate: self];
[theAudio setNumberOfLoops:0];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)playLooped:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops:-1];
[theAudio setVolume:1.0];
[theAudio play];
[theAudio release];
}
Declare your AVAudioPlayer in the header the viewController ( don't alloc a new one each time you play a sound). That way you will have a pointer you can use in a StopAudio method.
#interface myViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *theAudio;
}
#property (nonatomic, retain) AVAudioPlayer *theAudio;
#end
#implementation myViewController
#synthesize theAudio;
- (void)dealloc {
[theAudio release];
}
#end
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if(!theAudio){
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:path] error:NULL];
}
[theAudio setDelegate: self];
[theAudio setNumberOfLoops:0];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)playLooped:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if(!theAudio){
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:path] error:NULL];
}
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops:-1];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)stopAudio {
[theAudio stop];
[theAudio setCurrentTime:0];
}
also be sure to read the Apple Docs
The code you've posted will only play one sound, the first sound sent to the method.
If you want to only play one changeable sound, after stoping the player, release theAudio and then set the new sound.
Add a check to see if the player is already playing at the beginning of each method:
if (theAudio.playing == YES) {
[theAudio stop];
}
AVAudioPlayer Class Reference
In your playOnce method the 'path' variable is unused -- remove that to get rid of your warning message. Your playOnce does not set anything up to play so I'm not sure how that is supposed to work -- unless you call playLooped first? You also need to be calling prepareToPlay after the initWithContentsOfUrl.
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if (theAudio && [theAudio isPlaying]) {
[theAudio stop]
} else {
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
[theAudio prepareToPlay];
[theAudio setDelegate: self];
[theAudio setNumberOfLoops: 1];
[theAudio setVolume: 1.0];
[theAudio play];
}
}
You will need to utizilize a BOOL value to get this to work properly.
in your .m file BEFORE #implementation put this:
static BOOL soundIsPlaying = NO;
Then your IBAction needs to look something like this:
- (IBAction)play {
if (soundIsPlaying == YES) {
[theAudio release];
soundIsPlaying = NO;
}
else if (soundIsPlaying == NO) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"SOUNDFILENAME" ofType:#"wav"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
theAudio.volume = 1.0;
theAudio.numberOfLoops = 0;
[theAudio play];
soundIsPlaying = YES;
}
}
thats honestly about it. It will stop sounds when another button is pressed.
You can probably do something like the following:
(void) playLooped: (NSString * ) aSound {
NSString * path = [[NSBundle mainBundle] pathForResource: aSound ofType: #"caf"];
//stop audio player from playing so the sound don't overlap
if([theAudio isPlaying])
{
[theAudio stop]; //try this instead of stopAudio
}
if (!theAudio) {
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
}
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops: -1];
[theAudio setVolume: 1.0];
[theAudio play];
}
When I press a button, then press another one, the sounds overlap. How can I fix that so the first sound stops when another one is pressed?
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio setDelegate: self];
[theAudio setNumberOfLoops:0];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)playLooped:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops:-1];
[theAudio setVolume:1.0];
[theAudio play];
[theAudio release];
}
Declare your AVAudioPlayer in the header the viewController ( don't alloc a new one each time you play a sound). That way you will have a pointer you can use in a StopAudio method.
#interface myViewController : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *theAudio;
}
#property (nonatomic, retain) AVAudioPlayer *theAudio;
#end
#implementation myViewController
#synthesize theAudio;
- (void)dealloc {
[theAudio release];
}
#end
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if(!theAudio){
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:path] error:NULL];
}
[theAudio setDelegate: self];
[theAudio setNumberOfLoops:0];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)playLooped:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if(!theAudio){
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:path] error:NULL];
}
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops:-1];
[theAudio setVolume:1.0];
[theAudio play];
}
- (void)stopAudio {
[theAudio stop];
[theAudio setCurrentTime:0];
}
also be sure to read the Apple Docs
The code you've posted will only play one sound, the first sound sent to the method.
If you want to only play one changeable sound, after stoping the player, release theAudio and then set the new sound.
Add a check to see if the player is already playing at the beginning of each method:
if (theAudio.playing == YES) {
[theAudio stop];
}
AVAudioPlayer Class Reference
In your playOnce method the 'path' variable is unused -- remove that to get rid of your warning message. Your playOnce does not set anything up to play so I'm not sure how that is supposed to work -- unless you call playLooped first? You also need to be calling prepareToPlay after the initWithContentsOfUrl.
- (void)playOnce:(NSString *)aSound {
NSString *path = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
if (theAudio && [theAudio isPlaying]) {
[theAudio stop]
} else {
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
[theAudio prepareToPlay];
[theAudio setDelegate: self];
[theAudio setNumberOfLoops: 1];
[theAudio setVolume: 1.0];
[theAudio play];
}
}
You will need to utizilize a BOOL value to get this to work properly.
in your .m file BEFORE #implementation put this:
static BOOL soundIsPlaying = NO;
Then your IBAction needs to look something like this:
- (IBAction)play {
if (soundIsPlaying == YES) {
[theAudio release];
soundIsPlaying = NO;
}
else if (soundIsPlaying == NO) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"SOUNDFILENAME" ofType:#"wav"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
theAudio.volume = 1.0;
theAudio.numberOfLoops = 0;
[theAudio play];
soundIsPlaying = YES;
}
}
thats honestly about it. It will stop sounds when another button is pressed.
You can probably do something like the following:
(void) playLooped: (NSString * ) aSound {
NSString * path = [[NSBundle mainBundle] pathForResource: aSound ofType: #"caf"];
//stop audio player from playing so the sound don't overlap
if([theAudio isPlaying])
{
[theAudio stop]; //try this instead of stopAudio
}
if (!theAudio) {
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath: path] error: NULL];
}
[theAudio setDelegate: self];
// loop indefinitely
[theAudio setNumberOfLoops: -1];
[theAudio setVolume: 1.0];
[theAudio play];
}
I am currently loading an audio file inside of a button. I am assuming there is a more efficient way to load this file instead of every time the button is pressed. Where should this be loaded? Globally, inside viewdidload. I'm loading it like the code below.
NSString *path = [[NSBundle mainBundle] pathForResource:#"click" ofType:#"mp3"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
viewDidLoad is a good idea -- will let you free up the memory in viewDidUnload too in case you are short on memory. You could also implement getters and setters in the code below by synthesizing theAudio and using self.theAudio
#interface myClass {
AVAudioPlayer *theAudio;
}
#implementation myClass {
- (void) viewDidLoad {
NSString *path = [[NSBundle mainBundle] pathForResource:#"click" ofType:#"mp3"];
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
}
- (void) viewDidUnload {
[theAudio release];
}
}
I want to play multiple audio files (.WAV) using IBAction and AVAudioPlayer. Unfortunatelly the sound plays but if I play the sound many times, my application crashes. Can you help me?
Here's my code.
ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface ViewController : UIViewController <AVAudioPlayerDelegate>
{
NSString *Path;
}
- (IBAction)Sound1;
- (IBAction)Sound2;
- (IBAction)Sound3;
- (IBAction)Sound4;
#end
ViewController.m
#import <AVFoundation/AVAudioPlayer.h>
#import "ViewController.h"
#implementation ViewController
AVAudioPlayer *Media;
- (IBAction)Sound1
{
Path = [[NSBundle mainBundle] pathForResource:#"Sound1" ofType:#"wav"];
Media = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:Path] error:NULL];
[Media setDelegate:self];
[Media play];
}
- (IBAction)Sound2
{
Path = [[NSBundle mainBundle] pathForResource:#"Sound2" ofType:#"wav"];
Media = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:Path] error:NULL];
[Media setDelegate:self];
[Media play];
}
- (IBAction)Sound3
{
Path = [[NSBundle mainBundle] pathForResource:#"Sound3" ofType:#"wav"];
Media = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:Path] error:NULL];
[Media setDelegate:self];
[Media play];
}
- (IBAction)Sound4
{
Path = [[NSBundle mainBundle] pathForResource:#"Sound4" ofType:#"wav"];
Media = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:Path] error:NULL];
[Media setDelegate:self];
[Media play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[player release];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)dealloc
{
[Media Release];
[super dealloc];
}
#end
There are a couple things that look wrong in your code:
(1). There are no method Release, [Media Release] should be [Media release];
(2). If you play Sound2 while Sound1 is still playing, you leak Media instance:
Media = [[AVAudioPlayer alloc] initWithContentsOfURL:...
This allocates new player and overwrites old one without releasing it first;
(3). It is usually bad idea to release calling object in delegate;
(4). I'd also suggest to rename Media to media and Path to path.
So playing action should look like this:
- (IBAction)playSound1
{
path = [[NSBundle mainBundle] pathForResource:#"Sound1" ofType:#"wav"];
media = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[media play];
[media release];
}