views:

1357

answers:

1

I'm trying to play a sound based on which button is pressed using AVAudioPlayer. (This is not a soundboard or fart app.)

I have linked all buttons using this code in the header file:

@interface appViewController : UIViewController <AVAudioPlayerDelegate> {

AVAudioPlayer *player;

UIButton *C4;
UIButton *Bb4;
UIButton *B4;
UIButton *A4;
UIButton *Ab4;
UIButton *As4;
UIButton *G3;
UIButton *Gb3;
UIButton *Gs3;
UIButton *F3;
UIButton *Fs3;
UIButton *E3;
UIButton *Eb3;
UIButton *D3;
UIButton *Db3;
UIButton *Ds3;
UIButton *C3;
UIButton *Cs3;
}

@property (nonatomic, retain) AVAudioPlayer *player;

@property (nonatomic, retain) IBOutlet UIButton *C4;
@property (nonatomic, retain) IBOutlet UIButton *B4;
@property (nonatomic, retain) IBOutlet UIButton *Bb4;
@property (nonatomic, retain) IBOutlet UIButton *A4;
@property (nonatomic, retain) IBOutlet UIButton *Ab4;
@property (nonatomic, retain) IBOutlet UIButton *As4;
@property (nonatomic, retain) IBOutlet UIButton *G3;
@property (nonatomic, retain) IBOutlet UIButton *Gb3;
@property (nonatomic, retain) IBOutlet UIButton *Gs3;
@property (nonatomic, retain) IBOutlet UIButton *F3;
@property (nonatomic, retain) IBOutlet UIButton *Fs3;
@property (nonatomic, retain) IBOutlet UIButton *E3;
@property (nonatomic, retain) IBOutlet UIButton *Eb3;
@property (nonatomic, retain) IBOutlet UIButton *D3;
@property (nonatomic, retain) IBOutlet UIButton *Db3;
@property (nonatomic, retain) IBOutlet UIButton *Ds3;
@property (nonatomic, retain) IBOutlet UIButton *C3;
@property (nonatomic, retain) IBOutlet UIButton *Cs3;

- (IBAction) playNote;

@end

Buttons are all linked to the event "playNote" in interfaceBuilder and each note is linked to the proper referencing outlet according to note name.

All *.mp3 sound files are named after the UIButton name (IE- C3 == C3.mp3).

In my implementation file, I have this to play a only one note when the C3 button is pressed:

#import "sonicfitViewController.h"

@implementation appViewController
@synthesize C3, Cs3, D3, Ds3, Db3, E3, Eb3, F3, Fs3, G3, Gs3, A4, Ab4, As4, B4, Bb4, C4;

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {

    NSString *path = [[NSBundle mainBundle] pathForResource:@"3C" ofType:@"mp3"];
    NSLog(@"path: %@", path);
    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];

    [super viewDidLoad];
}

- (IBAction) playNote {
    [self.player play];
}

Now, with the above I have two issues:

  • First, the NSLog reports NULL and crashes when trying to play the file. I have added the mp3's to the resources folder and they have been copied and not just linked. They are not in an subfolder under the resources folder.
  • Secondly, how can I set it up so that when say button C3 is pressed, it plays C3.mp3 and F3 plays F3.mp3 without writing duplicate lines of code for each different button? playNote should be like

    NSString *path = [[NSBundle mainBundle] pathForResource:nameOfButton ofType:@"mp3"];

instead of defining it specifically (@"C3").

Is there a better way of doing this and why does the *path report NULL and crash when I load the app?

I'm pretty sure it's something as simple as adding additional variable inputs to - (IBAction) playNote:buttonName and putting all the code to call AVAudioPlayer in the playNote function but I'm unsure of the code to do this.

A: 

Performing multiple actions with same selector is a common task. Just set a tag property for each button and use a NSArray of NSStrings to store file names. Your even need not create each button separately. See code sample for similar question http://stackoverflow.com/questions/2536350/problem-with-selector-in-iphone/2541844#2541844 answer.

Check if your files is realy copied to bundle. For example in simulator log your bundle directory with NSLog(@"myBundle:%@",[[NSBundle mainBundle] bundlePath]); and look at files.

Vladimir
Can the tag property be a string or does it have to be a number?
slickplaid
tag is integer property of UIView (and all descendants including UIButton) class. To use any other object (e.g. NSString) as a tag create NSArray of such object and access them with using tag as index. For example: [myString objectAtIndex:[myButton.tag]];
Vladimir