Jesse’s Random Thoughts

 
« Back to blog

Jumping Sounds on the iPhone

I went as Mario for Halloween 2009. While it was a blast running around looking for overalls and red baseball caps, my favourite part of the costume was a finishing touch I put together at the last minute: an iPhone app that made the Mario jumping sound when I jumped. The code behind the scenes is not beautiful or especially robust, but it worked. I thought I'd share a bit about how I put it together.

The first thing I needed was a way to find out what happens when you jump. A quick implementation of the UIAccelerometerDelegate lets you see what happens when you shake the phone around:

 
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
{ 
    NSLog(@"%lf %lf %lf %lf\n", acceleration.x, acceleration.y, acceleration.z, acceleration.timestamp); 
} 

The only problem here is that you can't jump while your iPhone is attached to your computer with a short cord, and if you unplug that cord, you can't see the log output. So, my quick-and-dirty solution was to write the acceleration info to a file and add a button to the app that lets you dump that file to the log output:

 
- (void)viewDidLoad { 
    [super viewDidLoad]; 
 
    history = [[NSMutableString alloc] init]; 
} 
 
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
{ 
    [history appendFormat:@"%lf %lf %lf %lf\n", acceleration.x, acceleration.y, acceleration.z, acceleration.timestamp]; 
} 
 
// Called when we're terminating 
- (void)save 
{ 
    [history writeToFile:[self savePath] atomically:NO encoding:NSUTF8StringEncoding error:nil]; 
} 
 
// Called from UI when user pushes the button 
- (IBAction)printIt:(id)sender 
{ 
    NSString *saved = [NSString stringWithContentsOfFile:[self savePath]]; 
    NSLog(@"%@", saved); 
} 

Pretty straight forward: I just make a mutable string, append to it, and save it when the app terminates. You can then plug it into your computer, run the app again and press a button to have it get dumped to the console. We throw that data in a spreadsheet, and we get to look at it:

This is a brief recording of my jumping around. You can see that one axis (the one pointing vertically) moves quite a lot while jumping. This makes it really easy to detect a jump. Now, if this was for something more important than Halloween, you might consider all kinds of metrics for deciding when a jump occurred, depending on what other kinds of noise you might see. For this purpose, though, I just looked at this graph and decided to jump when the acceleration passes 2.0 in the vertical axis.

I used the AVAudioPlayer class to handle the audio playing, simply triggering when we hit a threshold of 2. Now, if you look back at the graph, you'll see that wasn't an especially good choice: we hit the same threshold when we land simply because we hit the ground fairly hard. The result was that we ended up hearing the sound twice. My solution: simply wait for at least a second between sounds. Assuming I didn't have a full second hang-time, this would work fine:

 
- (void)viewDidLoad { 
    // ... 
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:nil]; 
    lastSound = [[NSDate distantPast] retain]; 
    // ... 
} 
 
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration 
{ 
    // ... 
 
    if ([[NSDate date] timeIntervalSinceDate:lastSound] > 1) { 
        if (acceleration.y > 2.0) { 
            [player play]; 
            [lastSound release]; 
            lastSound = [[NSDate date] retain]; 
        } 
    } 
} 

There was one last niggling problem: the sound for the first jump was delayed. After some digging around, it appears this was caused by loading the sound file before the first jump. When you create an AVAudioPlayer, it doesn't actually load the sound - it just gets ready to load it. You have to call prepareToPlay on the sound first. After adding that call in, everything worked nicely.

There are a few other touches, including the code I've simply left out, in the final project. If you want to play around with it, you can grab a copy of it below. Enjoy!

Click here to download:
Mario.zip (27 KB)

Loading mentions Retweet

Comments (0)

Leave a comment...

 
To leave a comment on this posterous, please login by clicking one of the following.
Posterous-login     twitter