Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Hayden Kopser
Hayden Kopser
2,029 Points

Creating An Array With mp3 Sound Files

Hi, I am trying to build an app using the Crystal Ball App format but rather than using a label to reveal its predictions I want to create an array of mp3 sound files and then use either a UIButton or a touches event to play them back at random to the user. Does anybody know the most efficient way I could go about doing this?

3 Answers

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

@hayden this can be easily achieved. You would store the names of mp3 files without the mp3 extension in the array. So if your file is called "song.mp3" you would store only "song". You can play an mp3 file using the AVAudioPlayer class.

Let's say you accessed an object from your array containing filenames and stored it into a string called filename. Your code would look something like this:

NSString *mp3File = [[NSBundle mainBundle] pathForResource:filename ofType:@"mp3"];
AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
[avPlayer play];
Hayden Kopser
Hayden Kopser
2,029 Points

Thanks for responding Amit, I am a little confused, where exactly should I put that code? I created a new xcode project to practice making the sounds play, I have added 2 sound files to my project and #imported the <AVFoundation/AVFoundation.h> framework. I'll show you what I have declared in my header file

    @property (strong, nonatomic) NSArray *guySoundsArray;
    @property (strong, nonatomic) AVAudioPlayer *avPlayer;

    //I plan to implement this method that when called would trigger a sound to play
    -(void)playSound;

I synthesized my properties in the implementation file and created the guySoundsArray in viewDidLoad

  [super viewDidLoad];

    self.guySoundsArray =[[NSArray alloc] initWithObjects:@"Fanabla",
                                                          @"Hello", nil];

}

Then below the didReceiveMemoryWarning method I added this code

    -(BOOL)canBecomeFirstResponder{
    return YES;
    }

    //when called playSound method is supposed to play a random file from the guySoundsArray
    -(void)playSound{

    NSUInteger index = arc4random_uniform(self.guySoundsArray.count);
    NSString *fileName =[self.guySoundsArray objectAtIndex:index];
    NSString *randomMP3File = [[NSBundle mainBundle] pathForResource:fileName                  ofType:@"mp3"];

    AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL     fileURLWithPath:randomMP3File] error:NULL];

    [avPlayer play];

}

    -(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event

    -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{


        if(motion == UIEventSubtypeMotionShake){

        [self playSound];
    }

}

However the build fails when I try to run the program and I receive 2 warnings and 1 error

The warnings are at @implementation where is says 'Incomplete implementation' and at [avPlayer play] where is says 'Local declarations of 'avPlayer' hides instance variable

and then the error comes at the motionEnded:withEvent: method where it says 'Expected method body' but I thought I filled out the method body. I tried to call playSound from within that method.

How can I go about fixing this so that when motion ends the app will play a random sound clip from the array at a high volume? Should I randomize it using arc4random? For future reference, where in the implementation file should I implement my own methods, do they always need to be below didReceiveMemoryWarning?

I apologize for the extremely lengthy message but as I am beginning to develop my own apps and am comfortable with creating the UI, I want to build a good foundation and clear understanding of where and how to write the code and logic to bring my apps to life.

-Thank you very much for your help

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

@Hayden If this is your first time building an app then I recommend first going through the entire course and then customize the app.

The error seems like your two motion events seem to be nested within each other. You have a misplaced curly brace.

It should be like this:

-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
}

-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{

        if (motion == UIEventSubtypeMotionShake){
               [self playSound];
     }
}

The warning makes sense because you have declared a property as avPlayer and then you are declaring an instance variable avPlayer. In this case you can delete the property avPlayer and simply use the instance variable.