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.

Monday, April 26, 2010

Flex 4's layouts, animations, and interpolators

Below is an applet that demonstrates three new Flex features:
1. Custom layouts
2. Generalized animations
3. Custom interpolators

The applet, called AngleTest (source code here), shows the notes of the diatonic scale (Do, Re, Mi, etc.) placed around a circle:


Re is at the top to make the symmetry of the diatonic scale more obvious (because horizonal or vertical symmetry is much easier for human brains to recognize than symmetry along any other axis).

Initially, the scale is in Do-mode ("major," or "Ionian"). You can tell, because degree number 1—in green, to make it stand out—is next to Do.

If you click the "Next Mode" button (in the upper-left corner of the applet), the degree numbers change to reflect their positions in Re-mode ("Dorian"). Degree 1, in green, is now next to Re.

I don't know about you, but I find that sudden change of numbers, in place, to be almost impossible to follow. What changed, exactly, and how?

So, I added an "Animate" checkbox, also towards the upper-left corner. Click it, so that a checkmark appears in its check box, thereby enabling animation. Now, click the "Next Mode" button again.

Cool! The degrre numbers slide smoothly from one note-name to another, showing—with much greater clarity—the relationships of the modes to the underlying scale. That's due to the interaction of two new Flex features: (a) Flex's new custom layout feature, which my code uses to place each degree label at the angle specified by its "angle" property, and (b) Flex's new generalized Animation effect, which smoothly animates the angle property between values.

Er, hmmm, but...there's a problem. One of the degree numbers rotates in the wrong direction! Whichever degree label is on Mi goes all the way around the circle counter-clockwise to Fa, instead of going clockwise a short ways to Fa. WTF?

The problem is fairly simple, actually: Mi's angle is 330 degrees, and Fa's is 0 degrees. The natural way to interpolate the numbers between 330 and 0 is downward, through 300, 200, 100, and so on down to 0...and that's exactly what the Animation effect's default interpolator does. That's the only interval on the circle in which a degree label is moving from a large starting angle to a small ending angle, so it's the only interval for which the degree label goes the wrong way.

What we need here is a custom interpolator -- an *angle* interpolator -- which recognizes that angles fall on a circular continuum, rather than a linear continuum.

In the "Interpolator" panel, just below the "Animate" checkbox, are two radio buttons that let you select whether to use Animate's default "Number" interpolator or my custom "Angle" interpolator.

The "Angle" interpolator keeps all of the degree labels moving clockwise.

It isn't commercial-grade, though. I'm pretty sure that the increment and decrement methods aren't right, but my code doesn't need those functions so I haven't tested or revised them accordingly. (You've been warned!)

The layout of the note-names is a little off, too. I'm not sure why. I think that it's because the bounding boxes of the labels reserve space for descenders -- the bits of letters like 'y' and 'p' that stick down below the rest of the text. Not sure, and for now, don't care -- it's good enough for Version 1.0.

When I look at other people's sample Flex code, I am frequently stunned by the amazing effects they are able to get out of a tiny bit of code. My code's not like that. I seem to have to write reams of the stuff.

For example, the arcs that show the widths of the seconds around the circle—the red and blue arrows—are, well, *arcs*, and Flex's new FXG graphics code does not support arcs. Theoretically, one can program them using cubic Bezier curves, but I seem to have missed that post-graduate mathematics course. Instead, I kludged them up in Adobe Illustrator, ran Illustrator's output through Adobe's Flash Catalyst, and pasted the result into my app. The result looks fine, but involved reams of impenetrably-complex MXML/FXG that's almost certainly longer than necessary. But...hey!  It works, and that counts for a lot.

Labels: , ,

Wednesday, March 17, 2010

Rendering Notes into Text

I'm a bit torn by a code architecture problem. A "Note" is a point in 2D tonal space, defined by the number of octaves and fifths that it is away from the origin note [0, 0] (which is also known as Re0). On the one hand, an abstract data type such as Note should not know anything about how it is rendered into graphic images or into text. The note [-2, 4] can be rendered in text as
  • the string "[-2, 4]"
  • the Text Layout Framework "TextFlow" data structure that represents "Fi0"
  • ...and so on.

Likewise, the interval [-2, 4] can be rendered as
  • the string "[-2, 4]"
  • the string "major third"
  • the string "M3"
  • an arrow pointing from a given note to another note two notes rightward
  • ...and so on.
The question is, what entity should render a given note (or interval) into a given text string?

The simple/stupid thing to do is have a method in the Note class, called something like toString(), that renders 'this' note into a canonical text form (e.g., "[-2, 4]"). Because strings are such a basic data type, having the Note class "know about" (and hence depend on) the String class is perhaps not a terrible violation of encapsulation.

But what about the rendering "Mi0"? To produce this, the Note class would have to know about (and hence depend on) the classes of Flex's Text Layout Framework, which is a pretty clear violation of Note's encapsulation.

Likewise, an Interval can be rendered into at least three different text strings ("[-2, 4]", "major third", "M3"). Should the Interval class implement methods for all of these different renderings? What if I want to add a new rendering? After doing so, I'd have to recompile all of the classes that used the Note class. Currently, my code base is small enough that this would be no big deal, but once I've got dozens of lessons, this kind of change could lead to a testing nightmare.

It seems to me that I've encountered a classic example of where the Factory design pattern is appropriate. I think I need a separate entity -- something that is not a Note, but which knows about Notes -- which renders Notes into...somethings.

There's be an abstract RenderNote class, with a method that would, given a Note, return an Object containing its rendering. RenderNote would have an abstract RenderNoteToString subclass, which would return a String for a given note. RenderNoteToString would have the subclass RenderNoteToStringVector, which would return the string "[-2, 4]" for the example note.

Then, RenderNote would also have a RenderNoteToTextFlow subclass, which would return a TextFlow (e.g., "Fi0") for a given note.

There would be a similar RenderInterval class hierarchy.

This all seems very complicated (as Factory deisgns usually are), but it would cleanly separate the text-rendering function out of Notes and Interval into separate classes. If, later on, I needed to render Note objects into a new kind of text representation, I could just add a new subclass to the RenderNote hierarchy; no recompilation or testing of the existing codebase would be necessary.

The result would be very much like Flex 4's use of "skins" for the graphical rendering of a UI control. The "RenderX" class could be seen as a "text skin," so to speak.

But...do I really want to mess with all of that complexity now? Or should I just slam a toTLFName() method into the Note class, and refactor it into a Factory if and only if it becomes a problem?

I think I'll do the latter.

Labels:

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: , , ,

Thursday, May 7, 2009

iGetIt! Keyboard v.000002 (with source)

Now that I understand that Flex 3's View Source problem is an official bug, here's:

...the latest iGetIt! keyboard:









...and a link to its source code:
www.igetitmusic.com/blog/SWFs/TestApp1/srcview/index.html

Labels:

ViewSource: Officially a bug

It's official: the problem I've been encountering with Flex's ViewSource feaure is a bug. Here's the page from Adobe's official bug reporting system:
http://bugs.adobe.com/jira/browse/FB-19253

It had already been reported, and has been fixed in the next version, which is still under development (expected to be released in Q4-ish of 2009).

It is comforting to know that the next version will fix the problem. But I'm not just comforted; I am validated; encouraged; even elated -- much more than I had expected to be. Given my long hiatus from computer programming (and the failure of Thumtronics), my confidence is not what it once was. I tend to assume that everything that goes wrong is my fault; that I "don't get it;" that this stuff must be really hard.

Yet this ViewSource problem is not my fault. I did understand it. It's a bug. The beam is not in my eye, but rather, is a mote in my brother's. I was right.

That's encouraging! :-)

Onward!

Labels:

Wednesday, May 6, 2009

Offshore tech support

I've posted help-requests to a number of Flex developer forums (including Adobe's) without getting any satisfactory answers. So, I've started looking into hiring offshore Flex developers to help me with tech support questions on a per-incident basis.

On the one hand, using a (cheap) offshore tech support service could help me climb the learning curve faster.

On the other hand, it *does* make me wonder if I could make a living as a computer programmer in America anymore. If I can cost-effectively outsource my tech support questions to offshore developers, then I could outsource the development of entire components offshore, or perhaps even whole applications.

On yet another hand, it's one thing for me to send a tiny little test app to an offshore developer, asking him to fix a very clearly-defined bug that I just don't know enough to fix myself. It's quite another thing for me to draw up a spec for (say) my QWERTY keyboard control, or for my entire music education courseware. I thought up new functionality for the QWERTY keyboard component as I wrote it -- for example, changing the color of the buttons to reflect the current scale. That's going to affect the design of my other controls, too. I never would have included that in the QWERTY keyboard spec, because it was the process of developing the component myself that led me to think of it.

I've contacted ExpertsFromIndia and Catalytic Software. I also signed up as a buyer on RentACoder. I had a bad experience getting projects done on RentACoder before, but for little tiny tech support questions it ought to work OK.

From what I know now, I'd prefer to go with Catalytic, because I know and trust the folks who run it -- ex-Microsofties that I worked with Back in the Day. Will they be cost-competitive? I'm not sure. Catalytic's main added value is its American management, extremely skilled and knowledgeable staff, and its overall professionalism. Those things cost money. For any serious mission-critical, big-ticket project they would be my absolute first choice vs. anyone else anywhere in the world, but...for piddly tech support questions and a few little Flex components? I suspect that Catalytic might be overkill. I would be delighted to discover otherwise.

Labels:

Sunday, May 3, 2009

View Source Redux

Well, I'm getting closer.

If you click on this link:
http://www.igetitmusic.com/blog/SWFs/Tweener/Tweener.swf
...the Tweener app will come up. It doesn't do anything interesting.

Now, right-click (or, on a Mac, Command-click) on it, and a menu will appear; choose View Source, and voila, you're taken to a little applet that allows you to view Tweener's source, which it correctly looks for in http://www.igetitmusic.com/blog/SWFs/Tweener/srcview/index.html.

Coolness! Love it! Kudos to Adobe! :-)

But, if I embed Tweener's SWF -- using a reference to exactly the same file, mind you (i.e., http://www.igetitmusic.com/blog/SWFs/Tweener/Tweener.swf) -- into this blog entry, then the View Source menu item for the embedded SWF does not work, because it incorrectly looks for the source code in http://www.igetitmusic.com/blog/srcview/index.html.

Here is such an embedding of Tweener:







Bring up its View Source menu, select it, and voila! you're taken to the wrong @#$%& page.

Apparently, the Tweener SWF contains an algorithm -- generated by Flex Builder, not me -- that constructs a path to where it expects to find the source code for its View Source menu item. This algorithm appears to be based on the path to the file in which the SWF is embedded, rather than the path to the SWF file itself.

But...that's a bug, isn't it? If I want to embed a given SWF in (say) ten different web pages, then using the source-path algorithm than Flex is currently using, I'd have to copy the SWF's source code to each of those ten web page's servers...which I can't possibly know in advance. That's a major violation of information-hiding, isn't it -- in addition to being a huge pain in the posterior.

I would think that a much better default behavior would be to look for [somepath]/foo.swf's source code in [somepath]/srcview/index.html, no matter what the path to the html in which foo.swf was embedded.

What am I missing, here?

Labels: ,

Design Patterns Are Unimplemented Language Features

It seems to me that design patterns are nothing more (and nothing less!) than recipes for systematically maximizing the benefits of information-hiding (Parnas, 1972). Everybody knew that information hiding was good, but...how did you DO it, exactly? Design patterns provide well-defined recipes for many common architectural problems -- recipes that push an application's inevitable fragility out to its fringes.

It also seems to me that many of these patterns exist only to overcome the deficiencies of imperative, statically-typed programming languages.

Parenthetically -- I was always a bit of a language slut, and being Microsoft's evangelist for the .NET Common Languge Runtime ("Project 7") allowed me to indulge myself by interacting with Bertrand Meyer (Eiffel), Niklaus Wirth (Pascal/Modula-2/Oberon), Simon Peyton Jones (Haskell), Luca Cardelli (ML), Zoltán Somogyi (Mercury), and a host of others. We got their languages working on the pre-release version of the .NET Runtime and Visual Studio.NET, and used these implementations to identify architectural weaknesses in (and potential improvements to) .NET's design. I particuarly enjoyed working with Erik Meijer (on Haskell), whom I helped hire out of the University of Utrecht into Microsoft Research, where he developed LINQ. What fun! :-)

Back to the point -- each subsequent generation of programming languages succeeds by providing a higher level of abstraction over the previous problem-solving tools, thus making it brain-dead simple to do something that was previously difficult. For example, I'm old enough to remember hand-coding vTables in order to do object-oriented programming in C. Then, C++ coded vTables for me -- yahoo! C++ made it trivially-easy to code vTables, because the language did it instead of me. Likewise, Java trivialized programming interfaces (and other information-hiding techniques). Dynamic languages take this a step further, and functional programming languages another step after that. The rise of PHP, Ruby, Python, etc. are examples of the abstracting-away of programmers' pain-points. This is usually expressed in terms of "increased programmer efficiency," which is the result of such abstraction. (Importantly, Moore's Law makes the computing burden of these ever-increasing levels of abstraction affordable).

However, offering a valuable abstraction is not, in itself, sufficient to drive a new language to success. It also have to promote itself as the Gateway to a Proftable Career. Java's provides the clearest example of this. Objective-C is making a comeback as the de facto standard language for iPhone programming, due to the iPhone's popularity.

ActionScript 3.0 is a fairly old-fashioned declarative language, compared to (say) Scala. As such, it does not provide the asbtractions needed to trivialize the GoF's design patterns. Even if I were able to find a lovely little dynamic/functional tool suite (language, framework, IDE, etc.) for the Flash Player, there are no job openings for those who have mastered that tool suite, as there are (and will soon be even more) for ActionScript/Flex/FlexBuilder. Equipping myself with salable skills is an important sub-goal of this development project, so that I can help pay for the continued development of JiMS iGetIt! Music System through contract programming.

So, for now, I'm just going to have to wade through these design patterns, and learn to do them the hard way, like everybody else.

Sigh.

Labels: , ,

Saturday, May 2, 2009

Conservation of Fragility

In boning up on design patterns, I keep encountering claims that the proper use of design patterns reduces an application's fragility (or increases code reuse, or enhances its rubustness in the face of changes, or some such equivalent wording). I don't think that this is sttrictly true. Fragility is conserved; the more code you have, the more fragile it is. That's unavoidable; it's like gravity (more mass, more weight).

What design patterns give you, though, is a means of pushing that inevitable fragility away from an application's core, out towards its outer fringes, where the *consequences* of that fragility are lower. When code breaks at the core, it's expensive to fix, becuase the break affects all of the other code; but when code breaks at the fringe, it's cheap to fix, because only nearby fringe code is affected.

Labels:

The Shape of Frustration...

All I want to do is draw a frickin' arrow.

Clearly, this is a job for Flex's "Shape" class. So I write a nice little subclass of Shape called Arc, which draws a circle-segment from beginAngle to endAngle. The details aren't relevant, because the code never gets far enough for the details to matter.

In the test application's MXML code, I add an Arc object:
a:arc id="theArc" width="300" height="200" y="0" x="0"
No problems there; the Arc object is instantiated, its constructor is called, all is spiffy-keen. I'll just set the arc's radius to half of either the Shape object's width or height, whichever is less. No worries, right?

Except that, when the constructor is called, the width and height of the Arc are both 0 (zero). Excuse me? Well, maybe that's because its properties haven't been initialized yet. No worries; there's a handy-dandy event called "CREATION_COMPLETE" that one can listen for, just for this purpose.

But noooooo. CREATION_COMPLETE is an event of class FlexEvent, and Shapes don't post events of that class. Reading the documentation for the Shape class and its ancestors, there appears to be no equivalent event.

Well, fine, whatever, I'll write a brutal hack: in Arc's constructor, I'll (a) set the radius to NaN (Not a Number), (b) add a listener for events of type ENTER_FRAME (which ARE available to Shapes), and (c) in that listener's code -- which gets called very frequently, which is why this is such a brutal hack -- check the radius, and if it's NaN, set it to the proper value, based on the arc's width and height. Disgusting, perhaps, but it ought to work.

But noooo. When the code gets to the ENTER_FRAME event, the width and height of the shape are still zero. WTF? I check the Shapes docs, and yes, they have width and height properties. For some reason, they just aren't being initialized from my MXML.

This is totally bizarre...but it gets worse.

As a test, I set the width and height of the arc explicitly in the ENTER_FRAME code, as follows:
width = 162;
height = 100;

So, Mr. Smarty-Pants Flex Framework, you don't to initialize my parameters? @#$%^* you, I'll initialize them myself.

But noooo! I step through the execution of the code with the debugger, and to my amazement, the above code does not change the values of width and height! *Other* stuff changes; for example, the value of the Arc's inherited "transform" property, previously null, points to a flash.geom.Transform object after the call to "width = 162;" and the value of the inherited property "visible" changes from false to true...but the width property remains zero! Same with the height property. WTF?

OK, so I'll just step through the Shape code, and that of its ancestors as necessary, to figure out what the @#$%^*& is going on. Source code is the ultimate documentation, right?

But noooo! Shape's code isn't accessible using Eclipse's usual click-on-the-class-name-and-its-source-file-opens mechanism. Every time I do the click, instead of seeing the source code, I get a @#$%^ alert titled Code Navigation Error telling me that
"Source code could not be found for [the Flex class I clicked on] in /eclipse/Adobe Flex Builder 3 Plug-in/sdks/3.2.0/frameworks/libs/player/10/playerglobal.swc."

@#$%^*&! Mother-@#$%^&-ing piece of @#$%!

OK, fine, whatever. Om Mani Padme Hum. I am One with the Universe. That which does not kill me, and all that.

Screw width and height, anyway. Who needs 'em. I'll just draw an arc with hard-coded numbers.

Nothing is drawn.

Well, maybe my arc-drawing code is wrong. I'll just call the built-in drawCircle() method instead, just to see that i can draw SOMETHING.

Nothing.

Do I have my graphics environment set right? Yep, I'm calling lineStyle(5) to set a wide black line, and beginFill(0) to fill the circle with black. Nothing.

The source code for some of Flex's classes is available -- UIComponent, for example -- but not for others. Not for the ones I need now. Googling "Code Navigation Error" and "Source code could not be found for" has turned up no fixes, workarounds, or brutal but embarassingly-effective kludges.

So, I'm dead in the water. I simply cannot figure out how to draw a Shape in Flex.

Here's a stripped-down version of the app, with just a tiny MXML file and a short, heavily commented TestDraw.as class that shows the problems:



Of course, the application does absolutely nothing.

Furthermore, I still can't get the @#$%^&* "View source" menu item to work. In the sample app above, for example, it insists on trying to find a file at "http://www.igetitmusic.com/blog/srcview/index.html", even though the app is at "http://www.igetitmusic.com/blog/SWFs/Tweener/Tweener.swf". I have not been able to find *any* documentation -- not one word -- on how to set this pathname.

For example, the book "Flex 3: Training from the Source" -- which is not a bad book, overall -- has a chapter titled "Deploying Flex Applications." Sounds perfect, right? Unfortunately, like everything else I've been able to find on this topic, the chapter says "choose Project -> Export Release Build, and you're done!" -- when, actually, that's just the first step. Executing the "Export Release Build" command produces a bunch of files in the project's bin-release folder. Cool! But...now what? Which files need to be copied to the file server? How *exactly* do I tell a web page to include the resulting Flash doohickey? Should I tell the web page to include the doohickey.swf, the doohickey.html, or one of the other files in the doohickey project's bin-release folder? And how, for the Holy Love of God, does one define the path to the doohickey's source code?

I am not frustrated by computer programming. I LOVE computer programming. What is frustrating is NOT being able to do computer programming due to chickenshit problems like those above.

THAT is *incredibly* frustrating...

Labels: ,

Thursday, April 30, 2009

Adobe's Flex forum

I have discovered what may prove to be a very helpful resource: Adobe's Flex forum. It appears to be a reasonably well-organized community self-help forum, in which Flex users are encouraged to post their questions and answer those posted by others.

Back in the day (by which I mean "the late 1980's," before many of today's eager young Flex programmers were born), I participated regularly in a similar forum: MacApp.Tech$, devoted to MacApp, the first widely-used object-oriented application framework. It took me a while, but I eventually posted a lot more answers than questions. I hope to be able to be similarly useful to the Flex forum's participants, eventually.

Labels: ,

Design Patterns

I stopped programming professionally on February 3rd, 1992, when I joined Microsoft as a Technology Evangelist. After that, any time I needed sample code showing how to use some new Microsoft technology, it was more effective for me to have a consultant code it up than to code it up myself. That way, I'd have the code, and a consultant that was up-to-speed on the new technology, too. I could then aim that consultant at companies who I knew were struggling to implement the technology themselves. Very efficient.

Unfortunately, this put me increasingly out of touch with rapidly-evolving programming practices.

A good example is the notion of "design patterns," which were first described (to my knowledge) as such in late 1994, nearly three years after I'd stopped programming. This is a double whammy, for two reasons.
  • First, I don't understand "design patterns." It's another learning curve I have to climb. It's clearly possible to climb it, and I will make it to the top eventually, but it's just one more damn thing between me and my objective.
  • Secondly, and more importantly, in the 15 years since "design patterns" were first described, they have become so deeply absorbed by the professional programming community that knowledge of these patterns is simply assumed. This is a huge pain in my ass.
For example, I eventually figured out that, to meet my need for "growing arrows," I would need to implement a custom Tween effect associated with a custom Arrow component. So I read Adobe's online article About Tween Effects, which drove me nuts. It seemed to be using three classes (Tween, TweenEffect, and TweenInstance) to do something that I thought could just as well be done by a single class. Since I'm trying to *understand* what I'm doing, rather than just programming by numbers, this apparently-neededless complexity was a real barrier to my progress. Adobe's documentation said nothing about why this complexity was present.

Then I noticed the word "factory," just once, in the About Tween Effects documentation:
  • "mx.effects.TweenEffect: The base factory class for all tween effects."
I vaguely remembered once knowing the meaning of the phrase "class factory," which gave me just enough information to connect the dots from the documentation to the design pattern. So, I drive over to my local Barnes & Noble and bought the original Design Patterns book, plus another written specifically for Actionscript 3. These are ladders of knowledge, helping me scale yet another learning cliff.

I recognize that my situation -- of returning to programming after a 17-year hiatus -- is not common, and that Adobe can not reasonably be expected to write its documentation to accomodate such an uncommon reader. However, it does not seem unreasonable to suggest that, when a given feature of Flex relies on a specific design pattern, the feature's documentation should say so, and perhaps even refer to an online description of that pattern.

I do enjoy learning new things, but I *am* first and foremost trying to get a product out the door. It seems like I'm having to do a depth-first search among the roots of every darn language, tool, and framework, platform, and paradigm I encounter along the way -- and I have no idea how many more of these diversions I'm going to encounter. The number seems to be unbounded. That makes it very hard to plan ahead. This concerns me.

Labels: ,

Wednesday, April 29, 2009

Animating an arrow along a path

In many places in my courseware, I need to be able to draw animated arrows -- arrows that start at Point A and grow along a line/curve/path towards Point B, thus indicating through their growth the direction of movement.

This seems like it ought to be a fairly common animation task, but I can't figure out how to do it in Flash, without using a zillion key frames, which kinda defeats the purpose. Google hasn't been able to point me in the right direction. I don't want to take the time to code a component for this, but I may have to do so.

Labels: ,

Tuesday, April 28, 2009

From components to lessons

I'm now happy with the current state of my "keyboard component" and the structure of the surrounding application. It's not entirely customer-ready, but it's in good enough shape that I need to start *using* it. That should expose a lot of weaknesses (and, perhaps, strengths) that I would not discover otherwise.

Therefore, I'm going to shift my focus from the development of components (using Flex) to the development of lessons (using Flash). I've hosted the www.igetitmusic.com domain using GoDaddy's free service, and will start developing lessons, which I will post there. I'll shift this blog over there shortly, too.

The free hosting service imposes a number of advertisements on the site, which I won't to have up there once the site is "legit." For now, though, I need to keep my burn rate to an absolute minimum, so I'm happy to have a free hosting option, ads or no ads.

With some help from Jeffrey Houser, I've almost figured out how to share my source code, so I'll be getting that up soon, too.

Labels:

Thursday, April 23, 2009

The Prime Scales

On a piano keyboard, the notes of the C Major scale have one shape and color (the "white keys"), while the notes that are chromatic to C Major have a different shape and color (the "black keys"). This seems awfully arbitrary. Why C? Why not A, B, or Bb?

On a digital piano, one can easily transpose the keyboard so that any given diatonic scale's notes fall on the white keys. That's cool. But what about other scales? There's more to music than the diatonic scale.

One of the nice things about a "virtual" on-screen keyboard is that one can change the way individual buttons are drawn "on the fly." That allows us to draw the notes/buttons that are in "the current scale" one way, while drawing those that are out of the scale a different way.

The latest version of my Flex iGetIt! keyboard, shown below, allows the user to select one of the Prime Scales from a ComboBox, with the coloration of the keyboard's notes/buttons changing accordingly. The notes of the current scale are the "white keys," whereas the out-of-scale notes are the "black keys."


Why is this a "good thing"?

There are scads of "scale books" that describe scads of "scales." I don't understand this.

As far as I can tell, there are really only a half-dozen scales that are relevant to tonal music -- the previously-mentioned Prime Scales. The scale books are fat with "scales" because

  • they confuse scale and mode, treating different modes of the same scale as if they were different scales, and
  • they confuse scale and key, treating different keys of the same scale as if they were different scales.

This conceptual confusion can lead to a combinatorial explosion of "scales." Do the math: six Prime Scales times seven modes per scale times fifteen possible keys is 6 * 7 * 15 = 630 possible "scales." Six hundred and thirty! From an educational perspective, that might as well be "infinity." No wonder people hate learning scales! Using the traditional instruments, notation, and theory, there is no end to it. You could study and practice your whole life and never master them all.

I don't see the point. This explosion of "scales" is an artifact of traditional music technology (i.e., traditional instruments and notation). They are not meaningfully distict, except that -- using traditional technology -- they require different notation and different performance gestures. The explosion is not a theory problem; it's a technology problem. Using JiMS, you only have to master the six Prime Scales. Six! That's less than 1/100'th of the traditional number. Two orders of magnitude!

More importantly, by clarifying the relationships between scales, modes, and keys (and chords, and melodies, and tunings, and so on), JiMS inter-relates these important musical concepts, thereby providing a strong theoretical foundation for understanding music.

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: , , ,