The Seven Stages of Learning Dojo

Filed in development | dojo | html5 | javascript | ui | web Leave a comment

So, yah I’m learning Dojo, though from what I’ve heard this could easily apply to ExtJS.  It’s a different mindset to get accustomed to an enterprise Javascript framework, and comes with a bit of a steep learning curve.

And, so it begins….

“Ooooooh look at all these awesome features on http://dojotoolkit.org!  They have a hot themetesterfull documentation for like every single part of their toolkit.  And GLORIOUS quickstarts!

1. Shock and Denial

“WTF, I’ve copied this code EXACTLY, but it spews tons of errors, and doesn’t even come close to working.”

“I’ve looked up all these error messages, but I can’t find a straightforward answer.  Everyone references concepts I’m not familiar with….and they keep telling me to hop on an IRC channel to talk to the developers.  Is IRC still a thing?  Do they have a BBS as well?  Maybe I can learn the language of my 14.4 kilo-baud modem and ask IT how to do stuff in Dojo by chriping and clicking at it”

“It’s gotta be me….I’m an idiot, it can’t be this difficult to get basic stuff working”

2. Pain and Guilt

“Screw, it – let’s man up and just read massive quantities of documents and tutorials.  Hell, I’m going to buy a book from 2008 even thought it’s horribly out of date.  I’m just going to sit through this initial pain to get a better understanding of the whole system.”

“Am I really this dumb?”

3. Anger and Bargaining

“Dojo SUCKS, I hate it!  It doesn’t work. I need to be a freakin rocket scientist to understand this system”

“jQuery, will you take me back?  Please?  I just want some data stores, and some binding, and some well written and documented plugins.”

4. Depression, Reflection, and Loneliness

“So lonely….the only materials I see online are from 2008, and from SitePen who charges for training, why would they help and give it all away for free?”

“Maybe if I had studied harder in school, this wouldn’t be a problem”

5. The Upward Turn

“Going back to the beginning and reading a bunch of stuff seems to have paid off, I think I’m beginning to understand now”

“Where in the hell did they tell you about this parseOnLoad attribute in the script tag?  It’s not in any of the quickstart examples, but it’s freaking mandatory to get anything to work”

“Well, no WONDER, this example didn’t work, it was written in Dojo 1.6 before the AMD Loader, and I’m mixing and matching my code between 1.6 and 1.7 – and 1.7 has REALLY changed the game”

“Ahhhhhh…..I need to nest the requires, cause my require doesn’t know what the ready object is before it loads the core stuff”

6. Acceptance and Hope

“Now that I understand the basics, I really like Dojo.  It rocks pretty hard!”

“There are things I don’t yet understand, but now that I have the big picture, I can roll with anything Dojo can throw at me, but all in all, I’m very psyched about all these new toys!”

7. Reconstruction and Working Through

“Dude, did I really just wire up a data store to a div which I made into a repeater, all inside a freaking accordion?  Damn….awesome”

“I made a build system, and moved all my layers somewhere else, so I’m completely relying on my own custom build….I only get like 2 errors, and none of them block functionality.  This will get better, but for now, it’s awesome enough”

Fin

And here I am.  Though, I think I cycled through steps 3, 4, and 5 a few times.

Why Dojo? From a Flash/Flexer’s Perspective

Filed in development | dojo | flash | flash/flex | flex | html5 | javascript | ui 5 Comments

Hey you guys…  Is your Twitter stream bombarded with Ted Patrick tweets and retweets about Sencha?  Do you get Sencha ads targeted at you when you visit websites, like EVERYWHERE you go?

I am.  It’s kind of annoying since I’m not looking to learn Sencha.  Truthfully, though, you can hardly blame the current Sencha evangelist.  After Adobe abandoned Flex sending it off to Apache, Ted seems to be leading a HUUUUUUGE marketing push trying to turn former Flex devs into Sencha/ExtJS devs.  Ted is leading webinars, reaching out to people, posting on G+ threads, the whole deal.

I can hardly blame him because:

a) I follow him on Twitter, so it’s mostly my own damn fault

b) This is the perfect time to grab a bunch of disillusioned and lost Flex devs, and Ted is doing it in a perfectly ethical (although a bit overzealous way).

I looked into going “beyond” jQuery because of a G+ post by Jesse Warden claiming that ExtJS is the perfect compliment to enterprise development.  He made the very apt analogy that Flash is to jQuery as Flex is to ExtJS/Sencha.  It really made me re-think things because it had been drilled into my brain that jQuery “won”, and given the tide of developers (84.8% of all websites using a library use jQuery) it seemed like there was no reason to use anything else.

Turns out, there really is a use for the lesser used libraries/frameworks/toolkits.  We can see this because even if jQuery is and always will be your library of choice, as you build more advanced applications you might want some binding, templating, MVC, or other action.  AngularJS by Google is getting more widely used.  It gives you binding, declarative HTML markup for data, and other MVC goodies.  There’s Backbone.JS, Underscore.JS, and tons of others.  A lot of folks seem to be combining all of these separate libraries together to custom fit their project.  And I’m sure that works fantastically – I was doing similar things for a time.

As these separate projects get more and more features, you may now have feature overlap between 3 different libraries you’ve used in your project.  It seems a LITTLE wasteful at best.  At worst, maybe your dev team does a very basic thing 3 different ways because binding is available 3 different ways given each of the libraries you’re using.

Wouldn’t it be better, or even just worth looking into, if you could find a cohesive library/framework that offered all of these things together? Maybe it could even do a little more and help you make a massive Javascript application that loaded in components and scripts AS YOU NEED THEM instead of all at once in the beginning.

It looked like Dojo and ExtJS were the most mature offerings in terms of what I describe.  I took a look at ExtJS by Sencha first.  At first glance, it looks pretty awesome.  You’ve got designer and animator tools.  They are a wee pricey, but considering my Flash background, spending $279 on Sencha Designer and $199 on Sencha Animator doesn’t seem obscene.

What I can’t get past is having to spend $329 for a Javascript library license!  When I’m doing Flash/Flex development, I use the Flash Builder IDE for coding and sometimes Flash Professional if I’m doing animations or graphics.  And that’s cool.  I chose to buy into these tools.  I didn’t have to pay to use Actionscript 3 though.  My fellow developers who may not do Flash all the time can crack open any text editor and edit my code.  They can check it back into SVN and contribute to the project.  They can launch the Flex SDK command line and build my project.  None of this costs a dime.

If and when they get more invested in Flash/Flex, they might then want to buy Flash Builder or even IntelliJ for the advanced featureset including debugging, profiling, etc.

Not so with ExtJS.  I’m buying a license to use the code base.  Kind icky in my mind.  If I start a project in ExtJS/Sencha and I pay my $329 for the seat, but then I want some more help on the project occasionally, each developer will then need to pay out $329 just to use/edit the code no matter what tools they use.  If you are starting a major project, and plan the ExtJS cost into the budget, then great.  But if you’re a lone developer who wants to start something which blossoms into something bigger – the licensing can be a major roadblock.

Moreso, if I’m a consultant and I’m paid x dollars to develop a web application, I can easily choose and pay to use ExtJS.  After two months, I make a deliverable.  It might be the type of project where I do the major architecture and first phase, but then it gets shipped off internationally for maintenance mode or a lower cost second phase of the project.  Well, if you use ExtJS, you’ve just upped maintenance mode by $329 for every developer that needs to touch the project.  You’ve just cost your client lots of money.

This is why I discounted Sencha and ExtJS and moved on to exploring Dojo.  Dojo seems to offer MOST of what Sencha does.  They both have a rich set of components, offer lazy loading of scripts so that your massive enterprise application doesn’t load several hundred scripts (or a huge 2MB block of script) before the application starts up.  Both have a build system – Dojo’s runs on Rhino or Node, and is built on Closure or Shrinksafe.  ExtJS seems to be built off of a Yahoo builder.

In terms of scripting, both seem to nudge you in the direction of organizing your Javascript into classes which can be based on straight inheritance, or mixins.

Both seem to offer a visual tool for design.  Dojo’s Maqetta is free and can be used for jQuery, YUI, or Dojo.  I don’t see myself being very productive in it though – I can lay things out, but it wasn’t obvious to me if I could wire in data or do anything extensive.  Though I haven’t used Ext Designer, I have to imagine it’s a better product than Maqetta.  But then I seriously question how much I’d use a good tool for this anyway.  It’s like when everyone complains that design mode in Flex really sucks – but what if it didn’t? Would you actually use it, or just code everything?  I think we’d use it only like 5% of the time.  But this is all personal preference – ExtJS wins here, but only if you feel like you need a good design tool, which I don’t.

Dojo seems to offer one thing that ExtJS doesn’t though – and that’s declarative HTML markup.  This may be where my ExtJS ignorance comes in, so feel free to correct me if I’m wrong, but to mark up a component like you might do with Flex’s MXML, you write a JSON object describing the component or layout you’re introducing in ExtJS.  This is pretty cool – but with Dojo, you get to write REAL HTML.  I can tag existing divs or other elements as a Dojo component and they’ll act like Dojo components.  Yes, Dojo does offer templating, but you can choose which to use…or even to use both.

The worst part of Dojo?  They don’t have a MASSIVE marketing and tutorial push.  There is tons of ExtJS and Sencha material out there to learn from.  Yes, there is tons of Dojo material, but much of it is older and not up to date.  The material on the Dojo site is pretty technical and not very “quickstart-ish”.  What quickstart material they do have, don’t seem to be big picture enough to inform you what’s really going on.  I always had bad luck copying and pasting code from tutorials and having it work without spending hours debugging.  Most of the trouble with Dojo material is the switch to new loading routines that happened with the 1.7 release in December 2011.  I feel like when they release 2.0 sometime this year, we’ll have some better effort from the Dojo Foundation in terms of educating people on how to use the toolkit

All in all, Dojo and Sencha seem eerily similar from everything I read.  I feel so lucky that by learning Dojo, I’ll probably feel right at home in ExtJS as well.  For me it really comes down to the licensing that drives me to Dojo.  If that wasn’t an obstacle for me, there were more than a few times I’ve been frustrated by Dojo in the past couple weeks of learning it that I’d been open to abandoning ship if there was another choice.  I get the feeling though that there are similar frustrations with understanding ExtJS (helped in large part by their tutorials).

That’s why I’m team Dojo right now!  However, I’ll continue using jQuery for the smaller projects.  Dojo could easily replace jQuery, but for the smaller stuff when something minimal is all you need, there’s no sense in going against the grain and using something that not many people have experience with.

I’ll be posting more technical stuff on Dojo, but for now, this is how I got where I am!

The ADSR Envelope with Audiolib.js

Filed in development | html5 | javascript | music | ui | web 6 Comments

So, let’s talk envelopes. First what they are, and what they can do to the quality of a sound.

Demo here: http://www.benfarrell.com/labs/examples/envelopes-12-17/, but read on for how it all works!

An envelope is a real simple concept actually. Take any signal, like a sound. Maybe that sound plays at a constant volume. When you apply an “envelope” to that sound, you are changing the volume of that sound while it’s played. It might go up and down, back up again, whatever.

How it goes up and down, and the speed at which the volume is changed is up to the details of the envelope used.

You could create an envelope that takes 8 hours to complete. Maybe you want to go to sleep with some music, and then wake up in the morning with music. If you know it takes you 30 minutes to fall asleep, you’ll start the music playing at a loud volume. Over the next 30 minutes, you envelope your sound from loud to quiet, to off. In the morning, 30 minutes before you wake up, the envelope makes the music go from off, to quiet, to loud again. It wakes you up!

While this 8 hours illustrates how an envelope works, it’s a bit different when talking musical tones.

It’s not that different, however. We’re still talking about volume over time, but we’re talking milliseconds instead of hours or even minutes or seconds.

The character or personality of a musical tone can be changed greatly by altering the envelope. While we talk about this in terms of 1/1000th of a second, you don’t really notice the volume changing as you listen to the tone. Your ear doesn’t necessarily detect that the volume is going up and down.

Instead, the sound just has a different tonal quality! A piano for example wouldn’t sound as sharp if it didn’t go from no sound to loud that quickly. An accordion though, has a longer time as it goes from quiet to loud. And that quality – the “attack” (amongst other factors) create the personality of the tone.

Let’s talk specifics now. ADSR.

That’s Attack, Decay, Sustain, Release. The ADSR envelope is just one type of envelope, but it’s a popular one that’s been used in electronic music for decades.

  • Attack is the period of time after the initial release, it’s typically the loudest part of the sound
  • Decay is the phase while you’re going from the attack to the sustain – you’re “decaying”  the volume from this sharp initial phase to the normal volume phase
  • Sustain is the normal phase of the sound.  It is typically less volume than the attack, and go on for an indefinite period of time, or for a specific amount of time
  • Release is the draw down from the sustain period to no sound.  A fade out

the attack, decay, sustain, and release phases

I’ve talked about Audiolib.js in previous posts.  Audiolib is the Javascript library that enables you to make these dynamic sounds in Chrome and Firefox.

Audio programming isn’t easy though!  So while Audiolib helps out in awesome ways, it doesn’t have concepts of notes and music theory.  You have to tell it what frequencies to play, and if playing a chord, which individual frequencies make up the chord – which I explored and created my own helpers for.

The ADSR envelope is another example of something that Audiolib.js provides, however, it doesn’t provide any obvious usage for it.

There’s actually a VERY good reason for this.  While, we’re talking about envelopes on musical tones, the 8 hour sleepy-time envelope is another good usage example.  And that’s restricting envelopes to the volume of a sound.  There are tons more examples in audio synthesis that envelopes can be applied.  Like effects – you can apply a distortion effect to a sound (like a rock guitar).  But you can envelope the amount of distortion which is applied to the guitar.  This has nothing to do with volume, and everything to do with just how much of something is applied to something else.

So, I’d like to create a usage of our ADSR envelope that is limited to producing a musical tone – especially in the example of producing live sound by using a trigger (here it will be your computer/laptop keyboard).

Let’s start with our previous example where we extend the Audiolib.js Oscillator via a plugin.  We extended it to simply take a musical notation, like an “A” and set the correct frequency:

audioLib.generators('Note', function (sampleRate, notation, octave){
// extend Oscillator
for ( var prop in audioLib.generators.Oscillator.prototype) {
this[prop] = audioLib.generators.Oscillator.prototype[prop];
}
// do constructor routine for Note and Oscillator
var that = this;
 
// are we defining the octave separately? If so add it
if (octave) {
notation += octave;
}
that.frequency = Note.getFrequencyForNotation(notation);
that.waveTable = new Float32Array(1);
that.sampleRate = sampleRate;
that.waveShapes = that.waveShapes.slice(0);
}, {});

So let’s figure out how to work in an ADSR envelope. The usage for the Audiolib.js version is like so:

myEnvelope = audioLib.ADSREnvelope(sampleRate, attack, decay, sustain, release, sustainTime, releaseTime);

The parameters work like so:

  1. Sample Rate:  The sample rate of the audio – I won’t go into it here, as it’s a basic setting for audiolib
  2. attack – the amount of time (in milliseconds) that the attack phase takes to complete
  3. decay – the amount of time (in milliseconds) that the decay phase takes to complete
  4. sustain – the level of volume during the sustain phase (from 0 to 1)  - the default is 1
  5. release – the amount of time it takes for the release phase to complete (in milliseconds)
  6. sustainTime – the amount of time it takes for the sustain phase to complete (in milliseconds).  This param is pretty important though, because if you pass in null, the sustain period is indefinite.  Unless you call into the envelope with a trigger, it will continue being in the sustain phase forever
  7. releaseTime – the amount of time between the release phase and the envelope looping around to the attack phase again

The envelope has 6 states of being (0-indexed inside the code):

  1. Attack Phase
  2. Decay Phase
  3. Sustain Phase
  4. Release Phase
  5. Timed Sustain Phase
  6. Timed Release Phase

To kick off our envelope, you trigger it:

myEnvelope.triggerGate(true);

Now we can start using our envelope.  The usage is a little weird to me, as the Audiolib.js library treats it like a “generator” which seems a bit complicated for what it does.  I just want a stream of numbers, but OK I’ll bite.  I’ll use it with the byte arrays and whatnot, as if it’s an Oscillator.

var buffer = new Float32Array(1);
myEnvelope.append(buffer, 1);

So, I’m just pulling one value at a time from the envelope, and putting it into my “buffer”.  But my buffer only has one value in it at any time.  Like I said, I feel like I’m being forced into using it in more complicated of a way than I need!  Maybe there’s something I’m missing.

Now, every time, I get create an audio data point in my sound, I can multiply the data point by my envelope.  Thus my envelope is applied!

this[this.waveShape]() * buffer[0];

To do this, I overrode the “getMix” function in the Audiolib Oscillator.  But I needed to do other things too.

Since I trigger the envelope with triggerGate, it will cycle through the attack and release to the sustain phase as the envelope is used, automatically.

It gets complicated at the release phase though.  After your computer/laptop keyboard is released, we need to enter the release phase.  But we’re still grabbing sound, because the release phase still produces sound as it fades.  So our Oscillator needs to track that it’s in the release phase (it knows by keeping track of the envelope.state, which is 3 or 5 here for release or timed release).

Then finally when it gets back to state 0, or the cycle begins again, we mark this note as “released”, so our buffer knows that it doesn’t need to pull from it anymore.  We have to be very careful of note pulling from more notes than we need, cause all this music stuff is hard work, and too many notes slows down your CPU and breaks the audio processing.

The above is if the sustain phase goes on as long as you hold the key!  What if it’s a timed sustain – then we need the logic in there to release the key when the envelope is done, rather than when our user releases the key.

Here’s our final Note.js code.  And here’s a controller for keeping track of keys being pressed.

It all comes together in my (Chrome only) demo:

http://www.benfarrell.com/labs/examples/envelopes-12-17/

The demo starts out by not using an envelope at all.  You’ll hear some clicky-ness when you press and release a key.  That’s because you’re hearing the transition between no sound and the abrupt start in the phase of the waveform.  It’s EXACTLY one of the reasons why envelopes are useful – to ease these transitions in and out.

When you turn on the envelope, you can start adjusting parameters to see how the different properties of attack, decay, sustain, and release affect the overall personality of the tone.

Chords and Arpeggiators with Audiolib.js

Filed in html5 | javascript | ui | web Leave a comment

So, as you may have noticed with my recent flurry of blog posts I’ve been playing with Audiolib.js.  I can’t thank the author Jussi Kalliokoski enough for getting this project going.  When I did my Flash version, I spent many moons getting the audio buffer working correctly, then the oscillators, and I hadn’t even gotten started on effects so much yet.

But audiolib.js has all of this, which means I can focus on the usage with the API rather than making the low level audio stuff work.

For example, Chords and Arpeggiation!
Sorry! This only works in the latest version of Chrome

After a couple nights with the project, I extended out the standard Oscillator with a Note.  I’ve since refactored a bit to do the minimum amount of music theory in the Note Oscillator object itself, and offload into a different object – but the net effect is that instead of instantiating a new Oscillator with a frequency, we can instantiate a new Note with a musical notation.  For example with Oscillator, we’d say 440hz, with Note, we’d say “A” or “A4″ (if you don’t want to assume the 4th octave).

The obvious extension to this is groups of notes – or rather Chords.  There are two challenges here.  The first is to convert a chord notation to array of notes.  For example, if I say “Cm”, or C Minor, I want an array such as ["C", "Eb", "G"].  We need to convert the C Minor notation into the implied triad of 3 notes using the minor scale.  Also possible is a 6th, 7th, 9th, 11th, or 13th.  In fact, now that I type, I realize I never did a 5th, which if I recall correctly, omits the middle note of a triad.

It all came out fairly well.  I don’t think augmentation, sustain, or diminish work properly yet, but the chord structures are there. The simplest way to use this is to use ChordFactory instead of Chord. Simply call ChordFactory.createNotations(“C”, 4) to get a list of notes (strings) or ChordFactory.createNotes(“C”, 4) to get an array of Note Oscillators.

ChordConstants = {
   MAJOR_TRIAD: "maj",
   MINOR_TRIAD: "m",
   SEVENTH: "7",
   MINOR_SEVENTH: "m7",
   MAJOR_SEVENTH: "maj7",
   NINTH: "9",
   MINOR_NINTH: "m9",
   MAJOR_NINTH: "maj9",
   ELEVENTH: "11",
   THIRTEENTH: "13",
   SIXTH: "6",
   MINOR_SIXTH: "m6",
   SUSTAIN: "sus",
   AUGMENTED: "aug",
   DIMINISHED: "dim"
};
 
ChordFactory = {
    /**
     * create a list of notations from chord
     * @param chord notation
     * @param notation array (individual notes)
     */
    createNotations: function createNotations(notation, octave) {
        var chord = new Chord(notation, octave);
        return chord.getNotations();
    },
 
    /**
     * create an array of note oscillators using the audiolib framework
     * @param sampleRate
     * @param notation
     */
    createNotes: function createNotes(sampleRate, notation) {
        var chord = new Chord(notation);
        nts = chord.getNotations();
 
        var osc;
        var oscs = [];
        for (var nt in nts) {
            osc = audioLib.generators.Note(sampleRate, nts[nt])
            oscs.push(osc);
        }
        return oscs;
    }
}
 
function Chord(notation, octave) {
    var that = this;
 
    /** root note of chord */
    that._root = "C";
 
    /** octave of root */
    if (octave) {
        that._rootOctave = octave;
    } else {
        that._rootOctave = null;
    }
 
    /** chord notation */
    that._notation = notation ? notation : "Cmaj";
 
    /** notes in built chord */
    that._notes = [];
 
    /**
     * get notes from built chords
     *
     * @return notes
     */
    this.getNotations = function() {
        return this._notes;
    }
 
    /**
     * chord notation setter
     *
     * @param notation
     */
    this.setNotation = function(value) {
        this._notation = value;
        this.buildChord();
    }
 
    /**
     * chord notation getter
     *
     * @return notation
     */
    this.getNotation = function() {
        return this._notation;
    }
 
    /**
     * root note setter
     *
     * @param root
     */
    this.setRoot = function(value) {
        this._root = value;
        this.buildChord();
    }
 
    /**
     * root note getter
     *
     * @return root note
     */
    this.getRoot = function() {
        return this._root;
    }
 
    /**
     * root octave setter
     *
     * @param octave
     */
    this.setRootOctave = function(value) {
        this._rootOctave = value;
        this.buildChord();
    }
 
    /**
     * root octave getter
     *
     * @return root octave
     */
    this.getRootOctave = function() {
        return this._rootOctave;
    }
 
    /**
     * get notes in major triad
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.majorTriad = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,3);
    }
 
    /**
     * get notes in minor triad
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorTriad = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, false, false, rootOctave).slice(0,3);
    }
 
    /**
     * get notes in seventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.seventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,4);
    }
 
    /**
     * get notes in major seventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.majorSeventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,4);
    }
 
    /**
     * get notes in minor seventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorSeventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, false, false, rootOctave).slice(0,4);
    }
 
    /**
     * get notes in ninth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.ninth = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,5);
    }
 
    /**
     * get notes in major ninth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.majorNinth = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,5);
    }
 
    /**
     * get notes in minor ninth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorNinth = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, false, false, rootOctave).slice(0,5);
    }
 
    /**
     * get notes in eleventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.eleventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,6);
    }
 
    /**
     * get notes in major eleventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.majorEleventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,6);
    }
 
    /**
     * get notes in minor eleventh chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorEleventh = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, false, false, rootOctave).slice(0,6);
    }
 
    /**
     * get notes in thirteenth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.thirteenth = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,7);
    }
 
    /**
     * get notes in major thirteenth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.majorThirteenth = function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, true, false, rootOctave).slice(0,7);
    }
 
    /**
     * get notes in minor thirteenth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorThirteenth= function(root, rootOctave) {
        return this.getStandardNotesInChordMakeup(root, false, false, rootOctave).slice(0,7);
    }
 
 
    /**
     * get notes in sixth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.sixth = function(root, rootOctave) {
        var keySig = Note.notesInKeySignature(root, true, rootOctave);
        var keys = new Array();
        keys.push(keySig[0], keySig[2], keySig[4], keySig[5]);
        return keys;
    }
 
    /**
     * get notes in minor sixth chord
     *
     * @param root note
     * @param root octave
     * @return notes
     */
    this.minorSixth = function(root, rootOctave) {
        var keySig = Note.notesInKeySignature(root, false, rootOctave);
        var keys = new Array();
        keys.push(keySig[0], keySig[2], keySig[4], keySig[5]);
        return keys;
    }
 
    /**
     * sustain chord
     *
     * @param notes
     * @param direction to sustain
     * @return notes
     */
    this.sustain = function(notes, sus) {
        sus = (sus == undefined) ? 4 : sus;
        // grab the third in the chord
        var third = notes[1];
        var notations = Note.sharpNotations;
        var thirdIndex = Note.sharpNotations.indexOf(third);
        if (thirdIndex == -1) {
            notations = Note.flatNotations;
            thirdIndex = Note.flatNotations.indexOf(third);
        }
 
        if (sus==2) {
            // lower the third one half step
            if (thirdIndex-1 < 0) {
                notes[1] = notations[notations.length-1];
            } else {
                notes[1] = notations[thirdIndex-1];
            }
        } else { // assume sus == 4
            // raise the third one half step
            if (thirdIndex+1 >= notations.length) {
                notes[1] = notations[0];
            } else {
                notes[1] = notations[thirdIndex+1];
            }
        }
        return notes;
    }
 
    /**
     * augment chord
     *
     * @param notes
     * @return notes
     */
    this.augment = function(notes) {
        // grab the fifth in the chord
        var fifth = notes[2];
        var notations = Note.sharpNotations;
        var fifthIndex = Note.sharpNotations.indexOf(fifth);
        if (fifthIndex == -1) {
            notations = Note.flatNotations;
            fifthIndex = Note.flatNotations.indexOf(fifth);
        }
 
        // raise the fifth one half step
        if (fifthIndex+1 >= notations.length) {
            notes[2] = notations[0];
        } else {
            notes[2] = notations[fifthIndex+1];
        }
        return notes;
    }
 
    /**
     * get all standard notes in a chord, from triad to thirteenth
     *
     * @param root note
     * @param major key (true/false)
     * @param major chord (true/false)
     * @param root octave
     * @return notes array
     */
    this.getStandardNotesInChordMakeup = function(root, majorKey, majorChord, octave) {
        majorKey = (majorKey == undefined) ? true : majorKey;
        majorChord = (majorChord == undefined) ? false : majorChord;
 
        var majKeySig = Note.notesInKeySignature(root, true, octave);
        var minKeySig = Note.notesInKeySignature(root, false, octave);
 
        // grab the next octave if we need it
        var majKeySig2 = Note.notesInKeySignature(root, true, octave+1);
        var minKeySig2 = Note.notesInKeySignature(root, false, octave+1);
        var notes;
        if (majorKey && majorChord) {
            // C Major Seventh for example
            notes = [ majKeySig[0], majKeySig[2], majKeySig[4], majKeySig[6], majKeySig2[1], majKeySig2[3] ];
        } else if (!majorKey && majorChord) {
            // C Minor Seventh for example
            notes = [ minKeySig[0], minKeySig[2], minKeySig[4], minKeySig[6], minKeySig2[1], minKeySig2[3] ];
        } else if (majorKey && !majorChord) {
            // C Seventh for example
            notes = [ majKeySig[0], majKeySig[2], majKeySig[4], minKeySig[6], majKeySig2[1], minKeySig2[3] ];
        } else if (!majorKey && !majorChord) {
            // C Seventh for example
            notes = [ majKeySig[0], minKeySig[2], majKeySig[4], minKeySig[6], majKeySig2[1], minKeySig2[3] ];
        }
        return notes;
    }
 
    /**
     * convert notation to note list
     *
     * @param notation
     * @param use the octave in the notation
     * @return note list
     */
    this.notesFromChordNotation = function(notation, octave) {
        var root;
        var major = 0;
        var chordType;
 
        // find root
        if (notation.charAt(1) == "#" || notation.charAt(1) == "b") {
            root = notation.substring(0, 2);
            notation = notation.substring(2);
        } else {
            root = notation.substring(0, 1);
            notation = notation.substring(1);
        }
 
        // major or minor? (3 states - 1 is on, -1 is off, 0 is unspecified)
        if ( notation.substr(0, 3) == "maj") {
            major = 1;
            notation = notation.substring(3);
        } else if (notation.substr(0, 1) == "m") {
            major = -1;
            notation = notation.substring(1);
        }
 
        // set chord type
        if ( notation.charAt(0) == "6" ) {
            if (major == -1) {
                chordType = ChordConstants.MINOR_SIXTH;
            } else {
                chordType = ChordConstants.SIXTH;
            }
            notation = notation.substring(2);
        } else if ( notation.charAt(0) == "7" ) {
            if (major == 0) {
                chordType = ChordConstants.SEVENTH;
            } else if (major == 1) {
                chordType = ChordConstants.MAJOR_SEVENTH;
            } else if (major == -1) {
                chordType = ChordConstants.MINOR_SEVENTH;
            }
            notation = notation.substring(1);
        } else if ( notation.charAt(0) == "9" ) {
            if (major == 0) {
                chordType = ChordConstants.NINTH;
            } else if (major == 1) {
                chordType = ChordConstants.MAJOR_NINTH;
            } else if (major == -1) {
                chordType = ChordConstants.MINOR_NINTH;
            }
            notation = notation.substring(1);
        } else if ( notation.substr(0,2) == "11" ) {
            chordType = ChordConstants.ELEVENTH;
            notation = notation.substring(2);
        } else if ( notation.substr(0,2) == "13" ) {
            chordType = ChordConstants.THIRTEENTH;
            notation = notation.substring(2);
        } else {
            if (major == 1 || major == 0) {
                chordType = ChordConstants.MAJOR_TRIAD;
            } else {
                chordType = ChordConstants.MINOR_TRIAD;
            }
        }
        var notes = this.notesFromChordType(chordType, root, octave);
 
        // modify note set if needed
        var modifier = notation;
        switch ( modifier.substr(0,3) ) {
            case ChordConstants.AUGMENTED:
                notes = augment(notes);
                break;
 
            case ChordConstants.DIMINISHED:
                // to do
                break;
 
            case ChordConstants.SUSTAIN:
                var param = int(modifier.charAt(3));
                notes = sustain(notes, param);
                break;
        }
 
        return notes;
    }
 
    /**
     * get notes from chord types
     *
     * @param type
     * @param chord root
     * @return notes
     */
    this.notesFromChordType = function(type, root, rootOctave) {
        switch ( type ) {
            case ChordConstants.SIXTH:
                 return this.sixth(root, rootOctave);
 
            case ChordConstants.MINOR_SIXTH:
                 return this.minorSixth(root, rootOctave);
 
            case ChordConstants.SEVENTH:
                 return this.seventh(root, rootOctave);
 
            case ChordConstants.MINOR_SEVENTH:
                 return this.minorSeventh(root, rootOctave);
 
            case ChordConstants.MAJOR_SEVENTH:
                 return this.majorSeventh(root, rootOctave);
 
            case ChordConstants.NINTH:
                 return this.ninth(root, rootOctave);
 
            case ChordConstants.MINOR_NINTH:
                 return this.minorNinth(root, rootOctave);
 
            case ChordConstants.MAJOR_NINTH:
                 return this.majorNinth(root, rootOctave);
 
            case ChordConstants.ELEVENTH:
                 return this.eleventh(root, rootOctave);
 
            case ChordConstants.THIRTEENTH:
                 return this.thirteenth(root, rootOctave);
 
            case ChordConstants.MAJOR_TRIAD:
                 return this.majorTriad(root, rootOctave);
 
            case ChordConstants.MINOR_TRIAD:
                 return this.minorTriad(root, rootOctave);
 
            default:
                 return this.majorTriad(root, rootOctave);
        }
    }
 
    /**
     * build the chord given the parameters set in this class
     */
    this.buildChord = function() {
        this._notes = [];
        var notations = this.notesFromChordNotation(this._notation, this._rootOctave);
        for (var c = 0; c < notations.length; c++) {
            this._notes.push(notations[c]);
        }
    }
 
    // do a build based on initial params
    that.buildChord();
}

Namespacing will probably come when I think of a name for this project!

Anyway, we have some code that creates chord structures!  Yay!  Now, what about sending this to the buffer for mixing.  The most basic example in audiolib.js is like so:

 

function audioCallback(buffer, channelCount){
    // Fill the buffer with the oscillator output.
    osc.append(buffer, channelCount);
}

This takes the Oscillator (or any audio generator for that matter) and generates some bytes to send to the audio buffer. Audiolib had some examples of mixing, but I didn’t care for them so much, as they seemed a little overly complicated with whatever idea of “leads” they had – I was a bit confused. In the end, I came up with something that worked a little better for me, but is probably virtually the same concept:

function audioCallback(buffer, channelCount){
    // get a list of generators from our keyboard controller object - it keeps tracks of keys pressed
    var gens = ctrl.pull();
    var bl = buffer.length;
    var gl = gens.length;
 
	// loop through each sample in the buffer
	for (current=0; current<bl; current+= channelCount){
		sample = 0;
                // here we're combining samples from our list of generators
                // and combining down into one sample
                for (i=0; i<gl; i++){
			gens[i].generate();
			sample += gens[i].getMix()*0.5;
		}
 
		// Here we write this sample to each channel we have (I'm just doing 2 channels)
		for (n=0; n<channelCount; n++){
			buffer[current + n] = sample;
		}
	}
}

That’s pretty much it! We’re constructing Oscillators from Chord notations, and then mixing the result for playback.

The last thing I wanted to try was an arpeggiator. An arpeggiator takes a chord structure, and instead of playing all the notes at the same time, only plays one note at a time in sequence.

I extended the Audiolib Oscillator again, making an Arpeggiator plugin. I needed to override the “generate” method. Every time “generate” is called, I’d step through. Once my step count reaches a threshold (the samplerate divided by some number), I’d change to the next frequency.

Here’s what I got:

audioLib.generators('Arpeggiator', function (sampleRate, arpeggiatorRate, notes, octave, autoReverse){
    // extend Oscillator
    for ( var prop in audioLib.generators.Oscillator.prototype) {
        this[prop] = audioLib.generators.Oscillator.prototype[prop];
    }
 
    // do constructor routine for Note and Oscillator
	var	that = this;
    if (autoReverse === undefined) {
        that.autoReverse = true;
    } else {
        that.autoReverse = autoReverse;
    }
    that.buildFrequencies(notes, octave);
	that.waveTable	= new Float32Array(1);
	that.sampleRate = sampleRate;
	that.waveShapes	= that.waveShapes.slice(0);
    that.arpStep = 0;
    that.arpIndex = 0;
    that.arpeggiatorRate = arpeggiatorRate;
 
    /**
     * override generate function
     */
    that.generate = function(){
		var	self	= this,
			f	= +self.frequency,
			pw	= self.pulseWidth,
			p	= self.phase;
		f += f * self.fm;
		self.phase	= (p + f / self.sampleRate / 2) % 1;
		p		= (self.phase + self.phaseOffset) % 1;
		self._p		= p < pw ? p / pw : (p-pw) / (1-pw);
 
        self.arpStep ++;
        if (self.arpStep > self.sampleRate * self.arpeggiatorRate) {
            self.arpStep = 0;
            self.arpIndex ++;
            if (self.arpIndex >= self.frequencies.length) {
                self.arpIndex = 0;
            }
            self.frequency = self.frequencies[self.arpIndex];
        }
	}
}, {
    buildFrequencies: function(notes, octave) {
        var self = this;
        self.frequencies = [];
        if (!(notes instanceof Array)) { // work with either a chord structure...
            notes = ChordFactory.createNotations(notes, octave);
        }
 
        for (var c = 0; c < notes.length; c++) { // ...or array of notations
            self.frequencies.push( Note.getFrequencyForNotation(notes[c]) )
        }
 
        if (self.autoReverse == true) {
            for (var c = notes.length-2; c > 0; c--) {
                self.frequencies.push( Note.getFrequencyForNotation(notes[c]) )
            }
        }
        self.frequency = self.frequencies[0];
    }
});

Lotsa code here tonight! I’d like to get started on some basic effects and envelopes next to make some non-boring tonal qualities to my playback. At that point, I hope to have a nice little useable API I can put up somewhere – especially since I don’t have to put lotsa code up!

Making an Audiolib.js Plugin

Filed in development | html5 | javascript | music | ui | web Leave a comment

I just started checking out Audiolib.js this weekend.  Audiolib is a Javascript project to help you synthesize sounds and tones in JS.

Just recently, Google Chrome added the Web Audio API, while Firefox added the Audio Data API.  Both let you get low level with sound – you can add bytes to an audio buffer and manufacture sound in realtime.

The library is bundled with “sink.js” which handles the inconsistencies in the audio API between Firefox and Chrome to create a common API.  Once this is abstracted away, we can make some audio.

I’ve done the nitty gritty of writing bytes to the buffer in Flash, and from my limited playing Audiolib does a great job with this, and I’m ecstatic I don’t have to rewrite my Flash stuff!

Audiolib provides “generators” for you to work with.  A “generator” is something that makes a sound, and defines a common API for anything that makes a noise to write that sound to the audio buffer.

In the generators namespace/package, we have an Oscillator, White/Pink/Brown Noise, and a Sampler.  White noise is cool and all, but I jumped right to the Oscillator to make a real tone.  The Oscillator takes a sample rate and a frequency.

You can define it thusly:

dev = audioLib.AudioDevice(audioCallback /* callback for the buffer fills */, 2 /* channelCount */);
osc = audioLib.Oscillator(dev.sampleRate /* sampleRate */, 440 /* frequency */);

So, first we defined the device to use – we told it what to use for the audio callback, and how many channels there are (we have 2 channels…left and right).

The audio callback is a pretty standard thing in the world of audio. When the sound card is starting to run out of audio to play, it signals Javascript and says “Hey I need more audio! Fill me up with some bytes”. With our “audioCallback” function, we say “No problem sound card! I got your back! When you run low, please call our audio callback method – this will fill your audio buffer up”

Here’s an example of the audio callback:

function audioCallback(buffer, channelCount){
  osc.append(buffer, channelCount);
}

All that happens here, is that the buffer and channel count gets passed into the method, and we tell out Oscillator what this is, and this Oscillator generates the appropriate bytes and send them to the buffer.

But what is that generator…the Oscillator? Well, it creates a sound at a certain frequency. We pass in the frequency as we instantiate this “osc” object. When the audioCallback fires, it pulls this frequency from the osc object and plays a specific tone!

This is awesome! All the hard work is done for us – but one of the first things I wanted to tackle here was to make it easier for musicians to understand.

See, casual musicians don’t know that a middle “A” on a piano oscillates at 440hz – they just know that they hit a middle “A” to play the tone. I want something that makes sense for casual musicians, so my first small task with audiolib is to override Oscillator to take a notation vs a frequency.

Audiolib provides a plugin spec, but it tripped me up a little to understand how a “Generator” worked. See, they have a js/generation folder which contains the Oscillator. It’s all quite readable and self-documented.

However, the “append” method was not found in the Oscillator class at all! I was looking EVERYWHERE for it!

Eventually I found it in the “wrapper-end.js” script that’s outside of all the folders.

Basically, you create a generator like Oscillator, and you write it to the audiolib.generators namespace. By virtue of being in this namespace, the “wrapper-end” script comes along to wrap things up. It takes all the things in the audiolib.generators namespace and adds the generator base functions. Basically it makes all the generators extend the generator base class after the fact.

Kinda confusing and sneaky if you ask me! Oh well.

Regardless, the plugins are well documented, so I copied the sample generator plugin:

audioLib.generators('SemiClock', function (sampleRate){
	this.sampleRate = sampleRate;
}, {
	prevSample: 0.0,
	generate: function(sample){
		this.phase = + !this.phase;
	},
	getMix: function(){
		return this.phase;
	},
	phase: 0
});

Cool, so we’re naming a generator in the generator namespace, and defining some required methods, like “generate” and “getMix”.

Well, all I want to do is make a copy of all the objects in Oscillator and add a function and initialization routine to accept a musical notation and instantiate an oscillator with the correct frequency.

So here’s my take:

audioLib.generators('Note', function (sampleRate, notation, octave){
    // extend Oscillator
    for ( var prop in audioLib.generators.Oscillator.prototype) {
        this[prop] = audioLib.generators.Oscillator.prototype[prop];
    }
 
    // do constructor routine for Note and Oscillator
	var	self = this;
    self.octave = isNaN(octave) ? 4 : octave;
    self.setNotation(notation);
	self.waveTable	= new Float32Array(1);
	self.sampleRate = sampleRate;
	self.waveShapes	= self.waveShapes.slice(0);
}, {
    /* incremental tones as sharp notation */
    sharpNotations: ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"],
 
    /* incremental tones as flat notation */
    flatNotations: ["A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab"],
 
    /**
     * notation setter
     * @param notation (octave is optional)
     */
    setNotation: function(nt) {
        this.notation = nt;
 
        // does notation include the octave?
        if ( !isNaN( parseInt(nt.charAt(nt.length -1)) )) {
            this.octave = parseInt(nt.charAt(nt.length -1));
            this.notation = nt.substr(0, nt.length-2);
        }
        this.frequency = this._getFrequencyForNotation(this.notation);
    },
 
    /**
     * turn a notation into a frequency
     * @param notation
     * @return frequency
     */
    _getFrequencyForNotation: function(nt) {
        var freq;
        var indx = this.sharpNotations.indexOf(nt);
 
        if (indx == -1) {
            indx = this.flatNotations.indexOf(nt);
        }
 
        if (indx != -1) {
            indx += (this.octave-4) * this.sharpNotations.length;
            freq = 440 * (Math.pow(2, indx/12));
        }
        return freq;
    }
});

Basically what I did here is extended the Oscillator class. I looped through all the properties of the Oscillator.prototype object and copying it onto the new class.

I then, went in to the Oscillator generator and copied the small initialization routine.

Then I injected my own methods! I replaced the frequency setting with a method to lookup the index of the musical notation in my preset arrays of notations. I also parsed out the octave (if it existed).

In the end, I have a “Note” class which is exactly the same as the Oscillator class – however, instead of passing in the frequency (ie 440hz), you pass in “A”, or “A4″ for the 4th octave.

To change the notation of the oscillator/note, simply call the setNotation again!

I’m definitely looking forward to exploring Audiolib.js more. It has a few concepts that I hadn’t gotten around to implementing in my own Flash framework yet, so I’m excited to see how it’s done.
 

Thoughts….er…Wild Unsubstantiated Predictions on Flash

Filed in flash | flash/flex | flex | ui | web Leave a comment

Yes, Adobe did us, the developers wrong this week. No doubt about it. Even if they have the best possible intentions, they did an AWESOME job salting the developer community earth this week.

It got me thinking, assuming they did have the best possible intentions for Flash, what could that mean? What is going on behind the closed doors and tight lips?

OK, let’s revisit what they said:
Adobe is Stopping development on Flash Player for browsers on mobile.

Read it again…it says Adobe is stopping development. They already have a partner developer program, which means that a company can come in, sign an NDA, and make their own Flash player.

They ALSO have the Open Screen Project. The project consists of a lot of companies all pledging to support the SWF format reliable on many screens.

My knee jerk reaction to this past week’s news is “Hoooooo boy…..HTC, Google, MTV, Disney, Cisco, Samsung, etc, etc, are all gonna be super pissed that Adobe is dropping Flash and essentially this project”.

What if this news revolves around the OpenScreen project? We’ve heard from some of the senior Flash engineers how much of a pain it is to maintain Flash on every device in every browser. There are way too many screens. The message we’re hearing from the Flash engineers is that they will still continue desktop development.

My thought process leads to Adobe’s PDF history here. Adobe created the spec, and owned Acrobat for many years. The spec was released in 2001 and was released as an open standard in 2008. This means that anyone can create tools that make or read PDFs. We have Foxit, Google Chrome Support, OSX support, the list goes on. Adobe still has Acrobat, and while you may think it’s bloated and you complain about it non-stop, its still a very popular method to read and write documents. We have other text document standards as well of course…like HTML!

Does this sound like another open specification we know? Yep the Flash SWF specification. The spec is open, but the player is not open source. Adobe has told us in the past that proprietary tech like the h264 video format prevents them from releasing the code in it’s entirety. However, we’re now at a cross-roads with Flash. Lots of stuff available on the desktop is not available on a device (3D) and vice versa (gestures, acceleromter, GPS, etc). Flash is no longer consistent everywhere.

This feels to me like a good opportunity for Adobe to maintain it’s vision for Flash on the desktop and say “Guys, if you are implementing Flash on your screen…this is what you should shoot for”. But vendors like Sony can also say, “Wellllll, the 3D stuff won’t work on my cheap TV, we’re just gonna take the other stuff”. It also feels like a good stopping point for them if they were to hand this off to the OpenScreen foundation. They have massive penetration on the desktop, and a decent inroads on mobile devices.

Where Adobe leaves off, Android/Google can pick up for their own OS – and do it BETTER than Adobe because they know their own devices better than Adobe ever could.

Adobe could certainly leave h264 video out of the open sourced player, and leave it up to vendors to pay the licensing fee and hook it into their version of Flash.

Also, go back a few months, we saw AIR 3 announced with native extensions, fast native performance. All of this is designed to make SWFs a powerful format. It also makes a path for vendors to hook into Flash in whatever way they want.

Anyway – I like working with Flash. Just like I like working with a lotta cool tech. This is just my optomistic vision of what is going on behind closed doors, and its probably not even true. Even if it was true, Adobe lost a lot of trust with developers. But I’m not here to whine, that’s what the rest of the internet is for!

But, I’ll leave you with this…if it was being turned over to the OpenScreen project and managed by many companies, how much work and wrangling would it take IN SECRET to make all of these companies happy before announcing intentions.

Buy into this or not, I don’t care! Just a wild theory.

C Web Run, Run Web Run

Filed in c++ | flash/flex | html5 | javascript | ui | web Leave a comment

After a long vacation, i’m finally back from Adobe MAX and California.  Going to MAX certainly gave a lot of perspective on things.

Adobe’s keynote around Flash and HTML5 seemed to be a hot button for some people.  Flex wasn’t mentioned, and Flash was named “the console of the web”.  This seemed to draw ire from people who know Flash is more than games.

I actually think the verbage is just fine.  Flash is the box in your living room that runs nifty stuff.  It does applications, video, games, and all the cool stuff that is net connected but isn’t a “web page”.

Obviously, Flash does RIA applications because it does everything else.  It’s a little unfortunate that RIAs aren’t part of the overall message, but to be realistic, when normal people talk RIAs, they are thinking of what the HTML/JS/CSS stack can do easily—and if you want to claim that Flex should be used where HTML/JS/CSS can be easily used, you are fighting a losing battle these days.

For the rest of us technically adept people, we know in which situations Flash can or can’t be used.  It’s unfortunate it’s been reduced to “web standards” versus “the console,” but Adobe had to put it in terms the world could understand.  I think they threw in the towel on a small battle to win the larger war to keep Flash going strong.

This is all interesting, but it’s not my takeaway from MAX.  Adobe gives us a stack for the console: Flex/AIR/Flash. They also give us a stack for standards-based Web: JQuery/HTML/PhoneGap.  The untold story taking shape in the creative space is low level and close to the metal, as they say.  C++ is heading to the creative space and the Web. It is slowly taking shape as the technology that can be injected into the Web stack, the Flash stack, and the creative expression stack.

Prior to MAX, I had been looking into OpenFrameworks (OF). It’s a C++ library that allows people to creatively express themselves using C++.  This is significant because C++, in the past, was seen as one of those daunting languages that nobody wanted to touch because it was too complicated and reserved for computer rocket scientists.  But OF aims to make C++ approachable for creative types and allows them to push graphics around and do some cool things like face tracking, object detection, and more.
Basically, anything creative that Flash or Javascript is too slow to handle, C++ can do and OF is your path to get there.

Sure, OF is significant, but it’s just part of the story.  Adobe has another project in labs called Alchemy.  They recently announced in a MAX session that it would be getting a lot more attention…official product support attention!  You may remember Alchemy as a MAX demo a few years back.  The source code for Quake was compiled from C++ through Alchemy and used as a Flash-compiled library.  The end result was that a Quake level was cross compiled and playable in Flash (and this was before Stage3D).

Alchemy is used to compile existing C++ libraries or just code you’d like to run that goes too damn slow in Flash/Actionscript.  This opens up a world of possibilities for near native performance.  In fact, remember that Photoshop Touch demo you saw in the Day 1 keynote? That was built with AIR.  Still, Actionscript is just a shade too slow to run Photoshop’s advanced image manipulation algorithms.  Instead, the developers simply leveraged Photoshop’s existing C++ libraries and plugged them into AIR/Flash.

That story was the same as the one I overheard from Ben Garney of PushButton Labs when talking about his game development work.  He coded up a library in C++, which could be targeted at normal native usage. When needed in Flash, the library can be simply compiled with Alchemy for usage in Flash.

The benefit is immense here—incredible performance boosts and the ability to leverage the same code everywhere that runs C++.

But the Flash story doesn’t stop there.  AIR 3.0 allows native extensions on both Desktop or mobile applications.  Whether you use C++ to create a windows DLL or use the NDK to create an Android extension, it doesn’t matter.  Objective-C for iOS might be a slighly different flavor…but Apple isn’t known for playing nice.

The benefits of Flash are huge, but what about beyond Flash?

Google Chrome is part of the same story with their “Native Client.”  Just recently, Google gave us the ability to leverage C++ code in their Web browser for more power and speed.  Meanwhile, projects like Emscripten will compile C++ to Javascript.  While Emscripten doesn’t equate to a speed boost, you can leverage exisiting C++ libraries.  This is important because C++ has been around for decades, and someone before you may have already solved your problem.

Where is all of this going?  Well, I conjecture that we will end up doing the meaty bits of our apps/applications/Webpages with C++.  We’ll share the same C++ libraries across Flash, AIR, Desktop, Mobile, and Web.  We’ll then layer a thin client on top whether or not we write it in Javascript, MXML, Actionscript, Dart, HTML, etc.  This layer will be visual, with the bottom C++ layer used for perfomance.
I may be completely wrong about this prediction.  Even if I am, the current creative ways to express ourselves with C++ give us normal folk a definite inroad into learning the most popular language on the planet.

In other words, if you take the opportunity now to learn C++, what could possibly go wrong?!

Hello from NCDevCon! My 2011 Presentations

Filed in development | flash | flash/flex | flex | html5 | ios | music | ui | video | web Leave a comment

Hello from NCDevCon.  If you were able to attend my presentations, thanks!

I’ve gone ahead and written them up as blog posts for you if you’d like to revisit what I talked about.

 HTML5 vs Flash Video: Choose Wisely (slides)

Live Instrumentation in Flash (slides)

HTML5 vs Flash Video: Choose Wisely Part 10 – Other Options

Filed in development | flash | flash/flex | flex | html5 | ios | javascript | ui | video | web Leave a comment

Lets face it, Apple really stuck us in a bad situation.  While HTML5 is really slick on the desktop (in supported browser with supported file types), its pretty clunky on iOS.  And Flash is ALSO really slick on the desktop, but doesn’t work at all on iOS.

So what we are left with are 2 things that work really well on the desktop, but no common thing that works well on Android, iOS, and the desktop.

What can we do?

Native iOS

Simply the best option on iOS now is to sign up for a developer’s license and make an app.  iOS offers two different video player frameworks MPMoviePlayer and AVPlayer.  MPMoviePlayer is the simplest to get started with, and offers you playback through the Quicktime UI.  AVPlayer is harder to get started with and you are forced to create your own UI, but you have more control over video playback.

AIR for Mobile

What may be the best solution is to build a Flash player with HLS streams on iOS and normal HTTP or RTMP streams on Android or the desktop.  While it’s true that Flash isn’t supported on iOS, Flash Builder 4.5 can compile your existing project out to iOS and Android applications.  All Flash video is supported in AIR, Mobile AIR and the web Flash player – except for iOS.  So you’ll need the two different streams.

Corona and other 3rd Party Packagers

Corona seems to be a very popular way to create cross platform mobile apps these days.  There are other packagers as well like Titanium, Appcelerator and more.  Last I looked they don’t handle video, or don’t handle video very well.  Probably the best is Corona which does allow video to play, but it needs to launch the video in a modal window or fullscreen, and you have little control over it. As cool as these solutions are, I don’t believe that they handle video all that well.

HTML5 vs Flash Video: Choose Wisely Part 9 – The Verdict

Filed in flash | flash/flex | flex | html5 | ios | javascript | ui | video | web Leave a comment

So what wins?  HTML5 video or Flash?  What should you use, what’s better?

The answer to this is that it depends on your project and what platforms you are targeting.

Use HTML5 video for simple playback

For short form video that contains no in-stream advertisements (that’s fancy talk for pre, post, and midrolls) its extremely easy to use HTML5 now.  If your content is at most a few minutes long and you want it to work on any browser and any device you should use HTML5 with a Flash fallback (or vice versa).

Your content should be MP4/h264 so that it will work on iOS, Flash, Chrome, and IE9.  If you feel feisty, you can make a copy of your content as OGG to play in Firefox, but you can easily handle Firefox with Flash video.

Use Flash for in-depth Ad and Tracking support

Adding ads can be a little trickier. It’s much easier to do this with Flash, but if your content is short, all you’ll most likely need is a short pre-roll.  If doing this with HTML5, the experience may be a bit clunky, but at least it will work on the iPad.

It stinks a little more as you add tracking (or other features).  Do you want to duplicate your programming efforts in both Flash and Javascript?

One suggestion might be to implement a Flash player with no control bar and to only handle simple playback of video.  Do all your graphics, reporting and ad logic in Javascript, and just use the Flash player in the same way you’d use a video tag.  In this way, you’re using two things that are pretty interchangable.

All in all, you’ll be most successful if you implement these features in Flash as Flash has the most support for this type of thing.  HTML5 is certainly possible, but hard – you’ll need to power through it, especially if you need it to work on iOS.

Use HTML5 for iOS
If your only options are Flash or HTML5, obviously you should use HTML5 for playback since Flash isn’t supported!

Use Flash for Long-Form Streaming Content

This is a hard truth – HTML5 can’t do streaming.  As such, it can’t do long-form content without completely bogging down end user’s browsers.

For playback on Android devices, you can use your same Flash player for long-form streaming playback (just make sure to make it mobile and touch friendly).

For iOS, you’re pretty much out of luck.  You can run streaming long form content through iOS, but unfortunately that same content won’t work on normal browsers.  If you want playback on both desktop browsers and iOS devices, you’ll need to double your efforts and develop players for each scenario.

TOP