Online music education courseware for non-musicians who want to learn how to write their own rock songs.
About Me
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.
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.
Here's a new version of SoundTest that sounds much better (source code here):
The difference is that this new version calls sound-generating code from a beta version of the SonoFlash library. Assuming that this library will be offered at a reasonable price once it is released in final form, I expect to use it for most of my courseware's lessons.
Adobe has a list of requested features that one can vote for, and MIDI is on the list, but apparently it has never made the cut. Perhaps Adobe should acquire SonoFlash, and use its team (and cross-platform sound engine) to implement MIDI in Flash.
Click either "Play" button; a note will sound, and the button's name will change to "Stop".
Click the same button again to silence the note; the button's name will change back to "Play."
Click the other "Play" button; a different note will sound (an octave higher than the first note); click it again to silence it.
So far, so good. :-)
Here's what doesn't work:
Click on either "Play" button, sounding a first note.
Click on the other "Play" button, sounding a second note while the first button is still sounding.
Bad things now happen. The sounds do not blend (as one would expect octaves to do), but instead grate against each other in a nasty alternating, overlapping grind. Also, the application's performance slows to a crawl. Click on either button, to silence its note, and you'll see that it takes forever for the button to respond to the click.
I'm not sure how to fix this. The code seems to be working as intended. The flaw seems to be in how I'm using Flex/Flash's sound architecture -- that is, my tactics are correct, but my strategy's wrong.
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. ;-)
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 implicitbar.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, retaineddraw() 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.
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.
To develop my forthcoming music education courseware using Adobe'sFlash/Flex/AIR, I'm developing a suite of components that display and control musical information. This is going well, considering. Although I have a Computer Science degree, I haven't written a line of code since 1992...17 years ago. Climbing up the Flash/Flex/AIR/ActionScript/Eclipse/XML learning curve is fun but challenging.
My first Flash control is a slider that allows the user to choose a frequency (it works best if you drag the thumb slowly):
No big deal, but writing it helped me understand a lot of stuff, including Flash 10's new sound synthesis API SampleDataEvent.
I've seen other posts in which the source code to such controls is easily available (by right-clicking on the control and choosing "View Source" from a pop-up menu), but I don't know how to support that feature. I can't find any documentation for it; apparently it's so "obvious" that it is never described. If a reader could please tell me how to add support for Flash's "View Source" feature -- in full newbie-tutorial detail -- I'd be happy to make the code available for this and subsequent iGetIt! controls. (iGetIt!'s proprietary value is in the patent-pending iGetIt! Music System and the lessons based on it, not in its Flash controls.)
I expect to use the PitchSlider control (or something like it) to show the student that musical pitch (frequency) is continuous, varying in a smooth and unbroken manner. Some frequencies have names (such as 440Hz, which is named A4), and some do not, but all are musically equal. The structure of music is the same for all frequencies. Obviously, this ignores a ton of psychoacoustic issues like the human ear's range of hearing and critical band, but... close enough, as a first approximation.