views:

1640

answers:

1

I am using the AVAudioPlayer framework, and I have several sounds that play one at a time. When a sound is finished playing, I want the application to do something. I tried to use audioPlayerDidFinishPlaying to do the action at the end of the first sound, but I couldn't use that for the second sound because I got a redefinition error. Can I use NSTimeInterval to get the duration of a sound?

//  ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AVFoundation/AVAudioPlayer.h>

@interface ViewController : UIViewController {  
UIButton  *begin;
UIWindow  *firstTestWindow;
UIWindow  *secondTestWindow;
AVAudioPlayer *player;
NSTimeInterval duration;
}  

@property (nonatomic, retain) IBOutlet UIButton  *begin;
@property (nonatomic, retain) IBOutlet UIWindow  *firstTestWindow;
@property (nonatomic, retain) IBOutlet UIWindow  *secondTestWindow;
@property (nonatomic, retain)         AVAudioPlayer   *player;
@property (readonly)                NSTimeInterval  duration;


- (IBAction)begin:(id)sender;
- (IBAction)doTapScreen:(id)sender;

@end



//ViewController.m
#import "ViewController.h"

@implementation ViewController

@synthesize begin, player, firstTestWindow, secondTestWindow;

//first sound
- (IBAction)begin:(id)sender; {

    [firstTestWindow makeKeyAndVisible];
    NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource: @"Tone1"
                        ofType: @"mp3"];

    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

    AVAudioPlayer *newPlayer =
    [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                            error: nil];
    [fileURL release];
    self.player = newPlayer;
    [newPlayer release];

    [player prepareToPlay];
    [self.player play];

}

//If user does not do anything by the end of the sound go to secondWindow
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player
                    successfully: (BOOL) flag {
                               if (flag==YES) {
 [secondWindow makeKeyAndVisible];
    }
}

//second sound
- (IBAction)doTapScreen:(id)sender {
    //When user touches the screen, either play the sound or go to the next window
    if (self.player.playing) {
 [self.player stop];
 [thirdWindow makeKeyAndVisible];
    }

    else {
    NSString *soundFilePath =
    [[NSBundle mainBundle] pathForResource: @"Tone2"
    ofType: @"mp3"];

    NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];

    AVAudioPlayer *newPlayer =
    [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                               error: nil];
    [fileURL release];
    self.player = newPlayer;
    [newPlayer release];

    [player prepareToPlay];
    [self.player play];

}
}
+1  A: 

When a sound is finished playing, I want the application to do something.

Then set yourself as the delegate and respond to audioPlayerDidFinishPlaying:successfully:.

In the code snippet you showed, you've done step 2 but not step 1: You're not setting yourself as the delegate.

I tried to use applicationDidFinishLaunching to do the action at the end of the first sound …

Brain fart? That method has nothing that I can see to do with playing sounds.

…, but I couldn't use that for the second sound because I got a redefinition error.

Huh? Did you implement the method twice or something instead of just comparing the player object in the method body?

It would help if you showed the exact error message you got.

Peter Hosey
Oh! Yeah, I totally meant to say audioPlayerDidFinishPlaying, not applicationDidFinishLaunching. Sorry.I set the delegate to self, and it worked for the first sound. But the problem is not that audioPlayerDidFinishPlaying doesn't work, the problem is that I don't know how to do it again for a second sound. I have two different sounds.
Evelyn
By the way, when I put in [player setDelegate: self], I get the warning: "class 'ViewController' does not implement the 'AVAudioPlayerDelegate' protocol." Is that a problem?
Evelyn
You need to set yourself as both sounds' delegate. The sound will identify itself when it sends you a delegate message, so you can compare it to the sounds you have on hand.
Peter Hosey
As for the warning: It shouldn't break anything, but fix every warning anyway, so that you don't end up with 20 warnings you've been ignoring hiding something really important. You'll need to declare your class as conforming to that protocol.
Peter Hosey
Oh okay! That does work. Thanks. :) I wish I could do a different action for different sounds, though. I can only do the same action for both sounds using that method.(I just have one more question: is there any way for me to use NSTimeInterval to get the duration of a sound? Because that value would be very useful to me in other functions.)
Evelyn
“is there any way for me to use NSTimeInterval to get the duration of a sound?” NSTimeInterval is just a primitive type of number. It can't do anything. You can, however, ask the AVAudioPlayer for its duration. See the documentation: http://developer.apple.com/iphone/library/documentation/AVFoundation/Reference/AVAudioPlayerClassReference/
Peter Hosey
“I wish I could do a different action for different sounds, though.” You can act conditionally in the delegate method. Ask the player about itself and react to its response, or have two instance variables holding two players, and use the `==` operator to determine which one is talking to you.
Peter Hosey
Cool! Thanks. Could you give me any sample code for duration in AVAudioPlayer? That document only gives me the property declaration. Say for example I want a window to appear after the sound has been playing for 15 seconds. How do I do that in code?
Evelyn
It's a property, so you access it like any other property. If you don't know how to do that, consult the Objective-C 2.0 Programming Language: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/
Peter Hosey
As for making something happen after that many seconds: I'd use NSTimer. (Just remember to invalidate the timer if you pause the player, and re-create it when you resume it.)
Peter Hosey