iGetIt! Music

Online music education courseware for non-musicians who want to learn how to write their own rock songs.

My Photo
Name: Jim Plamondon
Location: Austin, Texas, United States

This blog documents the development of JIMS iGetIt! Music System (JIMS). JIMS' goal is to help you Understand Music in 24 Hours™, if you are (a) a non-musician (b) who wants to learn how to write your own rock songs. Requiring no instrument other than your own computer, and without using traditional notation, JIMS is being designed to deliver a deep understanding of tonal structure...in just 24 hours.

Thursday, June 18, 2009

Passing arguments to Flex event handlers using closures

Today, with help from my new friend Jack Kennedy (in San Antonio) and various online sources, I learned how to use "closures" to pass arguments to event handlers in Flex. I remember learning about function closures in a abstract way when studying for my Computer Science degree back in the mid-1980's, but I'd never had the opportunity/need to use them professionally. They weren't supported by any of the languages I was using then, but they are more widely supported now. They are supported in ActionScript 3.0.

Here's the problem I faced this week. I wanted to use a Flex timer to drive an animation, so I created a Timer object and registered an event listener function on it. The listener callback would be called whenever the timer dispatched a TIMER or TIMER_COMPLETE message. But...the callback function needed to access information that was not available within the scope of the callback function. I could put that information into a global variable, but that would smell bad. There did not seem to be a way to hook Timer to dispatch a custom subclass of TimerEvent, which was my first thought -- and my local info wouldn't be available to Timer's TimerEvent factory, anyway. I was stumped.

I recalled that Jack had mentioned, over dinner recently, that he used Timers frequently (and Flash animation rarely), so I figured that he must know how to overcome this problem. Between his cogent, concise response to my email inquiry, and some research to help me understand what closures were and how to use them correctly, I got my code working properly.

First, though, I put together this simple test app to experiment with:









Press the "Draw Circles" button, and the code draws a bunch of randomly-sized circles. The first circle is red, with subsequent circles increasing in hue through a cyclic rainbow until reaching red again, at which point all of the circles are erased. Clearly, the callback function "knows something" about color, else it could not progress smoothly through the rainbow as it does. How is the "Draw Circles" button's click handler providing that state information to the TIMER event callback function?

The answer: through the use of a closure. See the code here.
www.igetitmusic.com/blog/SWFs/ClosureTest/srcview/index.html

All of the magic happens in drawCircleHandler(). Here's the code from inside of drawCircleHandler() that registers the callback function for TIMER events:
// pass args to TIMER event handler using a "closure"
var count:Number = 0;
t.addEventListener(TimerEvent.TIMER,
function TimerHandler():void {
// Every time TimerHandler() is called, it increments
// drawCircleHandler()'s local variable "count"
count += DEGREES_IN_CIRCLE/MAX_CIRCLES;
drawColoredCircleInComponent(degreesToRGB(count), cCanvas);
});

(Clearly, I need to figure out how to embed pretty-printed source code in these blog posts.)

The essential point is that TimerHandler(), being defined within the body of drawCircleHandler(), can access drawCircleHandler()'s local variables, such as "count". Every time TimerHandler() is called by Flex's event-dispatching code, it increments the value of "count". This is rather magical, since drawCircleHandler() will long since have completed its execution by then, so one might think that its local (stack frame) variables would have been liquidated. But apparently, the closure's environment is allocated dynamically (from the heap) and retained (i.e., not garbage-collected) so long as anything points at it...anything, including as a Timer's listener-list.

You'll note that "count" is incremented in TimerHandler(). That wasn't my first design. First, I passed "count" into drawColoredCircleInComponent(), in which I incremented it and calculated its RGB equivalent. I figured that since "count" was a Number and therefore an Object, it was being passed by reference, so anything I did to "count" inside of drawColoredCircleInComponent() would act on the local "count" in drawCircleHandler(). Not so; the value of "count" stayed zero -- its initial value. Bummer.

In the second design, I incremented "count" in TimerHandler() and then passed it into drawColoredCircleInComponent(), where its RGB equivalent was calculated. This worked, but it didn't smell right -- why should drawColoredCircleInComponent() know about both "count" and color? My first design had the same smell, once I thought about it. It smelled better -- to my nose, at least -- to have TimerHandler() do handle both incrementing "count" and the calculation of its RGB equivalent, thereby localizing the semantics of "count" within the scope of drawCircleHandler().

That's my story, anyway, and I'm sticking to it. ;-)

Thanks, Jack! :-)

Labels: , , ,

Monday, May 18, 2009

Retained Mode Considered Harmful

I think I've made a small step towards figuring out how drawing works in Flex. Flex's drawing system appears to use a "retained mode" approach, in which the calls you make to "draw stuff" don't actually draw stuff. Instead, they (in effect) define a (new, hidden, secret, inaccessible) method which Flash/Flex uses to draw stuff whenever it feels like it.

Here's a tiny little test applet, called "bar" (because "foo" was already taken):







The above applet draws a small black circle that slides across the applet from left to right, eventually leaving the stage. No biggie...but it's drawing, which is big progress for me. ;-)

Here's a link to the above applet's source code, bar.as:
www.igetitmusic.com/blog/SWFs/bar/srcview/index.html

This source code is a minor variation of recipe 11.1, "Moving an Object," from O'Reilly's ActionScript 3.0 Cookbook.

In bar.as, a class bar is declared to extend Flash's Sprite class. (Yes, I know that bar should, by ActionScript/Flex convention, be capitalized as Bar, because it is the name of a class. Gimme a break. It's not germane.)

Every bone in my body tells me that this code is INSANE. All of the drawing code is in bar's CONSTRUCTOR, fer cryin' out loud. How can this code be *found*, let alone called, when an instance of bar is to be drawn?

I would expect that this drawing code would be placed in a draw() method of the bar class (i.e., bar.draw()), which would be called by Flash whenever an instance of bar was to be drawn, and that this draw() method would be an override of a draw() method inherited, ultimately, from Flash's DisplayObject class (from which bar's superclass, Sprite, descends). But neither DisplayObject nor Sprite have a draw() method, or anything similar to a draw() method. (They do have a RENDER event, but it is used to advise an object that it is about to be rendered; it is NOT a request that the receiving object now render itself.)

It gets weirder. Every time the Flash player needs to draw a new animation frame, it dispatches an ENTER_FRAME event. The bar class listens for this message in its onEnterFrame() method. No problems there. To animate the circle rightwards, I would expect bar.onEnterFrame() to (a) shift the location of the bar instance slightly rightward, and then (b) call bar.draw().

But nooooo! As I mentioned above, bar has nothing like a draw() method, nor does any of its super-classes. The only thing that bar.onEnterFrame() does -- and remember, I stole this code *directly* from the published, well-regarded recipe mentioned above -- is offset the bar object slightly rightward (more on that later). That's it. There's no drawing code in bar.onEnterEvent() at all, nor any calls to any other drawing code.

Somehow, the Flash player is accessing the drawing code that's defined in bar's constructor, and executing it sometime after bar.onEnterFrame() method is called.

WTF?

I see this pattern all over the sample code for Flash & Flex, from many different authors. Adobe's online documentation for Flex 3 is rife with it. They put drawing code in the class' constructor, or into a function which is only ever called by the class' constructor (to verify this, I've set breakpoints on such drawing functions, and seen that they are never called from anywhere except the constructor).

HOW DOES THE FLASH PLAYER FIND THIS DRAWING CODE, in order to execute it when it's time to actually draw the object?

I'm not sure, but I think I have identified a clue: "retained mode."

Apparently, the Flash player (and hence ActionScript and Flex) uses "retained mode" for all drawing. Unfortunately, only initiates into Adobe's secret society are taught the secrets of "retained mode." It's not documented anywhere that I've been able to find.


If you know where Adobe's use of retained mode is explained in detail, please
let me know where I can find this documentation.


The Wikipedia entry for "retained mode" is cryptic. The phrase "retained mode" does not occur in Adobe's online documentation for Flash, Flex, ActionScript, or Flex Builder. It's a big secret, and you can't really understand drawing in Flash/Flex/ActionScript unless you understand the Secret of Retained Mode. Or, at least, *I* can't. (Maybe I'm just stupid.)

Sure, I could just mindlessly copy other people's sample code, and put all of my drawing code into my classes' constructors. What the heck, it seems to work, right?

However, I've never been able to do that kind of "thought-free programming." It's one thing to reuse a well-documented component without understanding its implementation; that's what components (and their interfaces) are for. It is quite another to re-use a pattern without understanding it; that's a disaster waiting to happen. I want to understand. That makes me a slower "production" programmer initially, but eventually makes me more efficient and creative, because I come to understand how everything works, which allows me to make new and (hopefully) useful insights.

This Cartesian refusal to accept anything that one doesn't understand is *the* fundamental basis of all scientific advancement, fer cryin' out loud, so I'd think Adobe -- which had a strongly scientific culture, last time I interacted with it -- would give scientific skepticism a bit more respect by (for example) documenting its platform's architecture more clearly.

Here's what I think is going on deep in the secret bowels of Flash Player.

All "drawing" is effected by interacting with an instance of Flash's Graphics class. For example, in bar's constructor, the following code is called to effect the drawing of a circle:
this.graphics.beginFill(0x0000f, 100);
this.graphics.drawCircle(0, 0, 5);

this.graphics.endFill();

"this" is the instance of the bar class being constructed. Its graphics property is inherited from Sprite, which is bar's superclass.

Apparently, when you call the method of the graphics property -- such as the calls to beginFill(), drawCircle(), and endFill() above -- the methods don't actually draw anything. The method calls are simply recorded by the graphics object -- that is, they are retained. These method calls are (in effect) defining an implicit bar.draw() method (via delegation to bar.graphics), which Flash then calls whenever it needs to draw a bar instance.

In the bar.onEnterFrame() method, this.x is incremented by delta (initialized to 1 in bar's constructor).
this.x += delta;

Notice that incrementing this.x does not involve this.graphics, so it isn't "drawing code," per se. That is, it doesn't say what to draw, it just says where to draw.

Sometime after this.x is incremented in bar.onEnterFrame(), Flash calls the implicit (secret, hidden, retained) bar.draw() method that it generated from bar's calls to this.graphics's methods.

That is, I think, how drawing happens in Flash/Flex/ActionScript. If this is wrong in any significant way, please let me know.

If this is how it works, then it strikes me as being bad, bad, bad.

Retained mode is an example of self-modifying code, which always makes me nervous. It smells bad. Specifically, retained mode's implicit generation of a (secret, hidden, inaccessible) bar.draw() method makes it impossible to use time-honored object-oriented programming practices to modify a class' drawing behavior. In brief: I can't override a secret, hidden, retained draw() method.

I mean, really: drawing code in the constructor? The single-least-over-rideable method of any class? Are you insane?

I *must* be missing something, here. That just *can't* be right. I hope that someone will point out my misunderstanding and clarify how Flash player's drawing really works.

The opposite of retained mode is "immediate mode," in which calling the function drawCircle() draws a circle, right now. The Mac OS/Toolbox API, the Win32 API, the MacApp framework, the MFC framework -- every API I've ever worked with used immediate mode.

It is only by merest chance that I have any awareness of "retained mode" at all. I was on Microsoft's DirectX evangelism team back in the mid-1990's when Direct3D was first introduced. The first version of Direct3D used a retained mode API to improve efficiency (probably the same reason why Flash uses it). However, Direct3D's use of retained mode confused the heck out of game developers. As a result, they simply refused to use Direct3D, choosing to use OpenGL instead. The next version of Direct3D deprecated retained mode in favor of immediate mode, but it had lost so much mindshare in the meantime that it was a decade before Direct3D finally won over OpenGL's most vocal proponents.

Maybe all of this has changed since I stopped actively programming in 1992. Maybe now all Computer Science students are taught to think in terms of retained mode, so Adobe doesn't need to explain it anymore. Or maybe Adobe doesn't want to explain it; perhaps Adobe has too darn many ISVs already, and it wants to keep out the riff-raff by ensuring that only those who already know the secret "retained mode" handshake can get past the gate. That would be remarkably self-defeating, and although such self-defeating actions are surprisingly common, it doesn't sound like Adobe at all, but...what do I know?

Or maybe I'm barking up the wrong tree entirely, and Flash/Flex/ActionScript's drawing system doesn't used retained mode at all...in which case I'll apologize profusely.

Labels: , , ,

Monday, April 20, 2009

iGetIt! Keyboard v0.000002

Here's the latest version of my keyboard component:


It looks and behaves much better now. I copied and pasted the code from Flex's Button class into a new class (KBButton) and hacked away everything that I didn't need, which was a lot. I then did the same with the Flex classes needed for programmatic skinning, so that I could draw the keyboard's buttons as I saw fit. The drawing isn't perfect by any means, but at least now I know how control-drawing works.

My next step is to move the sound-generation code out of the KBCanvas (which holds the KBButtons) and into a stand-alone Synth class. In effect, the KBCanvas and its KBButtons (and their KBButtonSkins, and so on) will know only about drawing things on the screen in response to NoteEvents, and the Synths will know only about playing sounds in response to NoteEvents. Importantly, that means that the KBCanvas and the Synth will *not* know about the other. I will be able to change the design and implementation of either one completely indepently of the other. The Flex application will act as the central controller, intercepting keypress events from the user's computer keyboard and re-packaging them as NoteEvents. The KBCanvas and Synth will listen for these events, changing their visual/sonic states, respectively, when such NoteEvents occur. The application will keep its current state in a data structure (the "model") that doesn't know about Synths or on-screen views, either. Hence, a nice clean separation of model, view, and controller (with the application as the controller, and the Synth as a sort of "sonic view").

My progress in implementing these custom controls has been glacially slow, by the standards of commercial software development. But right now, speed isn't the point. It's more important that I soak up Flex's design patterns, Actionscript's idioms, and eclipse's workflow, thereby increasing my overall efficiency, than to get these components done "yesterday." I expect that my efficiency will be improving rapidly from here on out (albeit from a still-low level).

Labels: , , ,