AVAudioPlayer - playing multiple audio files, in sequence - iphone

I want to play multiple MP3 files, in sequence (one after the other) , using AVAudioPlayer. I tried it, and it stops after playing the first MP3. However, if I go into debugger, it works fine.. any ideas? I read somewhere AVAudioPlayer plays audio in the background.. how do I prevent it from doing this?
Vas

I think the AVQueuePlayer (subclass of AVPlayer) does exactly this job (play a sequence of items) since iOS 4.1 :
http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVQueuePlayer_Class/Reference/Reference.html
I didn't try it myself however but will definitely give a try to it.

Use one AVAudioPlayer per sound.

Well, your code example didn't work out of the box for me. Soooo, I figured I'd respond with a fixed version:
Looper.h:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface Looper : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer* player;
NSArray* fileNameQueue;
int index;
}
#property (nonatomic, retain) AVAudioPlayer* player;
#property (nonatomic, retain) NSArray* fileNameQueue;
- (id)initWithFileNameQueue:(NSArray*)queue;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)play:(int)i;
- (void)stop;
#end
Looper.m:
#import "Looper.h"
#implementation Looper
#synthesize player, fileNameQueue;
- (id)initWithFileNameQueue:(NSArray*)queue {
if ((self = [super init])) {
self.fileNameQueue = queue;
index = 0;
[self play:index];
}
return self;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if (index < fileNameQueue.count) {
[self play:index];
} else {
//reached end of queue
}
}
- (void)play:(int)i {
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:[fileNameQueue objectAtIndex:i] ofType:nil]] error:nil];
[player release];
player.delegate = self;
[player prepareToPlay];
[player play];
index++;
}
- (void)stop {
if (self.player.playing) [player stop];
}
- (void)dealloc {
self.fileNameQueue = nil;
self.player = nil;
[super dealloc];
}
#end
And here's how I would call it:
Looper * looper = [[Looper alloc] initWithFileNameQueue:[NSArray arrayWithObjects: audioFile, audioFile2, nil ]];
I only have slightly over a year of experience with iPhone/iPad development using Objective-C so feel free to respond with additional criticism.

I've implemented a class to handle this.
To use just do something like this:
[looper playAudioFiles:[NSArray arrayWithObjects:
#"add.mp3",
[NSString stringWithFormat:#"%d.mp3", numeral1.tag],
#"and.mp3",
[NSString stringWithFormat:#"%d.mp3", numeral2.tag],
nil
]];
Looper.m
#import "Looper.h"
#implementation Looper
#synthesize player, fileNameQueue;
- (id)initWithFileNameQueue:(NSArray*)queue {
if ((self = [super init])) {
self.fileNameQueue = queue;
index = 0;
[self play:index];
}
return self;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if (index < fileNameQueue.count) {
[self play:index];
} else {
//reached end of queue
}
}
- (void)play:(int)i {
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:[fileNameQueue objectAtIndex:i] ofType:nil]] error:nil];
[player release];
player.delegate = self;
[player prepareToPlay];
[player play];
index++;
}
- (void)stop {
if (self.player.playing) [player stop];
}
- (void)dealloc {
self.fileNameQueue = nil;
self.player = nil;
[super dealloc];
}
#end
Looper.h
#import <Foundation/Foundation.h>
#interface Looper : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer* player;
NSArray* fileNameQueue;
int index;
}
#property (nonatomic, retain) AVAudioPlayer* player;
#property (nonatomic, retain) NSArray* fileNameQueue;
- (id)initWithFileNameQueue:(NSArray*)queue;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)play:(int)i;
- (void)stop;
#end

It is a good idea to initialize, prepare the items, and queue ahead of time, for example on the viewDidLoad method.
If you are working on Swift,
override func viewDidLoad() {
super.viewDidLoad()
let item0 = AVPlayerItem.init(URL: NSBundle.mainBundle().URLForResource("url", withExtension: "wav")!)
let item1 = AVPlayerItem.init(URL: NSBundle.mainBundle().URLForResource("dog", withExtension: "aifc")!)
let item2 = AVPlayerItem.init(URL: NSBundle.mainBundle().URLForResource("GreatJob", withExtension: "wav")!)
let itemsToPlay:[AVPlayerItem] = [item0, item1, item2]
queuePlayer = AVQueuePlayer.init(items: itemsToPlay)
}
and then when an event occurs,
queuePlayer.play()
Notice that if you use the queue, you still might have some gaps between the sounds.
You can find the Objective-C version in the question How to do something when AVQueuePlayer finishes the last playeritem
Hope it helps.

Related

Play two loops for .mp3 files together

Is there any way to play 2 loop for the sound file together in iphone sdk
Thanks & Regards
shweta
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface MultiAVPlay : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer* myplayer;
NSArray* fileNames;
int ind;
}
#property (nonatomic, retain) AVAudioPlayer* myplayer;
#property (nonatomic, retain) NSArray* fileNames;
- (id)initWithFileNameQueue:(NSArray*)names;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)play:(int)i;
- (void)stop;
#end
#import "MultiAVPlay.h"
#implementation MultiAVPlay
#synthesize myplayer, fileNames;
- (id)initWithFileNameQueue:(NSArray*)files {
if ((self = [super init])) {
self.fileNames = files;
index = 0;
[self play:index];
}
return self;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if (index < fileNames.count) {
[self playMp3:index];
} else {
//reached end of queue
}
}
- (void)playMp3:(int)i {
self.myplayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:[fileNames objectAtIndex:i] ofType:nil]] error:nil];
[myplayer release];
myplayer.delegate = self;
[myplayer prepareToPlay];
[myplayer play];
index++;
}
- (void)stop {
if (self.myplayer.playing) [myplayer stop];
}
- (void)dealloc {
self.filenames = nil;
self.myplayer = nil;
[super dealloc];
}
#end

AVAudioPlayer not responding to stop command?

I'm currently trying to use a custom class for the AVAudioPlayer and all works great for playing a audio file but when it comes to stoping the said file it just skips over the stop command and plays another on top of the current file,
If anyone has any ideas on why this is happening I'd really appreciate the help.
Below is my AudioPlayer1.h file:
#import <Foundation/Foundation.h>
#import "AVFoundation/AVAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#interface AudioPlayer1 : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
BOOL playing;
NSTimeInterval duration;
}
#property (nonatomic, assign) AVAudioPlayer *player;
#property(readonly, getter=isPlaying) BOOL playing;
#property (readonly) NSTimeInterval duration;
-(void)GetSoundFileDuration:(NSString *) sound_file_name;
-(void)play;
-(void)stop;
-(void)setVolume:(float) volume;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
- (void)PlaySoundFile:(NSString *) sound_file_name;
- (void)notPlaying;
#end
Below is the contents of AudioPlayer1.m file:
#import "AudioPlayer1.h"
#implementation AudioPlayer1
#synthesize player;
#synthesize duration;
#synthesize playing;
- (id)init
{
self = [super init];
if (self != nil)
{
player = [[AVAudioPlayer alloc] init];
[player initWithContentsOfURL:nil error:nil];
player.delegate = self;
}
return self;
}
- (void) setVolume:(float)volume
{
[player setVolume:volume];
}
- (void)PlaySoundFile:(NSString *) sound_file_name
{
[player stop];
NSURL *sound_file = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:sound_file_name ofType:#"mp3"]];
[player initWithContentsOfURL:sound_file error:nil];
[player prepareToPlay];
playing = YES;
[sound_file release];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"audioPlayerDidFinishPlaying");
playing = NO;
}
- (void) play
{
NSLog(#"Play Called");
[player setVolume:0.1];
[player play];
playing = YES;
}
- (void) stop
{
NSLog(#"Stop Called");
[player setVolume:0.0];
[player stop];
playing = NO;
}
-(void)GetSoundFileDuration:(NSString *) sound_file_name
{
NSLog(#"%#",duration);
}
-(void) notPlaying
{
playing = NO;
}
#end
And below is the code that would start the audio:
- (IBAction)WPNaritive01:(id)sender
{
AudioPlayer1 * player = [[AudioPlayer1 alloc] init ];
if (player.playing == YES)
{
[player stop];
}
if (player.playing == NO)
{
[player PlaySoundFile:#"1"];
[player setVolume:0.1];
[player play];
}
}
I apologize about the odd layout to the code as I'm still learning. I've only now found out about making these classes by chance from reading another question. lol
Ok, I've figured it out.
Rather than creating the object over and over like I was perhaps doing in the code above I should have been alloc and init the player in viewdidload rather than doing it in the IBAction like I did.
This is what I did incase anyone else comes across the same problem:
LockonLocation.h
#interface LockOnLocation : UIViewController {
AudioPlayer1 *player;
...
LockonLocation.m
- (void)viewDidLoad
player = [[AudioPlayer1 alloc] init ];
...
And I used the same code as above to play the audio so that was correct.
If anyone has any other advice for me or any other members I'd love to hear from you...

iOS : How to reference a music background from a singleton class?

I have done a singleton class called MyBgMusic.h & MyBgMusic.m. How to reference that singleton class to my SecondViewController or the rest of the XIB.
Here is my singleton class:
H file :
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface MyBgMusic : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
UIButton *playBgMusic;
}
#property (nonatomic, retain) IBOutlet AVAudioPlayer *player;
#property (nonatomic, retain) IBOutlet UIButton *playBgMusic;
+ (id)sharedManager;
-(IBAction) toggleMusic;
#end
M file :
#import "MyBgMusic.h"
static MyBgMusic *sharedMyManager = nil;
#implementation MyBgMusic
#synthesize player,playBgMusic;
#pragma mark -
#pragma mark Singleton Methods
+ (MyBgMusic*)sharedManager {
static MyBgMusic *sharedMyManager;
if(!sharedMyManager) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedMyManager = [[super allocWithZone:nil] init];
});
}
return sharedMyManager;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedManager];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#if (!__has_feature(objc_arc))
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (id)autorelease {
return self;
}
- (void)dealloc
{
[MyBgMusic release];
[playBgMusic release];
[player release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Custom Methods
- (IBAction)toggleMusic {
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate = self;
[player play];
player.numberOfLoops = -1;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
SecondViewController.m ( I want to reference from the singleton class so that I can use it all over again without mess up the background music when pressing on and off. )
- (IBAction)toggleMusic{
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
Should I declare like this :
-(IBAction) sharedMusic {
[[MyBgMusic sharedManager] toggleMusic]; // instance method shareManager not found. What does it mean?
}
Create an IBAction in your SecondViewController hook up the xib then in code then have it call
[[MyBgMusic sharedInstance] toggleMusic];
In SecondViewController you should call [[MyBgMusic sharedInstance] toggleMusic];in the IBAction when you want to toggle music. Just as you used self.player.
You have to import your class and reference it wherever you want using this line :
[[MyBgMusic sharedManager] toggleMusic]
If you want, you can add even property and reference it without create an instance of your class.

audioPlayerDidFinishPlaying never triggers

I created a custom class to handle audio playback.
AudioPlayback.h
#import <Foundation/Foundation.h>
#import "AVFoundation/AVAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#interface AudioPlayback : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
BOOL playing;
NSTimeInterval duration;
}
#property (nonatomic, assign) AVAudioPlayer *player;
#property (readonly) BOOL playing;
#property (readonly) NSTimeInterval duration;
-(NSTimeInterval)GetSoundFileDuration:(NSString *) sound_file_name;
-(void)PlaySoundFile:(NSString *) sound_file_name;
-(void)play;
-(void)stop;
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
#end
Then, in AudioPlayback.h
#import "AudioPlayback.h"
#implementation AudioPlayback
#synthesize player;
-(id)init
{
self = [super init];
if (self != nil)
{
player = [[AVAudioPlayer alloc] init];
[player initWithContentsOfURL:nil error:nil];
player.delegate = self;
}
return self;
}
-(void)PlaySoundFile:(NSString *) sound_file_name
{
NSURL *sound_file = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:sound_file_name ofType:#"mp3"]];
[player initWithContentsOfURL:sound_file error:nil];
[player prepareToPlay];
[player play];
[sound_file release];
}
...
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"audioPlayerDidFinishPlaying");
}
The callback never triggers. Am I missing anything obvious?
I think "player.delegate = self" is call too early. You "initWithContentsOfURL" again in your "PlaySoundFile", which I think that cause the problem.
Try to put "player.delegate = self" before the "[player prepareToPlay]" in your "PlaySoundFile" method

how to play audio file depending on the position of UIimageview which is moving by accelerometer

I wrote the following code
But still the Audio part is not responding
#import "AccelerometerViewController.h"
#implementation AccelerometerViewController
#synthesize imageView;
#synthesize player;
- (void)viewDidLoad {
UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 1.0f/60.0f;
carRadius = imageView.frame.size.width / 2;
delta = CGPointMake(12.0,4.0);
translation = CGPointMake(0.0,0.0);
[super viewDidLoad];
}
- (void)accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration {
if (acceleration.x>0) delta.x = 2; else delta.x = -2;
if (acceleration.y>0) delta.y = -2; else delta.y = 2;
[UIView beginAnimations:#"translate" context:nil];
imageView.transform =
CGAffineTransformMakeTranslation(translation.x, translation.y);
translation.x = translation.x + delta.x;
translation.y = translation.y + delta.y;
[UIView commitAnimations];
if (imageView.center.x + translation.x > 320 - carRadius ||
imageView.center.x + translation.x < carRadius) {
translation.x -= delta.x;
}
if (imageView.center.y + translation.y > 460 - carRadius ||
imageView.center.y + translation.y < carRadius) {
translation.y -= delta.y;
}
//playing Audio file to show warning if my car moved on to another lane
if (imageView.center.x + translation.x > 160)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"tone" ofType:#"m4r"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *p =[[AVAudioPlayer alloc]
initWithContentsOfURL:file error:nil];
[file release];
self.player = p;
[p release];
[player prepareToPlay];
[player setDelegate:self];
[self.player play];
}
}
Can any one please help me
Here are a few things to check: Make sure you have imported the AVFoundation framework into your project and that you have #import <AVFoundation/AVAudioPlayer.h> in your header file.
Move all of your [object release] methods to the bottom of the block. It should't make a difference but it's worth a try.
Are you using the latest version of iOS? 4.2.1 is the newest.
Make sure that your audio file is named precisely tone.m4r - it is case sensitive.
In the left sidebar, expand "Targets", then the name of your app, then "Copy Bundle Resources". Is the file tone.m4r in there? If not, drag it in.
Finally, why are you creating the AVAudioPlayer *p and then setting it equal to self.player (which I assume you've defined in your header file)? Instead, in your header file in #interface declare AVAudioPlayer *player; if you haven't already. After the #interface block but before the #end add #property (nonatomic, retain) AVAudioPlayer *player; if you haven't already.
Replace
AVAudioPlayer *p =[[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
[file release];
self.player = p;
[p release];
with
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
[file release];
Edits:
•You don't need [player setDelegate:self];
•Make sure you have self.player, not just player (shouldn't make a difference but it's more descriptive).
•I created a totally new, blank project to test your/my code. See below.
AudioTesterViewController.h:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface AudioTesterViewController : UIViewController {
AVAudioPlayer *player;
}
#property (nonatomic, retain) AVAudioPlayer *player;
- (IBAction)playAudio;
#end
AudioTesterViewController.m:
#import "AudioTesterViewController.h"
#implementation AudioTesterViewController
#synthesize player;
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)playAudio {
NSString *path = [[NSBundle mainBundle] pathForResource:#"tone" ofType:#"m4r"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
[path release];
self.player =[[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
[file release];
[self.player prepareToPlay];
[self.player play];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Notes:
-(IBAction)playAudio is called by a button I made in Interface Builder, but you can, of course, just make it a void function or copy the code into another function instead.
If this code doesn't work, try clicking in the menu bar Build->Clean and then running the project.
Here is my file structure: