I'll be speaking at the Mobile East developer conference next week, on Advanced iOS Development.
Session details are here for your viewing pleasure. Selected highlights:
This presentation will take you from a basic level of understanding of iOS to look at advanced topics that will make you apps more polished, better designed and, ideally, more successful.
Abstract concepts are no use, so in this talk we'll take some existing successful commercial iOS applications as a case study, and see how a selection of iOS technologies and techniques combine within it.
Showing posts with label iphone. Show all posts
Showing posts with label iphone. Show all posts
Friday, 22 June 2012
Tuesday, 3 January 2012
Speaking: BCS Newcastle
I will be speaking at BCS Newcastle on the 25th January. I'll be giving my iOS development talk; a quick start in developing applications for iPhone, iPad, and iPod Touch.
Here's the synopsis:
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
We’ll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Here's the synopsis:
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
- The main languages: Objective C/C++
- Using the Xcode IDE, and various deployment/testing tools
- Common iPhone/Mac OS design patterns, idioms, and practices
- Becoming a native: how to “think in iPhone”
- An overview of the libraries and facilities that exist
- Limitations of the development environment.
We’ll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Thursday, 24 November 2011
PGMidi moved and updated
Please update your repos accordingly.
Over the next few days, I'll also be adding a few new tweaks and features to the project, so stay tuned.
Thanks for all the kind comments and feedback about the code - I'm really glad it's useful. Please do let me know if you've incorporated it in your own project.
Sunday, 9 October 2011
My latest iOS app: The Mahjong Score Book
My latest iOS app is out now (thanks to the iOS 5 SDK having finally gone GM). It's called the Mahjong Score Book and, as the name suggests, is designed to help Mahjong players keep tabs on their scoring in Mahjong games.Of course, once you have your scores captured inside a wee computer, there's more exciting things we can do with them. So the app allows you to:
- keep records of all the games you've ever played, with a very clear visual presentation, associated with the date played
- draw pretty graphs of game progress
- adopt different rule sets (limit hand value, maximum wins as east wind, etc)
- export games to databases, as images, or text files
- automatically roll dice to determine starting positions
- associate notes with each game
- and much more.
If you're interested, then check it out in iTunes here.
I appreciate that it's a niche app. It simply something I wrote to fulfil a personal need. Of course, someone else out there is going to find it useful, too. And so I've polished it, honed it, and produced a really very slick app.
I wrote Mahjong Score Book app back in the summer whilst on holiday, playing Mahjong with friends. It serviced its purpose well then and many times since, and I've learnt a few new iOS techniques whilst polishing off the application.
I'm sure that it won't make me millions, but I'm very proud of what I've produced in a relatively short time. If you know someone who plays Mahjong then please point them at it!
Wednesday, 21 September 2011
iOS: Using older SDKs with newer Xcode versions
When you update Xcode versions, the installer automatically removes any old SDKs you have lying around, and replaces them with the latest version.
This is fine behaviour, as the most recent SDKs remain backwards compatible. You can set your project to target older iOS versions. If you do this, the newer SDK features are disabled for you.
However, there are times when you need to use an older SDK.
For example, I am running the latest Xcode with a beta iOS 5 SDK installed. Since this was originally installed on a clean machine, I didn't set the beta install to use a parallel directory and leave the "release version" of the developer tools intact - they simply weren't installed. (Making a parallel install is, in general, the best practice when installing a beta Xcode/SDK set).
Fear not. You can still get your newer Xcode to build with an older SDK, without downgrading your Xcode or making a parallel install:
This is fine behaviour, as the most recent SDKs remain backwards compatible. You can set your project to target older iOS versions. If you do this, the newer SDK features are disabled for you.
However, there are times when you need to use an older SDK.
For example, I am running the latest Xcode with a beta iOS 5 SDK installed. Since this was originally installed on a clean machine, I didn't set the beta install to use a parallel directory and leave the "release version" of the developer tools intact - they simply weren't installed. (Making a parallel install is, in general, the best practice when installing a beta Xcode/SDK set).
Fear not. You can still get your newer Xcode to build with an older SDK, without downgrading your Xcode or making a parallel install:
- Close any running Xcode instance you have open.
- Locate the install DMG for an old version of Xcode (e.g. Xcode_3.2.5_and_ios_sdk_4.2_final.dmg, they name them so well) and open it.
- Do not run the installer!
- Open the Packages directory in that disk image. It is a hidden directory. Try this terminal incantation: "open /Volumes/Xcode\ and\ iOS\ SDK/Packages"
- Locate the iPhoneOS and iPhoneSimulator SDKs for the version you want. Run just those pkg files. (e.g. I ran the iPhoneSDK4_2.pkg and it's matching iPhoneSimulatorSDK4_2.pkg)
- Make sure you specify the /Developer directory as your install location. If you don't, the SDKs will be installed in your root directory, under the /Platforms directory; you'll have to manually copy them into /Developer/Platforms yourself.
- Now, re-open Xcode. If the SDKs installed in the right locations, they will be selectable in your project now.
Friday, 22 July 2011
Xcode: Determining the current SDK version in a script
In an iOS XCode project, I needed a shell script target (aka "External Build Tool" target) that invokes other scripts which in turn build stuff using Xcode. Curiously recursive.Now, I needed to pass that script the current iOS SDK version being used so it could arrange its own build malarkey, and get all its SDK ducks in a row.
There is no environment variable for that defined by Xcode. Bah. The closest you get is the current deployment target version, which appears in $IPHONEOS_DEPLOYMENT_TARGET.
That seems like rather a large omission.
You do get given $SDKROOT which is a file path to the current SDK. But that's not quite the same thing as a simple version number.
Never, fear, shell gibberish to the rescue. This is what I came up with:
SDK_VERSION=$(echo $SDKROOT | sed -e 's/.*iPhone\(OS\)*\(Simulator\)*\([0-9]*.[0-9]*\).sdk/\3/')
If you know a better way to do this, I'd love to know.
Thursday, 9 June 2011
The Enigma Continues
Version 1.4 of my cool iOS puzzle game, The Enigma Squares, has been released. Check it out here. In this version, I present you more than 80 new levels, with a number of fun, a number of fiendish, and a number of speed-trial puzzles.Check it out on iTunes now.
I've also released a new game. The Enigma Kids is a family-oriented puzzler. With child-friendly puzzles, great graphics and lots of fun, everyone will enjoy this game.
Check out The Enigma Kids on iTunes here.
Let me know what you think!
Friday, 13 May 2011
iOS: The Enigma Squares (1.2)
The Enigma Squares version 1.2 is available in the App Store now. Amongst other excitement, it adds Game Center support. You can now share your achievements and high score with other players. Woo hoo.So far, I'm very impressed at how far players have got. I'm glad the game is providing an interesting challenge!
More interesting updates are in the pipeline...
Thursday, 12 May 2011
iOS: Packaging apps store submissions from the command line (my zip broke)
How to package iOS apps for submission to iTunes Connect from the command line.I'm a firm believer in the power of the command line. I like my GUI tools as much as the next man (as long as he's a bearded Unix guru from the 1970s). But for sheer power, repeatability and flexibility you just can't beat a good script.
Which is why every project I work on has to have a simple single script that configures, builds, and packages the code, creating a well-named payload that can be installed/submitted/deployed. I feel a lot safer about the quality of a release if it's generated by a tried-and-tested script, rather than by a series of button clicks in a series of separate tools.
You know it makes sense.
iOS projects submitted to the App Store are effectively zip files with a particular directory structure. You can drive Xcode with the xcodebuild tool to build and link your distribution version of an iOS app.
However, whenever I tried to zip the project up from the command line, the Application Loader utility (what you use to submit your app to iTunes Connect) just gave bizare errors.
The CodeResources files must be a symbolic link to _CodeSygnature/CodeResources. Make certain that the bundle is on a locally-mounted volume...Application failed codesign verification. The signature was invalid, or it was not signed with an Apple submission certificate.
Well, that's nice gibberish. Not.
However, a zip archive created using the Finder's "Compress" menu entry worked fine. Very frustrating.
Don't fear! I fixed it. Here's how to do it in your very own build script: your zipper is broken; throw it out. Use ditto instead. Here's the line from my build script:
APP_FILENAME=/path/to/build/Application.appPACKAGED_FILENAME=MyGoodPackagedFilename.zipditto -c -k --keepParent --rsrc "$APP_FILENAME" "$PACKAGED_FILENAME"
Enjoy your build scripts.
Wednesday, 4 May 2011
iOS: The Enigma Squares
My first personal iOS project has finally seem the light of day. Please welcome into the world The Enigma Squares. It's an interesting (and dare I say it) entertaining block-moving puzzle game.Check it out on iTunes here.
I've produced plenty of iOS projects for my company. But this has been an entertaining personal side-project, to keep me busy through those long spring evenings.
It is actually a version of a game I first wrote (ahem) 20 years ago. Back then it was written for the Acorn Archimedes, and I sold it to a magazine for inclusion on their cover disk (remember those?) This version is a little more polished, a little more challenging, and a lot more fun.
The code's a fair bit better too, but that's another story. One that I'm sure I'll tell one day...
Let me know what you think of it!
Tuesday, 5 April 2011
iOS: A Fading AVAudioPlayer
In a recent iOS project I needed to play some background music and have it fade smoothly in and out when it starts and stops.The "play some music" part is easy. iOS give us AVAudioPlayer in the AVFoundation framework. Super sweet and easy to use. However the "fade in and out" bit doesn't come for free.
The canonical solution suggested on the web is to hand-craft some nasty looping logic to get the job done. This is 2011 and we can do better than that. And, indeed, here it is, in all it's Objective C glory.
My solution makes interesting use of categories, associative references and blocks. It's worth strolling through the implementation if you're interested in any of these. If not, you can just grab my code from the Gitorious project and use it in blissful ignorance.
1. Add a category
First, we open up our own category on the AVAudioPlayer class and define the methods we would ideally like the class to provide:
@interface AVAudioPlayer (PGFade)
- (void) stopWithFadeDuration:(NSTimeInterval)duration;
- (void) playWithFadeDuration:(NSTimeInterval)duration;
@end
That's the joys of categories - you can extend existent classes in your own application easily to make it look like methods were part of the original class interface. The common convention is to save this in a file called "AVAudioPlayer+PGFade.h".
Now client code can create a bog-standard AVAudioPlayer object, and call my new methods as if they were part of the base interface:
AVAudioPlayer *player = [AVAudioPlayer alloc] initWith...]; // however you want it set up
[player playWithFadeDuration:2.0];
2. Associative References
Now, our implementation of this is going to require some instance variables (ivars) to work with. The problem with categories is that they only allow you to add methods - you can't extend the set of instance variables defined in the class' @interface.
Or can you?
Associative references to the rescue! This is a handy Objective C runtime facility that allows you to associate another object with an existing object, with a lookup system very much like a dictionary - referenced by a void* key value.
The associated object is lifetime-managed with the original object, so when you release the parent, all associated objects are also released.
Using this facility we can "graft on" some of our own private ivars to the original class. Dirty, but effective.
One of the variables I need is a boolean variable tracking whether a fade is currently in progress. I actually expose this as a property called fading in the category interface. The implementation looks like this:
@implementation AVAudioPlayer (PGFade)
static char fadingKey;
- (BOOL) fading
{
NSNumber *number = (NSNumber *)objc_getAssociatedObject(self, &fadingKey);
return number && number.boolValue;
}
- (void) setFading:(BOOL)fading
{
objc_setAssociatedObject(self, &fadingKey, [NSNumber numberWithBool:fading], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
That's relatively simple. We just use two objective C runtime functions, objc_getAssociatedObject and objc_setAssociatedObject. For the association we use the address of a static variable - this will be an unambiguous value in the whole program. The object we store is an NSNumber object initialised with the value of our boolean.It's a simple and effective trick.
3. Blocks
The final bit is for bonus points. You can see the implementation of my fade routine in the example project code itself. It's pretty simple - I just initialise the fade state in a few more "associative reference" variables and schedule a method call with performSelector:withObject:afterDelay. Each time this is called, I adjust the AVAudioPlayer's volume, and schedule a new call if one is needed.
However, to truly perform a stop with fade, we need to ramp the audio volume down, and when it gets to zero stop the player. This could be achieved with some more state variables and clumsy logic, but iOS now provides us with blocks which are perfect for this kind of activity.
For sanity, I typedef a block (closure) type. The syntax practically identical to typedefing a pointer-to-function in C, but with ^ instead of *.
typedef void (^AVAudioPlayerFadeCompleteBlock)();
I make one more associated variable of this type, the block to call on completion:
- (AVAudioPlayerFadeCompleteBlock) fadeCompletion
{
return (AVAudioPlayerFadeCompleteBlock)objc_getAssociatedObject(self, &fadeCompletionKey);
}
- (void) setFadeCompletion:(AVAudioPlayerFadeCompleteBlock)completion
{
objc_setAssociatedObject(self, &fadeCompletionKey, completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
Note that blocks can be traded like objective C objects. You can retain, copy, and release them. In this case our code needs to take a copy (using the OBJC_ASSOCIATION_COPY_NONATOMIC flag). This ensures that any set block exists on the heap (persistent) rather than the default on-the-stack location.
Now, the internal "audio fade" routine need only check whether there is a completion block registered when the fade is complete, and if so call it:
if (fadeIsComplete)
{
self.fading = NO;
AVAudioPlayerFadeCompleteBlock completion = self.fadeCompletion;
if (completion) completion();
self.fadeCompletion = nil;
}
Invoking a block looks just like calling a function. Once called, we clear out the stored block in case it is holding other resources that should be released.
This provides an elegant way to perform any arbitrary action after the fade is complete.
That's all, folks!
The trio of Objective C facilities used here work together well to provide a simple and elegant solution to a problem that is often achieved with complex "strings-and-glue" logic. Check out the entire project on Gitorious here.
Friday, 18 March 2011
iOS: Prettier auto-rotation

A simple Friday iOS coding tip for you:
When your app auto-rotates do you have an unsightly white frame appearing around the edges of your beautifully hand-crafted UI?
The simple fix to your UI woes: make the UIWindow background clear (either in the XIB file, or just before your call to [window makeKeyAndVisible].
Simples!
Wednesday, 16 March 2011
[ios] iOS Development talk slides available
The slides from my popular iOS development talk, last given at BCS Edinburgh are available for you to view on Slideshare.To view them, follow this link.
Friday, 11 February 2011
[ios] Dynamic cast in Objective-C
In C++, you can cast a pointer between two (related) types, and ask the runtime to check if the conversion is valid using dynamic_cast. Usually in C++ the use of dynamic_cast is a sign that you're doing something wrong - good C++ design generally avoids such constructs.
However, Objective-C is a far more dynamic language, and often you do need to do something similar. The runtime provides all the smarts for this, but doesn't deliver it in a simple one-liner.
So let's fix that...
Wondering if a view controller's view property is a UISwitch? Try this:
UISwitch *switch= objc_dynamic_cast(UISwitch,viewController.view);if (switch) NSLog(@"It jolly well is!);
That's nice, isn't it? Here's how:
#define objc_dynamic_cast(TYPE, object) \
({ \
TYPE *dyn_cast_object = (TYPE*)(object); \
[dyn_cast_object isKindOfClass:[TYPE class]] ? dyn_cast_object : nil; \
})
For the curious, here's what's going on...
First, we define a preprocessor macro using a gcc extension: the macro compound statement. That's the ({ ... }) block. This is a little dirty, and I certainly wouldn't use a gcc-specific extension in my "portable" C++ code. However, Objective-C lives in a different ecosystem, where you can guarantee that compound statements will be supported. So we'll go with it.
The reason I use a compound statement is to define a "local" variable - dyn_cast_object. This is just to cover the macro's back - it needs to mention the name of the object argument twice, and if that expression has side effects you'd get twice the number of side effects otherwise. Side-side effects. So I store the argument in a local variable to avoid this. (Most of the time this is unlikely to be an issue, but if you ever got bit by this problem, you'll appreciate having done it right the first time).
Then we simply ask the object is it is of the class of our cast's destination type, using NSObject's isKindOfClass: selector.
Not too complex. And you could do the isKindOfClass: dance wherever you need to cast. But it's nice to write the macro once and then write clear code that reveals it's intent.
[ios] Cancelling a UIGestureRecognizer
You have a view with a handful of gesture recognizers. Perhaps some of them are chained together with requireGestureRecognizerToFail so that they interact well.Sometimes, you still need to respond to other user interaction, and cause any pending gesture to immediately fail. There isn't an API for that.
I had this issue when my application's "timeline" view, which was using pinch, tap, and pan gestures in concert, needed to grow temporary UIButton subviews. The buttons worked fine, but pressing them also triggered the gesture recognizers - very confusing for the user.
Here's the solution.
How to forcibly cancel a UIGestureRecnogizer
Add a new category (I call it "Cancel") to the UIGestureRecognizer class extending it with a new cancel method:
@interface UIGestureRecognizer (Cancel)- (void)cancel;@end
And implement the new method like this:
@implementation UIGestureRecognizer (Cancel)- (void)cancel{self.enabled = NO;self.enabled = YES;}@end
The simple trick of switching off and back on a gesture will force it to cancel.
Then for bonus points, I add a category on UIView to make it easy to cancel all the gestures attached to it. I tend not to hold the gestures as member variables in my view controller because there isn't any need to do so - they are retained by the view you attach them to.
//-----------------------------------------// In .h file:@interface UIView (CancelAllGestures)- (void) cancelAllGestureRecognizers;@end//-----------------------------------------// In .m file:@implementation UIView (CancelAllGestures)- (void) cancelAllGestureRecognizers{for (UIGestureRecognizer *gesture in self.gestureRecognizers){[gesture cancel];}}@end
This new method could then be easily used in my main view controller, by attaching it to the my UIButton objects as a new action:
[button addTarget:myViewWithGesturesaction:@selector(cancelAllGestureRecognizers)forControlEvents:UIControlEventTouchDown];
Categories are a useful Objective C feature that really do help to make your code more clear and readable. Here they provide the means for another simple solution. I hope you find it useful.
Friday, 4 February 2011
PGMidi updated
Attention PGMidi users! I've updated my MIDI Monitor example project again, this time making PGMidi less of an example, and a lot more useful for general use.
Check it out on the GitHub project page (historical note: it was hosted on this gitorious project page, but that is now deprecated in favour of GitHub).
What's changed:
- The PGMidi class now allows you to determine what MIDI sources and MIDI connections are currently available.
- It allows you to determine whether the source/destination is a networked session, or a physically attached device.
- The "events" PGMidi sends through the delegate interface are far more explicit.
- I've added some useful tools to find a matching source/destination pair if you want to speak to one specific MIDI device.
The MIDIMonitor example application continues to show how to use the PGMidi API.
Thanks for all the comments and feedback I've received about this code. I hope you find these updates useful.
Friday, 28 January 2011
Speaking: BCS Edinburgh (iOS development)

I will be speaking at the Edinburgh branch of the BCS on the subject of iPhone development on March the 9th.
The details of the session, times, and location are available here.
Here's the synopsis:
Developing applications for iPhone, iPad (and other iOS devices)
"An introduction to iPhone development for beginners or those who are casually interested and want a leg up the learning curve"
The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.
In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
- The main languages: Objective C/C++
- Using the Xcode IDE, and various deployment/testing tools
- Common iPhone/Mac OS design patterns, idioms, and practices
- Becoming a native: how to "think in iPhone"
- An overview of the libraries and facilities that exist
- Limitations of the development environment.
We'll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.
Thursday, 27 January 2011
iOS: performSelectorOnMainThread: with two arguments
iOS's NSObject class provides a mechanism to run any selector on a different thread. The most often used variant runs the selector on the "main" (i.e. UI) thread, the snappily titled: performSelectorOnMainThread:withObject:waitUntilDone:. However, the limitation with this call is that you can only supply one argument.
Sometimes, one is not enough. There is a two argument non-thread version, here. So why not invent our own two-argument threaded version?
We can add this easily enough to the base NSObject class by opening a new category on it just for the purpose.
Here's how...
1. Define our API
We open a category on NSObject (note the category name in brackets)
@interface NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait;@end
Naturally, it follows the existing performSelector API signatures, but just adds our extra withObject: argument.
2. Implement it
Here's the secret sauce. Careful application of NSMethodSignature, and NSInvocation.
@implementation NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait{NSMethodSignature *sig = [self methodSignatureForSelector:selector];if (!sig) return;NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];[invo setTarget:self];[invo setSelector:selector];[invo setArgument:&arg1 atIndex:2];[invo setArgument:&arg2 atIndex:3];[invo retainArguments];[invo performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];}@end
That's it.
Now you have your own simple way to invoke a call to selector on the main thread from wherever you are in your code. Handy.
Thursday, 18 November 2010
Make some noise! (Audio on iOS)
There are two main APIs on iOS for playing programatically-generated audio:Audio units are a lower-level, lower-latency technology. And also, a relatively complex API. Audio queues are higher-level and simpler to use, but have far greater latency.
I have produced a sample project showing the simplest creation of an audio unit and audio queue output so you can compare and contrast the two APIs. Get it on Gitorious here.
The following series of blog entries will describe each technology.
About the project
The project builds a sample iOS application that plays a steady sine wave as long as it is running. If you look at main.mm you'll see a single #define for USE_AUDIO_QUEUE_OUTPUT that can be used to switch between the audio unit and audio queue back ends.
There are extra things a well-behaved iOS audio app should do that are not (yet) illustrated by this example project. Notably, your app should use the Audio Sessions API to define what kind of audio session it requires and to handle interruptions to the audio output (e.g. when a phone call it received whilst your app is running).
Make some noise!
Before we work out how to make noise with our iOS devices, we need some audio to start with. For this reason, the AudioProducer protocol defines a simple interface that the audio backends can grab an audio stream from.
It looks like this:
/// Type of audio sample produced by an AudioProducertypedef SInt16 Sample;/// Protocol for objects that produce audio@protocol AudioProducer@property (nonatomic) float sampleRate;/// Fills a buffer with "size" samples./// The buffer should be filled in with interleaved stereo samples.- (void) produceSamples:(Sample *)audioBuffer size:(size_t)size;@end
That is, we'll be peddling signed 16-bit integer samples, and have a single method that can be called to grab the next block of interleaved stereo audio samples.
Given that, I have written a simple SineWave audio generator. It's not the most elegant generator, I'll admit. It uses a resonant filter to approximate a sine wave rather than the maths library trig functions for performance reasons.
The SineWave interface adopts the AudioProducer protocol, and adds two extra properties - the frequency of the sine wave and the peak (amplitude) of the wave. You can see the interface here and the implementation here.
Atomicity
Note that since this is a simplistic example I have made all of these properties nonatomic. However, both audio units and audio queues will pull audio from your application in a background thread (not the main user interface thread).
The audio unit uses a very high priority background thread, as it is a very low latency audio pipeline with little buffering. The audio queue thread is not set as high-priority, as it employs a large amount of buffering.
You must bear these threads in mind when writing an audio generator. Ensure that any parameter that can be changed is thread-safe. Make sure that if the UI is in the process of adjusting values and gets interrupted by the audio thread that no disasters (e.g. nasty audio glitches) can result.
What this looks like in practice is different for each application. But this is an important warning to heed.
Next time
So now we have some audio to play, next time we'll look at how to use the audio queue APIs to play it.
Thursday, 21 October 2010
Using CoreMIDI in iOS (an example)
In iOS 4.2 the CoreMIDI framework is dropping into the standard operating system. MIDI connectivity using generic class-compliant USB MIDI hardware will be available to all.
It's not a big framework, with a handful of pure-C APIs. But its affect will be profound. What was previously only possible using Akai's AkaiConnect SDK (which is a very nice Objective-C API) or Line 6's MIDI Mobilizer SDK will be available to all.
From what I can see, the iOS CoreMIDI version is going to be the exact same API as the Mac OS desktop variant. I expect developer take-up of this API to be far faster than for the existing two (non-standard) iOS MIDI interface APIs. Pretty soon every iPhone synth app will support Apple's generic MIDI API.
That is, if they can work out how to.
CoreMIDI isn't the best documented API (this is all you get: a list of typedefs and functions). Fortunately, the headers are well-commented and the API is mercifully simple and sensible. However, with no compelling examples (that I could find) it takes a little digging to work out how to use CoreMIDI.
So here I present a very simple example project, with a reusable Objective-C MIDI interface class. With this code, you can get up to speed with CoreMIDI quickly. Indeed, if you just paste my MidiInput class into your synth app you'd be good to go.
Grab it from the GitHub project here. (Update note: the repo master used to be hosted on Gitorious here but we've moved to GitHub in these enlightened times)
Please let me know if you find it useful, or if you use it in your own projects.
Integrating CoreMIDI in your application
First, you need to decide if you want your app to support devices running iOS versions before 4.2. Since CoreMIDI is only introduced in 4.2, you have to jump through a few hoops to keep your app running on earlier versions:
- Weakly link to the CoreMIDI framework, so on OS versions without it your application will still launch. (You do this by going to your application's target in the Xcode tree view, selecting "Get info", and in the "General" tab's "Linked libraries" section ensuring that CoreMIDI is set to "Weak" not "Required".)
- Including CoreMIDI functionality conditionally. The best way to do this is inspect the kCFCoreFoundationVersionNumber variable and only initialise your MIDI handling if the value represents iOS 4.2 or later. (See the iOS version detection header file in my example project for an elegant way to do this).
A demonstration of all of this is available in my example project.
Using CoreMIDI
CoreMIDI itself isn't too complex if you're happy to read the headers and work out what's going on. You need a basic grasp of how Mac OS's Core Foundation works, to understand lifetime management issues and to access string properties, etc.
CoreMIDI has a few basic concepts: most importantly clients, devices (with endpoints) and ports. The C APIs let you enumerate these, and register a notification to keep abreast of changes in MIDI connection state.
MIDI inputs are "sources" in CoreMIDI. MIDI outputs are "destinations".
Given those basic facts, you should be able to read through my MidiInput class and figure out what's going on.
Parsing MIDI
My example program just spits out a stream of binary MIDI data. I'm not showing any parsing of the MIDI data stream here. This parsing isn't rocket science, but is another step you have to perform.
Contact me if you want to know more about parsing MIDI.
Subscribe to:
Posts (Atom)

