Saturday, October 31, 2009

More details on AutoScrollLabel usage

Here are some screenshots demonstrating how to integrate the AutoScrollLabel class into an iPhone XCode project using Interface Builder.

1) Add the AutoScrollLabel class files to your project and add an outlet for the scrolling text. Save the files. Otherwise the next steps won't work.



2) Add a UIScrollView to your view using Interface Builder. Then, using the Inspector, change the class type to AutoScrollLabel.



3) Right click on the scrolling label and assign a referencing outlet to be the outlet you added in step 1.



4) Add code to your view controller class to set the text and other properties for the autoScrollLabel.



5) Compile your project and the autoScrollLabel should now be scrolling like a marquee.

And in case that's not clear, here's a (silent) video demonstrating the same thing. (You might want to bump the video to fullscreen so the text is readable.) Enjoy!

AutoScrollLabel Demo from Brian Stormont on Vimeo.

Friday, October 30, 2009

A simple scrolling UILabel for iPhone devs

Here's a simple class which mimics the most common features of a UILabel, yet will act like a horizontally scrolling marquee. It is actually a subclass of UIScrollView, so to use it with Interface Builder, you will need to create a UIScrollView item and then change its class to this class - which I called AutoScrollLabel.

If you don't care about the technical details of how it works and just want to use it, you can download the class files here:

http://stormyprods.com/sampleCode/AutoScrollLabel.zip

To use the class, simply set the text and if the text is wider than the allocated space in the view, it will automatically scroll. Here's a very simple example:


autoScrollLabel.text = @"Hi Mom! How are you? I really ought to write more often.";
autoScrollLabel.textColor = [UIColor yellowColor];


The class also supports the font property, so you can set the font as you normally would for a UILabel.

In addition, there are a few properties related to the scrolling:

scrollDirection: set to AUTO_SCROLL_LEFT (default) or AUTO_SCROLL_RIGHT
scrollSpeed: set to the number of pixels per second (default is 30)
pauseInterval: set to the number of seconds to pause when the end of the text is reached. (default is 0.5)
bufferSpaceBetweenLabels: how much blank space between the end of the text and the beginning of the next instance

It turns out this autoscrolling feature was fairly easy to implement. I'm surprised there isn't already something like this in the SDK. The scrolling is implemented using two UILabels contained in a UIScrollView. Each label contains an identical copy of the text and the labels are resized to be just large enough to hold the text without any truncation.

If the text in the UILabel is wider than the containing UIScrollView, then the two UILabels are laid out side-by-side, and the scroll view is animated to scroll from the beginning of one label to the beginning of the next label. The second label is there just to give the illusion of the text looping forever.

The class registers itself as the delegate for the scrolling animation block, so when the animation block ends, it waits the defined pause time, and then just performs another animated scroll, in which case the scroll view is reset back to the beginning of the first label and the process is repeated.

And that's it! Pretty simple. The animation block feature of a UIView does all the hard work.

I hope others find this useful. If you notice any problems in the code, please let me know.

Monday, October 26, 2009

Time Bomb v2.0 - Now Available on iTunes


A new update for Time Bomb is now available for download on iTunes. This update adds support for OpenFeint. You can now compare your fastest times to players around the world, send challenges and counter-challenges to friends, and unlock dozens of achievements.

You can read the full details about the game at TimeBombGame.com.

Friday, October 23, 2009

DevDiary: Artificial Life 1.5 progress

I'm making decent progress with the updates for the newest update of my Artificial Life iPhone app. I've completed the chromosome rule editing, so it will now be possible to edit a protozoa and give it whatever behavior you want!

Here are some screenshots of the new rule editing:





The rules can be dragged to be reordered as well.

I have a few more minor changes to make, and then hopefully will be submitting this update to Apple today. There are a lot more new features I plan on adding in future updates, but this update has been delayed so long I figure it is best to make it available now. I only have a small amount of time to work on this project during the downtime between other clients' projects.

Here's a short video demonstrating the rule editing:

Wednesday, October 21, 2009

Supporting AAC+ via the iPhone SDK

I've been asked a few times about how I've managed to support AAC+ v1 (also known as HE AAC v1) using the iPhone SDK. Even though AAC+ has been supported since iPhone OS 2.2, the process is not currently documented well at all in Apple's iPhone documentation. About 6 months ago, when I had a project requiring AAC+ support, I ended up using one of my iPhone Developer tech support credits to get an answer from Apple. Even then, the answer provided by Apple was fairly vague and it took a few more hours of tinkering for me to get things working.

Since it's apparently still not a well documented procedure, I figured I should share this information. I may be shooting myself in the foot competitively - AAC+ isn't something every radio app currently supports - but I do try to share with the developer community. AAC+ support isn't meant to be some secret feature usable only by some developers - it's officially supported by the SDK. It's just that the documentation is lacking.

This is not meant to be a full tutorial of using the iPhone SDK audio streams and queues. I am assuming you can already play standard audio streams in your app.

When you receive the audiostreamproperty notification for an AAC+ stream, initially the stream property will be AAC. You'll then need enumerate the kAudioFileStreamProperty_FormatList for that property. Retrieve the format list via a call to AudioFileStreamGetProperty(). Loop through the format list and if the stream is in AAC+ format one of the format IDs will be kAudioFormatMPEG4AAC_HE. This is the descriptor you'll need to use for AAC+ support when you call AudioQueueNewOutput().

This last point is key! You must use this new descriptor pulled out of the format list to create your audio queue. If you use the original descriptor, you will only be creating an AAC audio queue rather than an AAC+ one.

Oh, and don't expect this to work on the simulator. For some reason HE AAC is only supported on the real iPhone hardware - the simulator will never return a result of HE AAC - at least it didn't under 2.2.1. I haven't re-tested with any of the 3.x sims.

Also note that the SDK currently only supports AAC+ v1 with SBR (Spectral Band Replication). The PS (parametric stereo) feature of AAC+ v2 does not work and results in a mono audio playback. Also, the AAC+ support only works on OS 2.2 and higher.

Here's an example of how I detect the HE AAC descriptor in an audiostreamproperty notification handler . It's just a snippet of code taken out of context, but hopefully gives you an idea of how it is done:

AudioStreamBasicDescription asbd;
UInt32 asbdSize = sizeof(asbd);
UInt32 formatListSize;
Boolean writable;

err =
AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);
if (err) { /* do something for an error */ }

err =
AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, &writable);
if (!err) {

        
// get the FormatList data
        void* formatListData = calloc(1, formatListSize);
        err =
AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, formatListData);
        
if (err) { PRINTERROR("get kAudioFilePropertyFormatList"); free(formatListData); ; }
        
        
// Scan through all the supported formats and look for HE AAC
        for (int x = 0; x < formatListSize; x += sizeof(AudioFormatListItem)){
                
AudioStreamBasicDescription *pasbd = formatListData + x;
        
                
if (pasbd->mFormatID == kAudioFormatMPEG4AAC_HE){
                        
NSLog(@“Found HE AAC!");
                        
// HE AAC isn't supported on the simulator for some reason
                        if (!TARGET_IPHONE_SIMULATOR){
                                
memcpy(&asbd, pasbd, sizeof(asbd));
                        }
                        
break;
                }                                
        }
        
free(formatListData);
}

Wednesday, October 14, 2009

Tunemark Radio 1.0.3 has been released!

The latest update for the FREE Tunemark Radio app is now available on iTunes. This update includes some improvements to the clock-radio feature.

I've added a "sleep" timer so you can have the app automatically stop playing music after a preset amount of time.

The alarm now has a failsafe mechanism to play a built in audio tone if the radio station you selected for wake-up is not accessible due to network problems. Also, the alarm has a "Snooze" button so you can choose to go back to sleep for another 10 minutes.

And lastly, the alarm no longer requires the device to plugged into a charger in order for it to work.

As always, this app will remain FREE with no banner ads. If you have additional suggestions for improvements, please let me know.

You can read more about the app here: http://stormyprods.com/products/tunemark_radio.php

Wednesday, October 7, 2009

Balancing views of making money in the App Store

I find these two articles interesting reading. One is a very positive uplifting article regarding the opportunities writing iPhone apps (written by someone who has had a #1 ranked game and is obviously making decent money) and the second is by Newsweek, putting a more somber tone on the idea of trying to make money in the Apple App Store.

http://criticalthoughtgames.com/node/109

http://www.newsweek.com/id/216788/output/print

My personal opinion? Both articles make valid points. I'm not expecting to become a millionaire via the iPhone. I originally quit my job over a year ago to pursue a more challenging career and try to make it on my own doing freelance development. The iPhone is just one platform I was going to use. As it turned out, iPhone development turned out to be very interesting and enjoyable platform to use (even with all the frustrations the come with having to deal with Apple's review process) and I've been able to stay afloat financially concentrating solely on it for the past year. But, when I say stay afloat - I mean just that. I'm making about 1/4 of the salary I was making as a senior software engineer at a corporation. My revenue now is pretty much equal to my expenses - my bank account is about the same as it was when I first quit my job a year ago.

Looking out a little more long term, I don't think I'll continue to focus primarily on the iPhone. The income I am getting is just barely meeting expenses and it doesn't make financial sense to continue the sole iPhone focus indefinitely. At some point I will start working on other platforms to see if something else is a bit more financially viable. I'm not looking to get rich, but it would be best to do more than break even on the expenses.

I definitely have no regrets about quitting my job, though. The change in lifestyle gained from being my own boss and running my own business is well worth the loss in income. It's hard to put a price on freedom - and I suppose I should be grateful for the iPhone, since it has given me my start with this freedom.

Tuesday, October 6, 2009

Dev Diary: preventing iPhone sleep

I've recently added a "clock radio" alarm feature to some of my iPhone radio apps. As part of this process, I had to figure out a reasonable work-around for Apple's restriction of not allowing 3rd party apps to run in the background.

Unfortunately, the best that can be done for an app that wants to behave as an alarm clock is to require the user of the app to not exit the app. While this seems fairly straightforward, it does introduce another problem. When on battery power, most users will not want the screen of the iPhone to be on while they are using the alarm feature, so normal behavior would be for a user to set the alarm and then "lock" the iPhone screen. And there's the problem - the iPhone OS has a feature where if it is running on battery power, it will suspend any running app if the iPhone screen is locked, except under one condition. If the app is playing audio with the audio session property of kAudioSessionCategory_MediaPlayback, the app will be allowed to continue to run indefinitely while the iPhone screen is locked.

So, if you have an alarm clock feature in an app, this would seem to imply that you must keep the iPhone plugged into a charger, otherwise the app will be suspended a few minutes after you lock the screen and the alarm timer will never get triggered. Fortunately there is another way around this problem and it only uses a minor amount of battery power. If you have your app continuously play a silent audio file while the screen is locked, then this will prevent the OS from suspending the app.

Here's a rough example of how you can implement this using a few lines of code and the AVAudioPlayer class.


AVAudioPlayer *silentPlayer;
NSString *soundFile =[NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], SILENT_SOUND_FILE];
NSData *data = [NSData dataWithContentsOfFile:soundFile];

if (data){
NSError *outError;
silentPlayer = [[AVAudioPlayer alloc] initWithData:data error:&outError];
}else{
// trigger some error
}

silentPlayer.delegate = self;
silentPlayer.volume = 0.0;
[silentPlayer play];


Then, since I am specifying the class using this silentPlayer is its delegate, I also implement the following method to be notified when the silent file has finished playing. In this case, I want the silent file to loop, so I simply restart it.


- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// When the sound stops, wait 1 second and play it again - forever!
[NSThread sleepForTimeInterval:1.0f];
[player play];
}


Obviously, this isn't a complete implementation, but should give you the basics to get started with preventing the iPhone from sleeping. In my particular case, when I want the silent file to stop playing, I simply remove the delegate for the silentPlayer and then tell it to stop:

silentPlayer.delegate = nil;
[silentPlayer stop];

This way, when the silentPlayer stops playing, the audioPlayerDidFinishPlaying method will not be called again, so the silent file will no longer be looping.

Radio Paradise iPhone app v2.0 coming soon!

I've submitted the latest version of the Radio Paradise iPhone app to Apple for approval. This newest version will be 2.0. Based on Apple's current review times, hopefully it will be available mid-October.

I've changed the user interface a bit - hopefully most people will think it is an improvement. Here's a screenshot:



As is true with earlier versions, the app includes displaying the album artwork for the current song playing, along with support for viewing more song info (listener comments, ratings, etc.) via tapping the artwork. Tapping on the musical note brings up a "tunemark" feature for saving the song details to a list, emailing the info, or searching on iTunes for the track.

Also noticeable in this screenshot is a new feature - or at least the button for the new feature. I've added an alarm clock and sleep timer feature. This will allow you to use the app as a clock radio - waking up to Radio Paradise as well as a sleep timer to have the app automatically stop after a set amount of time. In the above example screenshot, the sleep timer is currently active and is counting down from 29 minutes.

The following screenshot shows the clock radio configuration screen:



Again, I'm not an artist or a skilled graphic designer, so the screen is pretty plain, but functional. You can have both the alarm clock and sleep timer active at the same time. In the above screenshot, the alarm is currently on and is set for 7am.

Unfortunately, Apple does not allow 3rd party apps to run in the background, so in order for the alarm clock to work, the app must continue to be running. The screen can be turned off to save battery power, but the app still must be running.

Since the radio playing depends on the Internet, the alarm clock feature includes a failsafe. If the Radio Paradise stream is down, or the wireless network is down, the alarm will detect this problem and will still play an audible sound - a simple "dinging".

All content copyright © 2009  Brian Stormont, unless otherwise noted.   All rights reserved.