Thursday, February 05, 2009

Writing a Lullaby App for the iPhone

[Update: Lullabies is now in the app store. Check it out.]

I have 2 young children, and the familiarity and dexterity they show in using their parent's iPhones continues to amaze me. They can unlock the phone, find the YouTube app, and press on a video to play. And they are only 3 and 2 years old.

I have a brother, James Howes, who is an amazing singer, trying to make a name for himself singing opera in the Midwest. I would love to do something to advance his career.

One night, I came up with the idea of an app to help make babies sleepy, a lullaby app. Restful animations would play while Jim sang something sleep inducing. Originally, a friend of mine was going to do the animations, but he was too busy and I ended up doing the animations using CALayers and Core Animation, which was a first for me.

So here are some ideas about using CALayers on the iPhone. The first thing I did was open up Photoshop Elements and create a 320x480 document. I like Elements because it has simple vectored tools, its Save For Web... function creates excellent PNG files, and most importantly it is a layered editing program. Thus I can mock up my animation before I ever write a line of code to see what parts I need. So for a toy clock, I can combine, a background, a pendulum, a spinning moon dial, a spinning sun, and some foreground artwork. These are all exported from Elements as PNG files. PNG is the proper choice as it has decent compression while still having a transparency, and full color.

To form a toy clock of the kind one might see strapped to a crib.

If I add a layer of shadow—easily created with Element's color to transparent gradient tool—I am able to animate its opacity over the course of the animation ending with a night time scene. I like this gloaming effect better than simply making the whole scene uniformly dim.

Now that I had my parts together, I loaded each into a CALayer as so:

UIImage* moonsImage = [UIImage imageNamed:kMoonsName];
self.moonsLayer = [CALayer layer];
self.moonsLayer.contents = (id)moonsImage.CGImage; = kMoonsName;
self.moonsLayer.opaque = NO;
[self addSublayer:moonsLayer];
self.moonsLayer.zPosition = 2;
self.moonsLayer.contentsGravity = kCAGravityResizeAspectFill;
[self.moonsLayer addAnimation:[self spinningAnimation] forKey:@"transform"];

Note, I made use of the zPosition to make sure my parts are drawn in the right order, and that I have a method that creates a CABasicAnimation spinningAnimation. I made a variety of CABasicAnimations to rotate the moon layer, spin the sun and swing the pendulum. You might have noticed that the center of the sun is the center of the moon dial is the center of the clock as a whole is the rotation point of the pendulum. This is not a coincidence; it makes figuring things out a whole lot easier. The pendulum graphic I used extends from the rotation point to the tip of the pendulum, although most of it is transparent.

I also made animations of snow falling, and bubbles bouncing. The hard part was simulating a bubble's iridescence (rainbow effect) in the Core Animation on the iPhone, believe me it would have been easier if Apple provided support for a proper masking layer as they do on the desktop.

It was darn hard getting my brother's audio tracks. Singing lullabies is not part of his normal repertoire—Rossini is more his speed—and he had no easily available recording facilities. The first tracks he sent me sounded like they were sung in an oak closet (better known as my cousin's kitchen). But after a very long time, he delivered the tracks I wanted, and I think they sound pretty good:
Down in the Valley. Note that any imperfections are caused by my amateurish editing skills; Jim is a singing machine.

Thankfully, Apple brought out the AVAudioPlayer class in the 2.2 SDK. It makes playing music much easier than the previous method of messing with AudioQueues. So actually playing the music was falling off a log easy.

So that's that. It was great learning about Core Animation, and I've ended up making good use of the skills in a per hour job this last month. And I hope to make more children apps in the future. I just hope this one makes a little money along the way.