Version 1.1 available on the App Store

June 24th, 2009 beardo No comments

I just got the email stating that version 1.1 is officially on the iTunes App Store. Here’s a list of what’s changed:

  • Fix game saving bug
  • Fix game over bug
  • Lose balloon power for wrong notes
  • Generally increase the speed (was way to slow on beginner)

I’m still working on 1.2 which should include a ton more features and hopefully only a few bugs.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

Two Week Sales Report

June 22nd, 2009 beardo No comments

uSightRead has been on the market for two weeks now, so how are sales? I’ve sold a total of 68 copies. Not too shabby. The estimated revenue is about 95 dollars (not taking into account currency conversions) which means that I’m about 6% towards my goal of paying for my MacBook. Of course, it takes a while for Apple to pay out, and you have to have more than $250 to trigger a payout. It’ll be a while before I actually see any money.

The one thing I haven’t done is spend much time on marketing. The most I’ve done was the guest post for 47hats, a post on the Business of Software forums, and one on Talk Bass to try and get some user feedback. The feedback has been awesome. One of the changes was to this website. A comment on 47hats said that if he came to the website and saw the development blog with all the code and such, that as a musician, he wouldn’t look any farther. To that end I’ve re-wickered the website to have a proper front page with this blog and a link from there.

We’ll see if that has any effect on my goal tracking. I just set it up in Google Analytics on the 16th, but there’s only been about 20 clicks on the “Buy Now” button. I think after I get done with the next version of uSightRead then I can start a big marketing push.  Try and make some annoucements on sites that target musicians rather than developers or MicroISV’ers.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

Do you hear what I hear?

June 19th, 2009 beardo No comments

One of the next big features I’m working on for the next version of uSightRead is sound. Now, this post isn’t about getting sound to play on the iPhone (which can be a pain in the arse), but about how I created the audio content for the game.

I wanted to have the actual notes play when the player gets the note correct. For the range of notes that I support (bass and treble clef) I needed 50 different notes. To create them I made a project in Cubase 5, simply entered the MIDI key editor and step-wise entered the notes I needed. I set the tempo so that each whole note would be one second long, and exported a wav file (16-bit, 22,050 sample rate). I thought it would be a simple matter of finding an audio splitting app, and breaking the one second chunks out of the large wav file.

Boy was I wrong. The first problem is that one note will “bleed” into the next note and can cause a small pop when cut into the one second chunks. Similarly, if the audio is in the middle of an up or down trend when it is cut at the end, a pop will occur because the sample goes from a high value or low value to zero immediately. This was not acceptable. I could get around these problems by exporting the notes one at a time, but I steadfastly refused to do this for 50 notes. Enter Python.

As of 2.6 Python has a built in wav file module called wave. To get around the first problem, I simply made the notes play for eight seconds, which allowed the notes to naturally decay before the next one started. The second problem required more work. I setup a Python script to break an audio file into one second chunks, and then scanned the last 5% of the file for a low point after which I simply zeroed out the samples. This eliminated any pops at the end. It also skips the middle seven seconds because I don’t need them. All-in-all it probably took me longer to make the script than to manually export the notes, but I also can re-do the entire operation with say, another instrument without any hassle.

Here’s the script:

import sys
import wave
import struct

notes = ['C', 'Cs', 'D', 'Ds', 'E', 'F', 'Fs', 'G', 'Gs', 'A', 'As', 'B'];

names = [];
for i in range(1,8):
  for note in notes:
    names.append("%s%d.wav" % (note, i));

inputFile = sys.argv[1];

print "Splitting file: " + inputFile;
inputWav = wave.openfp(inputFile, "rb");

print "n Frames: %d" % inputWav.getnframes();
print "Frame Rate: %d" % inputWav.getframerate();
print "Channels: %d" % inputWav.getnchannels();

totalSeconds = inputWav.getnframes() / inputWav.getframerate();
frameRate = inputWav.getframerate();
sampleWidth = inputWav.getsampwidth();

skipSeconds = 8;
for second in range(0, totalSeconds, skipSeconds):
  print "Part: %05d" % second;

  # determine the output file name
  name = "%05d.wav" % second ;
  if (len(names) > 0): name = names.pop(0);

  outWav = wave.openfp(name , "wb");
  outWav.setnchannels(1);
  outWav.setsampwidth(sampleWidth);
  outWav.setframerate(frameRate);

  outputFrames = inputWav.readframes(frameRate);
  packFormat = "%uB" % frameRate * sampleWidth;
  outputBytes = list(struct.unpack(packFormat, outputFrames));

  last = 0;
  previous = 1;
  first = frameRate * sampleWidth - int((frameRate * sampleWidth) * 0.05);
  for x in reversed(range(first, len(outputBytes) - 1, 2)):
    # The data was little endian, compute the sample value
    value = outputBytes[x] * 255 + outputBytes[x+1];
    if value < 50:
      last = x;
      break;

  outputBytes[last:] = [0 for x in range(last, len(outputBytes))];

  # write output
  outWav.writeframes(struct.pack(packFormat, *outputBytes));
  outWav.close();

  # skip intervening seconds
  for i in range(0, skipSeconds -1): inputWav.readframes(frameRate);

In the end it was pretty simple, but I haven’t done Python in about 8 years, and so there was a lot of internet-search based programming.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

Guest post for 47hats

June 16th, 2009 beardo No comments

I did a guest post for 47hats. It’s a website dedicated to MicroISVs and other small software business related stuff. If you’re a small software shop, you should check it out. The direct link to my post is here.

Meanwhile, I continue to add new features to uSightRead in preparation for the 1.2 release. I hoping to have it done and submitted to the App store in about two weeks. Unfortunately version 1.1 is still in review, so if you bought uSightRead and are waiting for the bug fixes, it’s coming.

Last night I did get sound working. Sound is not the easiest thing on the iPhone if you want to do anything remotely complicated. I may do a post on it, but right now I have a major head cold and can barely get my “day job” done much less anything else.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

A chicken in every pot, and a bug in every app

June 7th, 2009 beardo No comments

Alas, I am not a perfect coding machine. Two bugs were found in version 1.0 of uSightRead so I quickly fixed them and released version 1.1. First, the game was not correctly restoring the saved level and score when the user resumed from a saved game. Secondly, the “Game Over” screen wouldn’t disappear if you started a new game. Both were easily found and fixed. I added two enhancements as well. First, you lose balloon power when you misidentify a note, and second the note speed was generally increased. After playing for a while, easy was way too slow.

The upgrade has already been submitted to the iTunes store and will be available as soon as Apple approves it. On a brighter note (get it, note, music game, heh), I did manage to sell two copies of uSightRead on the first day. On top of that, only one of them was my wife!

I’ve also handed out some promo codes and the received positive feedback. Definitely encouraging.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

There’s an app for that

June 6th, 2009 beardo No comments

So let’s say you want a fun little game to learn to read music? There’s an app for that.

That’s right, uSightRead is live on the App store. It was submitted late Tuesday, and approved for sale on the following Saturday. That makes about four days from submission to approval. Not too shabby, although it is a simple game which probably aided in the quick review.

You can buy it here (opens iTunes). I’m so excited I may have just wet myself.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

The cost of making an iPhone App

June 5th, 2009 beardo No comments

While I’m playing the waiting game for my first application to be approved for the App Store, I thought I’d talk about what it costs to make an iPhone application. There’s a question on Stack Overflow that talks about it here. There’s cost dimensions to consider here, monetary cost and time cost. First the monetary costs.

Since I didn’t have a Mac, I had to purchase one. The iPhone SDK requires an Intel based Mac with OS X 10.5 installed (at the time of writing this). I looked around Craigslist and other such sites, but with the way Mac’s retain their value, I decided to just buy new. Fortuntely I got an educational discount thanks to my wife. The other major monetary cost is the $99 to join the iPhone Developer Program. Added with a few other things, the total cost is:

  • $1350 (Unibody MacBook, with tax)
  • $99 (iPhone Developer Program
  • $10 (usightread.com domain registration)

For a grand total of $1459. In my opinion, this is an extremely low number for starting a business. If you were starting from scratch in any other business, I don’t see how you could do it for any cheaper. I do get a break because I’m already paying for shared hosting, but that is only $10/month.

Secondly the time cost. This is highly variable depending on the skill of the individual making the application. I started with at least some background in Objective-C, and about 15 years of development experience which I think is a little above average for a starting iPhone developer. I would estimate the total time for creating uSightRead was about 50 hours. That includes the time to learn the Cocos2d-iPhone framework, create the artwork, and learn the nuances of iPhone development. I’d say that I spent at least 15 hours of that creating the artwork (Dammit Jim, I’m a developer not an artist). It doesn’t include the time to work through the my first iPhone sample app from Apple. If you figure about $40/hour for developer time, the monetary value of my time was $2,000.

My initial goal of this project was to break even on the monetary cost. With uSightRead slated to hit the App Store at $1.99 it seems reasonable. After Apple’s cut, my take would be $1.40 except that I still have to pay taxes on that. If I take 0.40 out for taxes, I’ll get approximately $1.00 per app. This makes the math easy and I’ll have to sell 1459 copies in order to cover my cost. Even if you take my time into accunt it’s only 3459 to break even. Only time will tell if this is a profit making venture.

One real time saver (and headache saver)  of using the App Store is that it totally eliminates the need to find a distribution channel or deal with payment processing. In other business, you’d have to setup a merchant account, and either handle the payment processing or pay someone to do that. Companies charge anywhere between 1% and 5% for payment processing services (usually on top of a $0.25-$0.75 per transaction fee). Of course Apple takes 30% so you may feel like your getting ripped off, but consider how long it would take you to get a piece of software into say, Best Buy. What percentage do you think they’d take if you could even get it in the store? I think 30% pretty fair for getting your app available to millions of potential customers.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

uSightRead submitted to the App Store

June 3rd, 2009 beardo No comments

Well, after about a month of hard after-hours work, version 1.0 of uSightRead has been submitted to the iTunes App Store. Hooray!

Now it’s just a waiting game for it to be approved. I’m really happy with the way it came out, and suprised at how easy it was to develop for the iPhone. There were some features that I cut out, but it just gives me a reason to keep going and to have additional releases. I already have plans for two more releases, but for now I’m going to take a little breather.

One other thing that I was having an issue with is setting up the bank information in App Store so that I could get paid. The issue is that they require a bank that has a SWIFT code. The SWIFT system is a proprietary international banking system that allows for money to be wire transfered across country borders. Most small banks (like the one I use) aren’t on the SWIFT system. I ended up opening an account specifically for the app store at Wells Fargo. Just a heads up for other budding iPhone developers out there.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

Labels, Menus, and Options in Cocos2d-iPhone

June 1st, 2009 beardo No comments

In my previous post I indicated that I was using the Cocoa Touch framework to do my menus and was having that interact with the Cocos2D-iPhone framework that I was doing to implement the actual game. This was a big mistake. After trying to get it all to interact correctly, I realized that I was “doing it wrong”. I ended up with a solution that added a blank UIView to the window, and then had to load up the other views. It was a mess and I still had the problem of the UIView overlay screwing up the touch events in Cocos2D-iPhone.

After decided there had to be a better way, I looked into the menu API in Cocos2D-iPhone. Turns out it is much easier, but to get good looking menu’s I’d need some more art. There are a few ways to make a menu with the API. First you can just use text and specify the menu name with a string. This is okay, but it really should look better for a game. Secondly, and the route I chose, is you can use images to display menu options. First I created some the images in Inkscape:

options_n

options_s

options disabled



The first image is the default display, second the image to display when selected (i.e. touched) and finally when the menu item is disabled. Here’s how to create a simple menu with these images:

/* Utility method to create a menu item assuming a naming convention */
- (MenuItemImage *)createMenuItem:(NSString *)prefix selector:(SEL)selector
{
	NSString *normal = [prefix stringByAppendingString:@"_n.png"];
	NSString *selected = [prefix stringByAppendingString:@"_s.png"];
	NSString *disabled = [prefix stringByAppendingString:@"_d.png"];

	MenuItemImage *result = [MenuItemImage itemFromNormalImage:normal
                                            selectedImage:selected
                                            disabledImage:disabled target:self selector:selector];

	return result;
}

// event handler...
-(void)showOptions:(id)sender
{
  [[Director  sharedDirector] pushScene:[OptionsMenuScene node]];
}

- (id) init {
    self = [super init];
    if (self != nil) {

      MenuItemImage *options = [self createMenuItem:@"options"
                                            selector:@selector(showOptions:)];
      Menu *menu = [Menu menuWithItems:optionsItem, nil];
      [menu alignItemsVertically];
      [self addChild:menu];
    }
}

It’s just that easy. I create a MenuItemImage using the three images, add it to a menu, and then add the menu to my scene. This example also takes advantage of the Menu class’s built-in layout facility. The event handler simply pushes another menu scene onto the scene stack. The documentation suggests that you avoid using the scene stack to save on memory, but I simply use it for the menus and it never gets more than 3 deep.

I also replaced the score display with a simple label:

scoreLabel_ = [Label labelWithString:@"Score: " dimensions:CGSizeMake(150,30)
                    alignment:UITextAlignmentLeft fontName:@"Helvetica"
                    fontSize:20.0];
[scoreLabel_ setRGB:0 :0 :0];
[scoreLabel_ setPosition:ccp(80, 300)];
[layer addChild:scoreLabel_];

// Then later to set the score:
[scoreLabel_ setString:[NSString stringWithFormat:@"Score: %d", score]]; 

The only thing interesting here is that I specify the width of the label, and make it left justified so that it renders how I need it to.

The last thing I did this weekend was to load and save game options. I used the built-in NSUserDefaults class to store and load the preferences. There are tons of examples out there, so I won’t bother repeating it here. I only have 7 more items on the list before I’m ready to release. Mostly it’s just some game mechanics and hooking up some more menus. I’m pumped.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit

Knocking on the door to success?

May 26th, 2009 beardo No comments

Got two opportunities over the long weekend to work on uSightRead. As of last night, the basic game works like a champ. Notes fly by, and the player must hit the correct note at the right time, and boom, they get points. I spent some time refactoring the code to support ledger lines for notes outside the staff. These are just sprites that follow along with the notes that are already there. The other thing I added was an overlay using Cocoa Touch. The overlay contains the score label, and a button for opening the settings.

I could have done the score and button with the Cocos2D-iPhone framework, but I didn’t really see anything that supported a button without having to build it up myself. I did find the Label class, so that would have worked for the score, but it seemed simpler to use Cocoa Touch. The one issue I had was if the UIView covered the entire surface, it would to throw off the touch handling withing Cocos2D-iPhone. To solve this, I simply made the UIView only take up the top 35 pixels of the app.

The only things left for the 1.0 release are to build the options/preferences menu, saving of those preferences (and high scores) and then some simple clean up of game mechanics (starting a new game, etc). I plan on releasing the 1.0 version and then providing free updates with new features. Lots of ideas, just not a ton of time to implement them. Hopefully by the end of the week I can have it submitted to the iTunes store and the button on the right will actually work :)

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Reddit