How to play more than two songs using AVAudioPlayer - iphone

I want to play more than two song in my app. how do I can do it using AVAudioPlayer ?

I was going to type up the answer, but google provides a perfectly good answer:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/27285-play-sequence-audio-files-avaudioplayer.html
The first piece of code from the page will just call all the sounds in sequence:
- (void)playSoundSequence {
// Make array containing audio file names
NSArray *theSoundArray = [NSArray arrayWithObjects:#"one",#"two",nil];
int totalSoundsInQueue = [theSoundArray count];
for (int i=0; i < totalSoundsInQueue; i) {
NSString *sound = [theSoundArray objectAtIndex:i];
// Wait until the audio player is not playing anything
while(![audioPlayer isPlaying]){
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:sound ofType:#"wav"]] error:NULL];
self.audioPlayer = player;
[player release];
[audioPlayer setVolume:1.0f];
[audioPlayer play];
//Increment for loop counter & move onto next iteration
i++;
}
}
}
But, you are probably better off using an AVAudioPlayerDelegate:
If you don't want to wait in the loop, you can also make your
controller an AVAudioPlayerDelegate and implement
Code:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
This will be called when the end of the audio file is reached, at
which point you would start playing the next audio file.
audioPlayerDidFinishPlaying will then be called again when that one
finishes playing, and you start the next one after that, etc.

Related

iOS Stop Audio Playback At Certain Time (AVAudioPlayer End Time)

I'm wanting to play just part of an audio file. This audio file contains 232 spoken words, I have a dictionary that contains the start time of each word. So I have the start and stop times I just can't find a way to stop at a given time or play the file for a certain duration. Any advice and/or sample code to help me would be much appreciated, thanks Jason.
So I've found a solution, there's a problem with how I get endTime but I sure I can fix it.
//Prepare to play
[audioPlayer prepareToPlay];
//Get current time from the array using selected word
audioPlayer.currentTime = [[wordsDict objectForKey:selectedWord] floatValue];
//Find end time - this is a little messy for now
int currentIndex = 0;
int count = 0;
for (NSString* item in wordsKeys) {
if ([item isEqualToString: selectedWord]) {
currentIndex = count+1;
}
count++;
}
//Store found end time
endTime = [[wordsDict objectForKey:[wordsKeys objectAtIndex:currentIndex]] floatValue];
//Start Timer
NSTimer * myAudioTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(checkCurrentTime)
userInfo:nil
repeats:YES]
//Now play audio
[audioPlayer play];
//Stop at endTime
- (void) checkCurrentTime {
if(audioPlayer.playing && audioPlayer.currentTime >= endTime)
[audioPlayer stop];
}
This should do what you want. you don't need a repeating timer that's thrashing the player.
NSString *myAudioFileInBundle = #"words.mp3";
NSTimeInterval wordStartsAt = 1.8;
NSTimeInterval wordEndsAt = 6.5;
NSString *filePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:myAudioFileInBundle];
NSURL *myFileURL = [NSURL fileURLWithPath:filePath];
AVAudioPlayer *myPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:myFileURL error:nil];
if (myPlayer)
{
[myPlayer setCurrentTime:wordStartsAt];
[myPlayer prepareToPlay];
[myPlayer play];
[NSTimer scheduledTimerWithTimeInterval:wordEndsAt-wordStartsAt target:myPlayer.autorelease selector:#selector(stop) userInfo:nil repeats:NO];
}
Try using AVPlayer instead and make use of
addBoundaryTimeObserverForTimes:queue:usingBlock:
What it does: Requests invocation of a block when specified times are traversed during normal playback.
https://developer.apple.com/library/prerelease/ios/documentation/AVFoundation/Reference/AVPlayer_Class/index.html#//apple_ref/occ/instm/AVPlayer/addBoundaryTimeObserverForTimes:queue:usingBlock:
The AVAudioPlayer gives you some neat properties to work with:
currentTime: during playback you can rely on this property.
playAtTime : starts playing from a pre-defined time.
But first of all I would write some helpers for that:
#interface Word {
double startTime;
double endTime;
}
#property double startTime;
#property double endTime;
#end
This is just a class to simply working with the following method.
- (void)playWord:(Word *)aWord {
self.avPlayer.playAtTime = aWord.startTime;
[avPlayer prepareToPlay];
[avPlayer play];
while (avPlayer.playing) {
/*
This while loop could be dangerous as it could go on for a long time.
But because we're just evaluating words, it won't be as much power draining
*/
if(avPlayer.currentTime >= aWord.endTime;
[avPlayer stop];
}
}
I would suggest you to use an array or any other mechanism to automatically switch to the next word. Maybe your could also add a Previous and Next button for handling user input.
Please let me know if that worked for you.
HTH

Can not call method from another view controller in Objective C, iPhone SDK

At my StartWorkoutViewController.m I trigger:
#import "WorkoutViewController.h"
#implementation StartWorkoutViewController
- (IBAction) start
{
[firstViewController performSelector:#selector(callMyAction)];
WorkoutViewController *ViewCon = [[WorkoutViewController alloc]init];
[ViewCon callMyAction];
[ViewCon release];
}
then at my WorkOutViewController.h I added this:
- (void)callMyAction;
and at my WorkOutViewController.m I added this:
#import "StartWorkoutViewController.h"
-(void)viewWillAppear:(BOOL)animated{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/achtergrondgeluid.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = -1;
[audioPlayer play];
}
-(void)callMyAction{
NSLog(#"suckers");
[audioPlayer pause];
}
Now my NSLog (#"suckers") triggers very well from the StarWorkoutViewController, but for some reason the audioPlayer does nothing, any idea? Also setting labels in the Workout ViewController from the callMyAction in this file. Don't work! Any idea? Thanks!
The reason nothing is happening is because your are calling the pause method before the player even starts playing. viewWillAppear does not get called until it is visually on the screen. It actually doesn't always get called even then but that is another issue entirely. So if you want to pause the player it needs to actually be playing. If you put that viewWillAppear code in viewDidLoad it will probably work as expected.
Currently your code is doing this:
Load WorkoutViewController
Pause Audio
WorkourViewController become visible (actually this may never happen as I am not seeing it being added to any windows or anything).
Plays audio.

didSelectRowAtIndexPath - access tapCount or similar

I'd like to control an instance of AVAudioPlayer from a UITableView item in a didSelectRowAtIndexPath instance.
First touch of the row item triggers 'play' of the AVAudioPlayer. Second touch of the row item triggers 'stop' of the AVAudioPlayer.
I can make the 'play' work but can't get the 'stop' to work. Also, subsequent touches of the row item starts another thread of the audio in the background.
What's the best way to ensure 1 tap starts the audio and a 2nd tap stops it?
Code samples - this method preps audio file and AVAudioPlayer for use:
- (void)makeReadyAudio {
NSString *path = [[NSBundle mainBundle] pathForResource:#"Murderers" ofType:#"mp3"];
NSURL *url = [NSURL fileURLWithPath:path];
NSError *error;
musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
[musicPlayer prepareToPlay];
}
This block will start & stop the AVAudioPlayer within a case statement in the didSelectRowAtIndexPath section:
case 7: {
//touch to start audio sound playing, touch again to stop playing
[self makeReadyAudio];
if ([musicPlayer isPlaying]) {
[musicPlayer stop];
NSLog(#"musicPlayer tested to be playing, so stop it.");
} else {
[musicPlayer play];
NSLog(#"musicPlayer tested to be *not* playing, so play it.");
}
break;
}
How about:
- (void) didSelectRowAtIndexPath:
{
if (player.isPlaying) {
[player stop];
} else {
[player start];
}
}
In other words, keep the player around and see what it is doing.
The problem is that you call makeReadyAudio every single time the row is tapped. You need to check if you have already done that. For example by doing something like:
if (musicPlayer == nil) {
[self makeReadyAudio];
}

AVaudioPlayer regarding song overlapping

I have using AVAudioPlayer in my app but the problem is that when i play the song from list it will played while before stopping the song i am again goes to song list then select another song then both song will start playing simultaneously so please tell me the code which will terminate my first song.
I use flag variable for initializing the song file---
fileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#" Om Namo" ofType:#"aac"]];
self._player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self._player)
{
_fileName.text = [NSString stringWithFormat: #"%# (%d ch.)", [[self._player.url relativePath] lastPathComponent], self._player.numberOfChannels, nil];
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
}
[fileURL release];
break;
Play and push function---
- (void)startPlayback
{
if ([self._player play])
{
//[self stop];
[self updateViewForPlayerState];
self._player.delegate = self;
}
else
NSLog(#"Could not play %#\n", self._player.url);
}
- (void)pausePlayback
{
[self._player pause];
[self updateViewForPlayerState];
}
I also make stop function---
-(void)stop
{
[_player release];
self._player=nil;
}
Please help me .
Is correct my stop function.
and where i put our stop function or any other solution to fix this problem...
I can think of 3 things :
1) You can make code look like code by putting 4 spaces infront of each line. The reason you've gt no answers so far is probably because your question is almost unreadable ;)
2) In your stop method you might want to try this :
- (void) stop {
[_player stop];
self._player = nil;
}
3) Apple highly discourage using an underscore in front of member names. I've never run into problems but I'd rename _player to player.

Can you see anything wrong in this code?

NSString *path = [[NSBundle mainBundle] pathForResource:[arraySub objectAtIndex:indexPathHere.row] ofType:#"mp3"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
self.player = myPlayer;
[player prepareToPlay];
[player setDelegate:self];
[self.player play];
NSTimeInterval lenghtMusic = player.duration;
if (player.currentTime == lenghtMusic) {
NSLog(#"It worked");
[tableThing deselectRowAtIndexPath:indexPathHere animated:YES];
[myPlayer autorelease];
[file autorelease];
}
Can you see anything wrong?
Apparently, the "if"-statement never gets called...
If I read your code correctly you are trying to find out when the player has finished playing and then you want to deselect the current rode and release the player. Your problem is that you start the player and then immediately checks where it is currently playing. Unless you have an almost 0 length file the currentTime and length will NEVER be equal.
If that is what you are trying to do you should use the AVAudioPlayerDelegate Protocol and especially the:
– audioPlayerDidFinishPlaying:successfully:
method that is called when the player is finished.
So you need to change your class that controls the player by editing the .h file to use the AVAudioPlayerDelegate Protocol. Obviously keep extending whatever you were before.
#interface YourClass <AVAudioPlayerDelegate>
#end
In your .m file:
Then when you have created and assigned your player instance:
[player setDelegate:self];
In the .m file also add the method
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Your success code goes here
}
You are comparing double's with ==, which is almost always false due to round-off errors.
Compare with a range e.g.
if (fabs(player.currentTime - lenghtMusic) < 0.0001) {
...
}
I'm a noob iPhone dev, but are you sure that player.currentTime is a NSTimeInterval? That looks like the most obvious candidate.
Also, I'd log out what your player.currentTime is and what lenghtMusic is before your if and that'll probably let you know what's going on.