Rss

Archives for : July2011

What If iOS Gaming Is A Fad?

In a much-quoted article last week, EA CEO John Riccitiello said consoles are now only 40% of the games industry, and that the company’s fastest-growing platform is the iPad, which didn’t even exist 18 months ago.

Taken together with the presence of Angry Birds plushies at every mall in the U.S., is this a sign of the ascendance of an iOS era in gaming? Maybe, but we’ve played this game before, and it doesn’t end well.

Only five years ago, it was a resurgent Nintendo that turned the gaming industry upside down with the Wii, a massive success and the first time since the NES that Nintendo had the top box for a console generation. Fortune praised Nintendo for rolling Sony and Microsoft, Roughly Drafted’s Daniel Eran Dilger was ready to bury the Xbox 360 in early 2008, and Penny Arcade taunted Sony for saying the overpriced PS3 was as hard to find in early 2007 as the then-rare Wii.

Yet today, Wii sales are collapsing, the company has chosen (or been forced?) to announce its next generation console while Xbox 360 and PS3 soldier on, and Kotaku is making fun of EA for actually putting significant effort into Madden NFL 12 for Wii, writing “it seems these days that most companies making games just don’t care about making Wii games anymore.”

It’s a fickle industry, but this is still a fast and hard fall for what, as of December, was still the top non-portable gaming console. How can the most popular console not have an economically and artistically strong ecosystem of game development built up around it?

Well, who are the Wii gamers? As conventional wisdom reminds us, the win of the Wii was to recruit non-traditional gamers: not just the usual shooter and sports fans, but casual gamers, young kids, the elderly, and many others. The Fortune article above has great praise for this as a business strategy:

Talk about lost in translation. Turns out there’s a name for the line of attack Iwata has been taking: the blue-ocean strategy. Two years ago business professors W. Chan Kim and Renée Mauborgne published a book by that title. It theorizes that the most innovative companies have one thing in common – they separate themselves from a throng of bloody competition (in the red ocean) and set out to create new markets (in the blue ocean).

This should sound familiar to a lot of us… because doesn’t it describe Apple to a T? Isn’t the smartphone, and even moreso the tablet, a blue ocean that allowed Apple to escape the carnage of the PC wars?

And when we think of iOS gaming, haven’t we seen a profound shift to new audiences and new games? The big iOS games aren’t old franchise warhorses; the ones that everyone can think of are small novelties, often from hitherto unknown developers.

So here’s the thing… what if the crowd that was playing Wii Sports in 2008 are the ones who are playing Cut The Rope today? Well, doesn’t that make it more likely they’re not going to linger long in iOS gaming? It’s great in the here and now, but a fickle fan base may grow bored of fruit-slicing and zombie-deterring and move on to the next shiny thing. It happened to the Wii, so why couldn’t it happen to iOS?

Speaking subjectively, what dulled my interest in Wii was the avalanche of mini-game shovelware, which drowned out the few valiant attempts to use the console’s unique features in interesting ways. Granted, that didn’t pan out as well as expected anyways: the sword-swinging of Soul Calibur Legends was a letdown for me, and maybe that’s why I didn’t seek out many of the games that actually tried, like Zack and Wiki and No More Heroes.

My own hope is that the larger and more diverse ecosystem of iOS game developers will keep things more interesting, and ensure there’s always something new for everyone. The market is so much more competitive than the retail-constrained Wii, that a play-it-safe me-too strategy (like trying to make the next Carnival Games for Wii) is unlikely to succeed for long: there’s not much point copying Angry Birds when Rovio is perfectly happy to keep updating their app with more levels than we can keep up with. Better to innovate with good gameplay, appropriate social features, and polish: Casey’s Contraptions is a great example of all three.

Final Fantasy Tactics soundtrack atop my iPad 2At some point, the iPad became my console of choice. Oh, someday I’ll go back and finish Steambot Chronicles on the PS2. But right now, I’m anxiously anticipating the iPad version of Final Fantasy Tactics, the iPhone/iPod version of which was submitted to Apple this week. I played it on the PS1 back in the 90’s, and am more than ready to sink 70 hours into another run through The War of the Lions, even knowing full well how it ends (sniff). See that picture? That’s the 2-CD original soundtrack of FFT, which I bought back at Anime Weekend Atlanta back when paying $50 for imported CDs from Japan was freaking awesome.

It’s a hopeful sign that Square Enix is betting on the iOS platform to support deeper and more intricate games, and price points higher than $1.99. Maybe that’s Square Enix’s “blue ocean” to escape the carnage of 99c novelties on the one hand, and multi-million dollar development disasters in the living room console war. If it works, it might be just what the platform needs to avoid a Wii-like implosion down the road.

Presumed Valid

A day after Apple’s third quarter earnings announcements, it’s time for the reading between the lines and amateur Kremlinology.

Here’s one thing that doesn’t make me very happy. Grab the earnings call audio (and notice from the .m3u8 extension that it’s in HTTP Live Streaming!), and scroll to around 24:50 in. The question is from Bill Schultz of Goldman Sachs:

OK, and a quick followup. There’s been a lot of news about, you know, patent disputes of late. Some seem to have gone in Apple’s favor while others haven’t. Can you help us understand, Tim, how to put these events in context… how we should think about your IP strategy overall and perhaps, you know, how all this is potentially impacting the competitive landscape in smartphones and tablets?

The much quoted response from Apple COO Tim Cook:

We have a very simple view, here. And that view is we love competition, we think it’s great for us and for everyone… but we want people to invent their own stuff. And we’re going to make sure that we defend our portfolio fervently.

That seems to speak obviously to Apple’s recent ITC win over HTC. And it’s probably meant as propaganda and spin as much as anything else.

But notice that it ignores the patent cases that have gone against Apple, such as Kodak and Personal Audio. Does Cook’s absolutist stance on patent mean that maybe Apple should have “invent[ed] their own stuff” in these cases? Maybe it’s a more relative morality, like every tabloidy legal case where whichever side wins declares to the TV cameras that “the system works.”

The elephant in the room is the patent trolls’ assault on indie developers, the consequences of which are spelled out by The Iconfactory’s Craig Hockenberry in The Rise and Fall of the Independent Developer. Cook’s response didn’t address Apple’s attempt to intervene in the Lodsys cases, or its current absence from even more galling patent claims against indie iOS developers by MacroSolve and others.

Is Apple going to step into every case that claims third parties violate patents by using Apple’s APIs? Well surely, they’re not going to commit to that publicly — barring a surprise “Thoughts On…” letter from Steve — and with the rate at which this nonsense is picking up, we should watch to see if and when Apple backs off and leaves indie developers to their fate. Apple could probably survive the worst-case scenario, the total collapse of third-party iOS development, considering that’s how they launched the iPhone in the first place (and considering how well Android phones are selling, despite a far weaker app ecosystem).

What’s discouraging is that it’s clear, despite hopes to the contrary, that Apple has no philosophical problem with software patents whatsoever. Indeed, in the Lodsys case, it’s not trying to invalidate the junk patent; it’s asserting that Apple’s license of the patents covers its use by third parties. The instinct may well be in their corporate DNA (and that of other large tech companies) that patents are a critical strategic asset, something to be amassed and protected whenever possible. That MacroSolve could patent electronic form submission, in 2003, seems not to bother them. Patents are, apparently, too important to be doubted.

Reminder: CocoaConf early bird ends Friday (July 22)

Quick reminder: Early Bird pricing ($350) ends Friday (July 22) for CocoaConf in Columbus, Ohio. It’s a new conference, but it has put together a very impressive set of speakers, most recently adding Bill Dudney, former Apple evangelist and co-author on my revised iOS SDK Development book.

I’m doing two talks on AV Foundation. These may draw on the three talks I’ve done at the Voices That Matter conferences, but if I have time, I’m considering rebooting them from the “tour the APIs” format to a “one big project” format. Maybe something along the lines of “Let’s Write QuickTime Player for iPhone” and “Let’s Write Final Cut Pro for iPad”. We’ll see… don’t want to over-promise when I’m already buried with programming work and two books.

Oh, and Columbus has my favorite chain restaurant, a holdover from my time in Atlanta, and my former employer at One CNN Center. Just sayin’, in case plans are needed for Saturday night. Ahem.

alutLoadWAVFile(). Or better yet, don’t.

My last iDevBlogADay entry was about the second edition of the Prags’ iOS development book, so this time, I want to shine some light on my other current writing project, the long-in-coming Core Audio book. Last month, I mentioned that we’d shipped an update with three new chapters. A lot of the focus is and should be on the Audio Units chapters, but I want to talk about OpenAL.

Core AudioIf you go looking for OpenAL examples on the web — like this one or this other one — chances are high that the sample code will include a call to alutLoadWAVFile().

This function, in fact all of alut.h was deprecated in 2005. But people are still using it in tutorials. In iDevBlogADay posts. On iOS. Which never shipped alut.h.

Yes, you can get the source and compile it yourself. There are even fossilized docs for it. But, really, please don’t.

Let’s get to the question of why it was deprecated in the first place. Adam D. Moss of gimp.org, writing back in 2005, please take it away:

OpenAL is an audio renderer and just doesn’t have any business doing file IO and decoding arbitrary file formats, which are well-covered by other specialised libraries.

As sick as everyone probably is of the GL comparisons, OpenAL loading WAV files is like OpenGL loading XPMs. A utility layer on top of AL is a useful thing, but most of the reasons that ever justified GLUT’s existance don’t apply to ALUT or are trivially implementable by the app, with or without
third-party code.

In the book, we didn’t want to rely on something that wasn’t part of iOS or Mac OS X, or on a file format that we otherwise have no use for (we’d much rather you bundle your app’s audio in .caf files). And as it turns out, Core Audio offers a much better way to load audio into your application.

In our example, we load a file into a memory, and then animate its location in the 3D coordinate space to create the illusion of the sound “orbiting” the listener. To keep track of state, we use a struct:



#pragma mark user-data struct
typedef struct MyLoopPlayer {
	AudioStreamBasicDescription	dataFormat;
	UInt16				*sampleBuffer;
	UInt32				bufferSizeBytes;
	ALuint				sources[1];
} MyLoopPlayer;

This struct describes the audio format, has a buffer and size to hold the samples, and has the OpenAL source that we animate.

The function below loads an arbitrary file, LOOP_PATH_STR, into the struct. It’s a long listing; summary follows:


// note: CheckError() is defined earlier in the book. Just tests
// OSStatus==nil, and fails with a useful printf() if not

OSStatus loadLoopIntoBuffer(MyLoopPlayer* player) {
	CFURLRef loopFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 
						LOOP_PATH,
						kCFURLPOSIXPathStyle,
						false);
	
	// describe the client format - AL needs mono
	memset(&player->dataFormat, 0, sizeof(player->dataFormat));
	player->dataFormat.mFormatID = kAudioFormatLinearPCM;
	player->dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger |
				kAudioFormatFlagIsPacked;
	player->dataFormat.mSampleRate = 44100.0;
	player->dataFormat.mChannelsPerFrame = 1;
	player->dataFormat.mFramesPerPacket = 1;
	player->dataFormat.mBitsPerChannel = 16;
	player->dataFormat.mBytesPerFrame = 2;
	player->dataFormat.mBytesPerPacket = 2;
	
	ExtAudioFileRef extAudioFile;
	CheckError (ExtAudioFileOpenURL(loopFileURL, &extAudioFile),
				"Couldn't open ExtAudioFile for reading");
	
	// tell extAudioFile about our format
	CheckError(ExtAudioFileSetProperty(extAudioFile,
				kExtAudioFileProperty_ClientDataFormat,
				sizeof (AudioStreamBasicDescription),
				&player->dataFormat),
			   "Couldn't set client format on ExtAudioFile");
	
	// figure out how big a buffer we need
	SInt64 fileLengthFrames;
	UInt32 propSize = sizeof (fileLengthFrames);
	ExtAudioFileGetProperty(extAudioFile,
			kExtAudioFileProperty_FileLengthFrames,
			&propSize,
			&fileLengthFrames);
	
	printf ("plan on reading %lld framesn", fileLengthFrames);
	player->bufferSizeBytes = fileLengthFrames *
		player->dataFormat.mBytesPerFrame;
	
	AudioBufferList *buffers;
	UInt32 ablSize = offsetof(AudioBufferList, mBuffers[0]) +
		(sizeof(AudioBuffer) * 1); // 1 channel
	buffers = malloc (ablSize);
	
	// allocate sample buffer
	player->sampleBuffer =  malloc(sizeof(UInt16) *
		player->bufferSizeBytes); // 4/18/11 - fix 1
	
	buffers->mNumberBuffers = 1;
	buffers->mBuffers[0].mNumberChannels = 1;
	buffers->mBuffers[0].mDataByteSize = player->bufferSizeBytes;
	buffers->mBuffers[0].mData = player->sampleBuffer;
	
	printf ("created AudioBufferListn");
	
	// loop reading into the ABL until buffer is full
	UInt32 totalFramesRead = 0;
	do {
		UInt32 framesRead = fileLengthFrames - totalFramesRead;
		buffers->mBuffers[0].mData = player->sampleBuffer +
			(totalFramesRead * (sizeof(UInt16)));
		CheckError(ExtAudioFileRead(extAudioFile, 
					&framesRead,
					buffers),
				   "ExtAudioFileRead failed");
		totalFramesRead += framesRead;
		printf ("read %d framesn", framesRead);
	} while (totalFramesRead < fileLengthFrames);

	// can free the ABL; still have samples in sampleBuffer
	free(buffers);
	return noErr;
}

The essential technique here is that we are using Extended Audio File Services to read from a source audio file. That gets more important in a minute. For now, we have the following essential steps:

  1. Define a mono PCM format compatible with OpenAL, and set this as the client format for an ExtAudioFile. This is the format that will be delivered to us.
  2. Calculate how big a buffer we need. The property kExtAudioFileProperty_FileLengthFrames gives us a frame count, and in PCM, being constant bitrate, we can calculate the buffer size as channel-count * bytes-per-frame * frame-count.
  3. Create the data buffer, build an AudioBufferList structure around it
  4. Read from the ExtAudioFile, into the AudioBufferList, until we reach end-of-file.

When the function returns, we have data in a format suitable for sending over to OpenAL via the alBufferData call:


alBufferData(*buffers,
		AL_FORMAT_MONO16,
		player.sampleBuffer,
		player.bufferSizeBytes,
		player.dataFormat.mSampleRate);

Now, I mentioned that it was important that we used ExtAudioFile, and here's why: it combines file I/O and audio format conversion into one call. So, whereas alutLoadWAVFile can only work with PCM audio in WAV containers, this code works with anything that Core Audio can open: MP3, AAC, ALAC, etc.

In fact, in the second example in the chapter, we switch from looping a buffer to calling the OpenAL streaming APIs. So if we combine our orbit:

with one of our editor's favorite and appropriately-named songs, loaded from an .m4a, we get this:

So there you have it: don't recompile a neglected and deprecated ALUT library for the sake of alutLoadWAVFile(), when you can use Core Audio on iOS/OSX to open any supported container/codec combination. More powerful, less skeevy... should be an easy choice.

One more thing... people have reported having problems getting the Core Audio sample code from Safari Online Books. I can see it when I'm logged in, but apparently I might be the only one. Until this problem is fixed, I'm making the book's sample code available on my Dropbox: core-audio-examples-04-30-2011.zip. Hope that helps.

Second Edition, Volume One

Today’s my day to start another run of bi-weekly entries on iDevBlogADay, so let’s start off with a splash.

You know that iPhone SDK Development book that I wrote with Bill Dudney for the Pragmatic Programmers? The one that did pretty well sales-wise and had one of the most active forums on pragprog.com? The one that got shelved after we’d written 200 pages when it appeared that Apple planned to somehow never drop the NDA for the iPhone SDK, even for released versions? The one that started as an iPhone OS 2.0 book and then slipped enough to be one of the first really comprehensive iPhone OS 3.0 books?

Also the one that didn’t get updated for iPhone OS 4.0?

And now that Xcode 4 is out, the one that’s getting us e-mails from new readers who send us screenshots of their Xcode 4 windows and asking “how can I make this look like the screenshots in your book?”

And the one that teaches rigorous memory-management practices that will be somewhat obsoleted by iOS 5’s Automatic Reference Counting?

Yeah, that one. There’s finally going to be a new edition of it.

Contracts were signed a while back (something of a gesture of faith, given the fate of my last two books with the Prags), editor is on-board, first chapter and a half is written (about 55 pages in the PDF), regular editorial meeting is finally happening… this ball is rolling.

Given how the first edition bloated to more than 500 pages as we found new stuff we had to cover, my proposal splits the book into two volumes. The first is foundational: tools, language, best practices, etc. We’re taking a whole chapter up front to really dig into Xcode 4, and another for C and Obj-C, which we think will help current iOS developers thrown for a loop by changes in Xcode and new coding conventions like blocks, class extensions, and of course ARC. And yes, I said C — we’re dropping the “we assume you already know C” business because not enough readers do, and will do a short catch up on pointers, typedefs, malloc(), and all that C stuff that trips up so many converts from scripting languages (see also this slide deck, which serves as inspiration for the section). We’re also covering debugging much earlier this time, to help readers get themselves out of trouble when they crash on a EXC_BAD_ACCESS.

The specifics of the various feature frameworks are reserved for the proposed volume 2. That way, I’m not trading pages, tempted to cut back something fundamental like unit testing in order to squeeze in a flashy new AV Foundation thing.

This is going to be an iOS 5 book through and through, more or less a full-on rewrite. Because of the NDA on iOS 5, that means you won’t see any pages from it, not even through the Prags’ beta program, until iOS 5 ships and its NDA drops. So, we’re talking “Fall” here.

Oh, and there is one more thing…

For the first edition, I co-wrote the book with Bill Dudney, author of the much-loved Core Animation for Mac OS X and the iPhone: Creating Compelling Dynamic User Interfaces book. You might also know Bill as an Apple developer evangelist, who gave a great WWDC 2011 talk on “Practical Drawing for iOS Developers” (Session 129… look it up). Bill wasn’t available to co-write this book, because Apple employees can’t contribute to third-party books.

Then again, if you follow Bill on Twitter, you might know that Bill left the company last week and moved back to Colorado.

Which means that Bill can, and in fact, will be co-writing the new edition. In fact, we’re co-ordinating our blog posts on this, so you can go read his announcement right now.

We have a lot of stuff to cover, but it’s a good problem to have: I’ve come around on Xcode 4 and I’m actually eager to talk about it, and iOS 5 gives us a great foundation for a new title.

So see you in September… or whenever the NDA drops. And before that, Bill and I will both be at CocoaConf in Columbus, OH, on August 12-13. Take a look at the session list; this one is shaping up really nicely.