How to make a Custom UIButton to toggle a Sound On/Off - iphone

i am an n00b and seeking help.
Now i can start a Soundfile with Following code:
- (void)addButtonSpeaker {
UIButton *buttonSpeaker = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonSpeaker setFrame:CGRectMake(650, 930, 63, 66)];
[buttonSpeaker setBackgroundImage:[UIImage imageNamed:#"buttonLesen.png"]
forState:UIControlStateNormal];
[buttonSpeaker addTarget:self action:#selector(playAudio)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:buttonSpeaker];
}
- (void)playAudio {
NSString *path = [[NSBundle mainBundle] pathForResource:#"Vorwort" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL
fileURLWithPath:path] error:NULL];
self.audioPlayer = theAudio;
[theAudio release];
[theAudio play];
}
With the same Button i would like to stop and play the sound.
Maybe i am searching for the wrong thing, but i can´t find the proper information on the web.
It would be really helpful if someone could give me a LINK to a tutorial or something like this.
thanks in advance
Planky

Create the AVAudioPlayer player object on loadView or somewhere.
- (void)loadView {
// Some code here
NSString *path = [[NSBundle mainBundle] pathForResource:#"Vorwort" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
self.audioPlayer = theAudio;
[theAudio release];
// Some code here
}
Then inside the button's action(change the action name to toggleAudio as others suggested), you can get the property isPlaying to see whether audio is playing or not, and do the respective actions.
- (void)toggleAudio { // original name is playAudio
if ([self.audioPlayer isPlaying]) {
[self.audioPlayer pause];
// Or, [self.audioPlayer stop];
} else {
[self.audioPlayer play];
}
}

Related

Playing sound on a button click

I'm facing a very strange issue, my requirement is to play a sound on the button click and this is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path=[[NSBundle mainBundle] pathForResource:#"button-3" ofType:#"mp3"];
tapSound=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL]];
[tapSound prepareToPlay];
tapSound.delegate=self;
//creating the button in view did load and button is declared in .h
btn=[UIButton buttonWithType:UIButtonTypeCustom];
btn.frame=CGRectMake(x, y, 58,58);
[btn addTarget:self action:#selector(btnClkd:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
//click method
-(void)btnClkd:(UIButton*)sender
{
[tapSound play];
}
But when I run the code and click the button my app gets crashed and got this error: "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton play]: unrecognized selector sent to instance 0x758c790' "
But if I play the sound anywhere else but not on the click of the button then it get played without any issue.I dont know why this is happening? Please help me
Do this:
-(void)btnClkd:(UIButton*)sender
{
NSString *path=[[NSBundle mainBundle] pathForResource:#"button-3" ofType:#"mp3"];
tapSound = nil;
tapSound=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL]];
[tapSound prepareToPlay];
tapSound.delegate=self;
[tapSound play];
}
Try this one . Add in your .h file
.h file
#import <AVFoundation/AVFoundation.h>
#import <AudioUnit/AudioUnit.h>
AVAudioPlayer *player1;
#property(nonatomic ,retain)AVAudioPlayer *player1;
in your .m file
#synthesize player1;
- (void)viewDidLoad
{
[super viewDidLoad];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"button-3" ofType:#"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[fileURL release];
self.player1 = audioPlayer;
[audioPlayer release];
[self.player1 prepareToPlay];
[self.player1 setDelegate:self];
[pool release];
//creating the button in view did load and button is declared in .h
btn=[UIButton buttonWithType:UIButtonTypeCustom];
btn.frame=CGRectMake(x, y, 58,58);
[btn addTarget:self action:#selector(btnClkd:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)btnClkd:(UIButton*)sender {
[self.player1 play];
}

UIButtons event Touch up Inside not work properly?

My question is little abmigious ,thats why I posted all my code,so I request to every one please test all this code before giving me the Answer.Thanx
In my application i create all UIButtons programmatically and then save all these UIButtons in NSMutableArray. Here is my code:-
-(void)button:(id)sender
{
int btnn = 0;
int spacex = 152;
int spacey=20;
int k=0;
saveBtn = [[NSMutableArray alloc] init];
for (int i=0; i<48; i++)
{
if (btnn>6)
{
spacey=spacey+25;
spacex = 152;
btnn = 0;
}
else
{
btnn++ ;
k++;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(spacex, spacey, 25.0, 25.0);
int idx;
idx = arc4random()%[arr count];
NSString* titre1 = [arr objectAtIndex:idx];
[btn setTitle: titre1 forState: UIControlStateNormal];
[btn setTitleColor: [UIColor yellowColor] forState: UIControlStateNormal];
[btn.titleLabel setFont:[UIFont fontWithName:#"TimesNewRomanPS-BoldMT" size:22.0]];
spacex = spacex + 25;
btn.tag=k;
[btn addTarget:self action:#selector(aMethod:)forControlEvents:UIControlEventTouchUpInside];
[saveBtn addObject:btn];
[self.view addSubview:btn];
}
}
}
Now in (aMethod:) I add click sound on Each UIButton TouchUpInside event. Here is my code.
- (void)aMethod:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
[theAudio play];
}
Every thing work fine in start of my application , but continiously clicking the UIButtons approximatilly after 100 clicks i hear no sound of click and when i click on Next UIButtons touchup inside event its crash.Can any body help me in this issue.Thanx
app due to uncaught exception NSInternalInconsistencyException, reason: Could not load NIB in bundle: NSBundle </Users/moon/Library/Application Support/iPhone Simulator/4.1/Applications/3E14E5D6-4D1B-4DAC-A2B9-07667E99C399/soundtesting.app‌​> (loaded) with name secondclass
Ah, yes. What we have here is a failure to understand log messages. Your UIButton, which I can only assume pushes a new view onto the stack, is referencing a NIB that simply doesn't exist. It's a naming issue, not a button issue. Most likely, I would check for any calls to -initWithNibName: and see if your NIB really is named "secondclass.". Remember, iOS file names are CaSe SeNsITive.
//.h
...
#property (nonatomic, retain) AVAudioPlayer * player;
//.m
-(void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate=self;
//in MRC, use [path release];
}
-(void)someMethod:(id)sender
{
[player play];
}
The reason might me memory leak for playing same audio these many times it may fill memory use this code for playing audio
- (id)initWithNibName:(NSString*)nibName bundle:(NSBundle*)nibBundleOrNil
{
if (self = [super initWithNibName:nibName bundle:nibBundleOrNil]) {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
theAudio = [AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath] error:NULL];
}
return self;
}
- (IBAction)playSound
{
[theAudio play];
}
- (void)dealloc
{
[theAudio release];
[super dealloc];
}
You have a memory issue. When you do :
- (void)aMethod:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
[theAudio play];
}
1/ path is never released
2/ theAudio is never release
So you need to release theAudio in delegate method :
– audioPlayerDidFinishPlaying:successfully:
And you need to release path like this :
- (void)aMethod:(id)sender
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate=self;
[theAudio play];
[path release];
}
I think your problem should be solved.
I test your code . Changes in your aMethod following code. Though this I can get tag value.
- (void)aMethod:(id)sender
{
UIButton *btn=(UIButton *)sender;
NSLog(#"\n\n\nselectedbutton tag === %d \n\n\n",btn.tag );
NSString *path = [[NSBundle mainBundle] pathForResource:#"button-17" ofType:#"wav"];
NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer play];
}

AVAudioPlayer leaks?

I've got a problem and don't know how to handle it. Tyring to build an app with sound and animation. It gives me a level 1 and then level 2 memory warning. I've tried build and analyze and i got all these potential leaks. If I release theAudio the sound won't play. Any hints?
Here is a part of the code and the leakes I've got
- (IBAction)playsound2
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"cat" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
*- **Method returns an Objective-C object with a +1 retain count (owning reference)***
theAudio.delegate = self;
[theAudio play];
***- Object allocated on line 302 and stored into 'theAudio' is no longer referenced after this point and has a retain count of +1 (object leaked)***
cat1.hidden = 0;
cat.hidden = 1;
[cat1 startAnimating];
cat.center = cat1.center;
[self performSelector:#selector(loadAnimations) withObject:nil afterDelay:1.0];
catLabel.hidden = 0;
}
Here is the solution for the same problem asked so far.
- (AVAudioPlayer *)audioPlayerWithContentsOfFile:(NSString *)path {
NSData *audioData = [NSData dataWithContentsOfFile:path];
AVAudioPlayer *player = [AVAudioPlayer alloc];
if([player initWithData:audioData error:NULL]) {
[player autorelease];
} else {
[player release];
player = nil;
}
return player;
}
And for better idea you can follow this.
You have to state an instance variable for the AVAudioPlayer class instance.
//Instance variable:
{
AVAudioPlayer* theAudio;
}
- (IBAction)playsound2
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"cat" ofType:#"mp3"];
if (!theAudio ) {
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
if (theAudio ) {
theAudio.delegate = self;
[theAudio play];
}
}
cat1.hidden = 0;
cat.hidden = 1;
[cat1 startAnimating];
cat.center = cat1.center;
[self performSelector:#selector(loadAnimations) withObject:nil afterDelay:1.0];
catLabel.hidden = 0;
}

Adjusting the size the volume, using the same uislider but for multiple sounds

I have 10 sounds in a view. And one uislider
This is the code for 1 of the sounds.
- (IBAction)oneSound:(id)sender; {
SystemSoundID soundID;
NSString *path = [[NSBundle mainBundle] pathForResource:#"1" ofType:#"mp3"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path],&soundID);
AudioServicesPlaySystemSound (soundID);
if (oneAudio) [oneAudio release];
NSError *error = nil;
oneAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (error)
NSLog(#"%#",[error localizedDescription]);
oneAudio.delegate = self;
[oneAudio play];
}
- (void)viewDidLoad {
[volumeSlider addTarget:self action:#selector(updateVolume) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
}
-(void)updateVolume {
[oneAudio, twoAudio, threeAudio, fourAudio, fiveAudio, sixAudio, sevenAudio, eightAudio, nineAudio, tenAudio, elevenAudio, twelveAudio, thirteenAudio, fourteenAudio, fifthteenAudio, sixteenAudio setVolume:volumeSlider.value];
}
This is the current method I've tried and it doesn't work. Thanks for the help
In updateVolume you can't call on multiple instances by listing them like that. What you should do is put all of these audio players into an array and loop through each and setVolume on each object in the array.

code to play sound programmatically using a button on the iphone

I am trying to figure out how to hook up a button to play a sound programmatically without using IB. I have the code to play the sound, but have no way of hooking the button up to play the sound? any help?
here is my code that I'm using:
- (void)playSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"boing_1" ofType:#"wav"];
AVAudioPlayer* myAudio = [[AVAudioPlayer alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:path error:NULL]];
myAudio.delegate = self;
myAudio.volume = 2.0;
myAudio.numberOfLoops = 1;
[myAudio play];
}
[button addTarget:self action:#selector(playSound) forControlEvents:UIControlEventTouchUpInside];
UIButton inherits its target/action methods from UIControl.
To hook up the button, make your playSound method the handler for the button's UIControlEventTouchUpInside event. Assuming this is in a view controller, you might want to put this in the viewDidLoad method:
[button addTarget:self action:#selector(playSound) forControlEvents:UIControlEventTouchUpInside];
FYI, you're leaking memory because you're alloc-ing an object but never release-ing it.
You should create a new AVAudioPlayer member for the class to avoid this.
#interface MyViewController : ...
{
...
AVAudioPlayer* myAudio;
...
}
- (void)playSound
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"boing_1" ofType:#"wav"];
[myAudio release];
myAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path error:NULL]];
myAudio.delegate = self;
myAudio.volume = 2.0;
myAudio.numberOfLoops = 1;
[myAudio play];
}
Don't forget to put [myAudio release] in your dealloc method.
(I did this without declaring myAudio as a #property, but that's not strictly necessary)