Use other method to play sound simultaneously - objective-c

I'm trying to play 2 different sounds simultaniously, which works perfectly when putting all code in 2 separate methods. Instead I thought creating a method which contains the soundplayer code and call that method from another with the song name as an argument. This a works ... almost.
Press button 1 -> sound one plays. Good!!!
Press button 2 -> sound1 stops and sound2 starts. Not Good!!!
How to make sound two to keep his/her fingers away from sound one.
Here's the code. It's probably a simple one, but I'm stuck for a while now.
.
.
.
-(IBAction) playSound1
{
NSString *nameOfSong = #"song1";
[self nowPlay:nameOfSong];
}
-(IBAction) playSound2
{
NSString *nameOfSong = #"song2";
[self nowPlay:nameOfSong];
}
-(void) nowReallyPlay:(NSString*) whatsTheName
{
NSURL *playSong = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:whatsTheName ofType:#"mp3"]];
self.soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:playSong error:nil];
soundPlayer.delegate = self;
soundPlayer.volume= 0.5;
soundPlayer.numberOfLoops = 0;
[soundPlayer play];
}
.
.
.

I solved it by defining 2 different AudioPlayers and select which one to play using if statements.
It works but still is not very sexy in my honest opinion. For my program (App for my little girl) it will do just fine, but what if one would want 25 sound playing at ones? Would you have to create 25 AVPlayers?
Is there another (sexier) way to take this hurdle ?
.
.
-(IBAction) playSound1
{
NSString *nameOfSong = #"song1";
NSString *playThis = #"first_song";
[self nowPlay:nameOfSong:playThis];
}
-(IBAction) playSound2
{
NSString *nameOfSong = #"song2";
NSString *playThis = #"second_song";
[self nowPlay:nameOfSong:playThis];
}
-(void) nowReallyPlay:(NSString*) whatsTheName : (NSString*) playWhat
{
if (playWhat == #"first_song")
{
NSURL *playSong = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:whatsTheName ofType:#"mp3"]];  
self.soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:playSong error:nil];
sound1Player.delegate = self;
sound1Player.volume= 0.5;
sound1Player.numberOfLoops = 0;
[sound1Player play];
} else if (playWhat == #"second_song"") {
NSURL *playSong = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:whatsTheName ofType:#"mp3"]];  
self.sound2Player = [[AVAudioPlayer alloc] initWithContentsOfURL:playSong error:nil];
sound2Player.delegate = self;
sound2Player.volume= 0.5;
sound2Player.numberOfLoops = 0;
[sound2Player play];
}
}
.
.

Related

freeing memory in a simple avaudioengine program?

I'm wondering how to free memory in this simple program that plays a file through a buffer and then stops it.
-(void)setupAudioOne
{
NSError *error;
BOOL success = NO;
_player = [[AVAudioPlayerNode alloc] init];
NSURL *hiphopOneURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Hip Hop 1" ofType:#"caf"]];
AVAudioFile *hiphopOneFile = [[AVAudioFile alloc] initForReading:hiphopOneURL error:&error];
_playerLoopBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[hiphopOneFile processingFormat] frameCapacity:(AVAudioFrameCount)[hiphopOneFile length]];
success = [hiphopOneFile readIntoBuffer:_playerLoopBuffer error:&error];
_engine = [[AVAudioEngine alloc] init];
[_engine attachNode:_player];
AVAudioMixerNode *mainMixer = [_engine mainMixerNode];
AVAudioFormat *stereoFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:2];
[_engine connect:_player to:mainMixer fromBus:0 toBus:0 format:stereoFormat];
[self startEngine];
}
Above is the general setup of the engine and the player node.
Then we implement the player with a play button:
- (IBAction)play:(id)sender {
if (!self.playerIsPlaying)
{
[self setupAudioOne];
[_player scheduleBuffer:_playerLoopBuffer atTime:nil options:AVAudioPlayerNodeBufferLoops completionHandler:nil];
[_player play];
}
}
And finally we stop the player with a stop button:
- (IBAction)stopHipHopOne:(id)sender {
if (self.playerIsPlaying) {
[_player stop];
}
playerIsPlaying is just a simple BOOL that determines if the _player is playing.
So basically my question is, when you hit the stop button as this program is written now, no memory will be freed.
Surely there is a simple line of code that I can add to the stop button that frees up the memory the engine and player is using?
Any thoughts?
Yes, there is. After stopping the player node, you can call:
[_engine disconnectNodeInput:_player];
[_engine detachNode:_player];
I saw you're also keeping a reference to the audio buffer, so you might want to nil that one as well. Let me know if that doesn't work for you. Something else could be leaking.

Display Image and play corresponding audio

I like to display and image and play corresponding audio file. But it is playing audio files first before displaying. I couldn't figure it what is wrong.
-(IBAction)playButton :(id)sender{
UIImage *imageA = [UIImage imageNamed:#"Image1.png"];
UIImage *imageB = [UIImage imageNamed:#"Image2.png"];
int randomAlphaNum = arc4random() % 2;
NSLog(#"%i", randomAlphaNum);
switch (randomAlphaNum) {
case 0:
imageView.image = imageA;
for (int i = 1; i <=5; i++) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/audioA.wav", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.volume = 0.5;
if (audioPlayer == nil)
NSLog(#"An audio error occured: \"%#\"", audioPlayer);
else
{
[audioPlayer play];
}
sleep(2);
}
return;
break;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
First of all I wouldn't recommend using sleep as it's going to chew up your main thread and make your UI unresponsive. I'd actually be curious if removing it alleviates your issue. There's a chance the app is flying through your code, playing the audio and is hitting the sleep command before the app can display the image on the screen. What happens if you remove sleep and only iterate through the for loop once?

NSString set from a url doesn't read?

I am having trouble getting my NSString to read my string that I have set. The play action is hooked to a UIButton OnTouchDown if it matters.
- (IBAction)play {
if (audioPlayer.playing == NO) {
urlSong = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
[audioPlayer release];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlSong error:&error];
audioPlayer.numberOfLoops = 0;
//if i set this line to stringSong = #"k"; then comment out the next line everything works fine
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
label.text = stringSong;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if ([stringSong isEqualToString:#"k"]){
label.text = #"audio stopped";
[audioPlayer stop];
}
}
When I run the code on my iPhone Xcode returns
EXC_BAD_ACCESS
on this line
if ([stringSong isEqualToString:#"k"]){
I know this is due to me trying to set the string from the url because when I plainly set my string to 'k' the code executes just fine.
If anybody is wondering the overall point of this, I am trying to have my audio buttons set to stop all other audio when this button is pressed and start the audio assigned to this button which in this case is 'k.mp3'. But if this audio is already playing just to stop playing all audio. Thank you.
You aren't retaining stringSong.
This line:
stringSong = [[urlSong lastPathComponent] stringByDeletingPathExtension];
Should be:
stringSong = [[[urlSong lastPathComponent] stringByDeletingPathExtension] retain];
At some point this needs to be released.

playing second Sound

am trying to do a simple AVAudioPlayer based application to play 2 different music upon button pressed, there is 2 views, the first is the home view contains 2 buttons,each button set a song which is named as integer(1.mp3, 2.mp3.....etc)and here'e the code
#import "podHome.h"
#import "podMusic.h"
#import "ArabAppDelegate.h"
#implementation podHome
#synthesize song1;
#synthesize tabi;
int CurrentPlay;
NSString *Currenttxt;
-(IBAction)uae{
CurrentPlay=1;
Currenttxt=#"uae";
podMusic *newContro=[[podMusic alloc] init];
[newContro setCurrentPlay1:CurrentPlay setCurrentText:Currenttxt];
ArabAppDelegate *theDelegate = (ArabAppDelegate*)[[UIApplication sharedApplication] delegate];
tabi = theDelegate.tabcontrolPod;
tabi.selectedIndex = 1;
[newContro release];
}
-(IBAction)libya{
CurrentPlay=2;
Currenttxt=#"uae";
podMusic *newContro=[[podMusic alloc] init];
[newContro setCurrentPlay1:CurrentPlay setCurrentText:Currenttxt];
ArabAppDelegate *theDelegate = (ArabAppDelegate*)[[UIApplication sharedApplication] delegate];
tabi = theDelegate.tabcontrolPod;
tabi.selectedIndex = 1;
[newContro release];
}
these tow (IBActions) are linked to the two buttons when pressing on one of them it will change to the other view and start playing the song
- (void)viewWillAppear:(BOOL)animated {
if((played == 1)&&(isBacked==FALSE)){
NSString *filePath = [[NSBundle mainBundle] pathForResource:texting
ofType:#"txt"];
NSString *filenameString = [NSString stringWithContentsOfFile:filePath usedEncoding:nil error:nil];
CurrentTex.text = filenameString;
AudioSessionInitialize(NULL, NULL, NULL, NULL);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,sizeof(sessionCategory), &sessionCategory);
AudioSessionSetActive(YES);
playBtnBG = [[UIImage imageNamed:#"play-pod.png"] retain];
pauseBtnBG = [[UIImage imageNamed:#"pause-pod.png"] retain];
[playButton setBackgroundImage:pauseBtnBG forState:UIControlStateNormal];
[self registerForBackgroundNotifications];
updateTimer = nil;
duration.adjustsFontSizeToFitWidth = YES;
currentTime.adjustsFontSizeToFitWidth = YES;
progressBar.minimumValue = 0.0;
NSString *path=[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%d",CurrentPlay] ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[player stop];
//self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self.player)
{
[self updateViewForPlayerInfo:player];
[self updateViewForPlayerState:player];
player.numberOfLoops = 0;
player.delegate = self;
}
[self startPlaybackForPlayer:player];
fileName.text= [[NSString alloc]initWithFormat:#"%#", songName];
// [fileURL release];
// CurrentPlay = 0;
isBacked = TRUE;
}
[super viewWillAppear:animated];
}
- (void)setCurrentPlay1:(int)varP setCurrentText:(NSString *)varT{
CurrentPlay = varP;
texting = varT;
played = 1;
isBacked = FALSE;
}
but the problem is that when the song is playing and am back to home view and pressing on the other song's button, it starts to play with the first one at the same time, i think the first should stop to begin the other, what should i release to do that???
My guess is that you have two instances of the AVAudioPlayer, and when you set them both to play, they both do!
One solution would be to tell other players to stop when you activate a new one, but that will quickly become troublesome as the number of players increases.
Instead you;'d be better of just setting up one player, and change it's song in accordance to what button was pressed. That way, there is no chance that two music tracks will play at the same time.
In your first button action write like this.
if(player2.isPlaying)
{
[player2 stop];
}
in the same way do the same thing in second button action like this.
if(player1.isPlaying)
{
[player1 stop];
}

Stopping all sounds at once?

Hello
I have 16 sounds in a view. And they loops etc. I want a rect button where you tap it all the sounds stop.
Here is the code i used for one of the sounds, its the same for the rest.#
- (IBAction)twoSound:(id)sender; {
if (twoAudio && twoAudio.playing) {
[twoAudio stop];
[twoAudio release];
twoAudio = nil;
return;
}
NSString *path = [[NSBundle mainBundle] pathForResource:#"2" ofType:#"wav"];
if (twoAudio) [twoAudio release];
NSError *error = nil;
twoAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (error)
NSLog(#"%#",[error localizedDescription]);
twoAudio.delegate = self;
[twoAudio play];
}
I tried
-(IBAction)goStop:(id)sender; {
[oneAudio, twoAudio, threeAudio, fourAudio, fiveAudio, sixAudio, sevenAudio, eightAudio, nineAudio, tenAudio, elevenAudio, twelveAudio, thirteenAudio, fourteenAudio, fifthteenAudio, sixteenAudio stop];
}
But that didnt work.
Thanks
I think you have to use an NSArray instead of many sound objects. So you can easily fill the array with the 12 sounds and then you can use a "for" cycle to stop them all.