Tag Archives: as2

flash audio timeline confusion

Audio synchronization in Flash has always been something of a black art. It’s a lot better these days, but there are still some interesting glitches floating around.

I’ve currently got a doozy of an issue in a project that I thought I was done with over a month ago 🙂

There are two and a half ways to manipulate sound in Flash.

  1. You can just drop audio tracks onto the timeline and hope for the best.
  2. You can instantiate Sound objects in, attach the audio tracks, and play them.
  3. A hybrid method where sounds are loaded onto the timeline but are then manipulated with a Sound object.

In 90% of cases, my game uses the second method. In the other 10%, I used the third. I have a simple flag (stored at _global.audio) that is set to true if people want sound playing and false otherwise. Any of my sound handling code monitors changes in the flag and sets volume on the appropriate sound objects accordingly. Nothing too fancy.

However, we’ve found an interesting fringe case when trying to control timeline sounds via actionscript. To duplicate the problem:

  • Take one stage with a 2 frame timeline and one movie clip.
  • On the movie clip, load a sound onto the timeline.
  • Put the clip onto frame 2 of the stage, leaving frame 1 empty.
  • Put a stop() action on the second frame of the main timeline.

This works as intended – ie, the sound plays exctly once.

  • Now, add some code to the movie clip’s timeline to control the volume:
    [as3]
    var snd:Sound = new Sound(this);
    snd.setVolume( 0 );
    [/as3]

This also works as intended – ie, the sound does not play at all.

  • Replace the stop() action on the main timeline with a gotoAndStop(1) call.

Now if you play the swf… the sound will happen… even though we’re explicitly telling it not to – and you’re jumping to a state where the movie clip containing the sound should not be loaded.

I suspect that what is happening is that when you leave the portion of the timeline where the Sound object exists, there is a bit of confusion in the VM. In stead of discarding the movie clip in its entirety as makes sense, it’s discarding the sound object first. The timeline then continues playing the audio where it left off (after being muted for only one frame).

So… if you want reliable control over your audio assets, the solution might then be to put your Sound object responsible for playing them in a location where it won’t be destroyed when the timeline updates. Unfortunately, that doesn’t seem to work either. I’ve tried locating my Sound object in _global or _root, but that doesn’t solve the problem either.

What appears to happen is that sounds on the timeline are attached to the stage when their individual timelines disappear. Telling my Sound object to listen to the stage in stead of to the movie clip works.

I’m investigating this more… maybe… but shrug. More likely, I will simply find a way to stop using sounds on the timeline at all in this one problem spot in the game. 😛

xpath

Yargh!

I’m currently involved in some very heavy manipulation of XML data in a Flash application. For such purposes, I am compelled to use XPath. It’s a decent enough language. Ok, I lied. It’s good. Saves mounds of time that would otherwise be spent iterating over xml tree structures and searching for elements.

When using XPath in Flash, one has two options. First, Macromedia Adobe has a first party implementation. Apparently it’s not that wonderful and nobody who knows better uses it. Second, there’s the XFactor Studio API. This is what I use. It’s what a lot of people use. It is nice. It has never failed me before.

Until today.

I have a very simple favor to ask of the library. I want to select all of a node’s siblings. Now, granted, I am doing some searching to determine which node’s siblings I need here, but it’s really basic.

The XML doc I’m working with looks something like this:

What I want is all <choice>’s in the same <group> as a <product> with a given <p>. Sound simple enough? Well, it is. The XPath statement to do this might look something like this:

//group[products/p='3']/choice
or
//group/choice[../products/p='3']

Both search paths are equally valid and return the same results when I try them out on other xpath implementations.

The XFactor version returns nothing. I know the lib works, and I know I’m using it correctly since my program continues to function up to this point (and I’m making 4 or 5 selections before this point).

So, I’m mildly peeved here. I’ve tried breaking it up into a pair of sequential queries (first select the appropriate group, then select the choices within that group), but that doesn’t do anything either.

So far, this problem has cost me 2 hours this morning and it doesn’t look to be clearing up any time soon. Sigh.

update

After another hour, I have determined that the XFactor XPath implementation is broken when it comes to searching based on text node values. Chris (coworker) swears up and down that it isn’t broken, so he’s trying to prove me wrong now 😛

In the mean time, I have implemented an ugly brute-force solution to the problem. So, in stead of:
[as3]
var path:String = "//group/choice[../products/p=’"+pid+"’]";
var list:Array = XPath.selectNodes( configurator.firstChild, path );
[/as3]
I have had to settle for something like this:
[as3]
// grab all products
var path:String = "//group/products";
var pNodes:Array = XPath.selectNodes( configurator.firstChild, path );
var gNode:XMLNode = null;

// iterate over products until we find the one we want, YICK
for( var k = 0; k &amp;lt; pNodes.length; k++ ) {
// look at all <p/> children
var tmp:Array = pNodes[k].childNodes;
for( var j = 0; j &amp;lt; tmp.length; j++ ) {
if( tmp[j].firstChild.nodeValue == pid ) {
// parent.parent 🙁
gNode = tmp[j].parentNode.parentNode;
break;
}
}
if( gNode != null ) break;
}

// grab the appropriate wad of choices, finally
var list:Array = XPath.selectNodes( gNode, "//choice" );
[/as3]

update

After about 20 minutes of headscratching, Chris seems to have given up as well 🙂

Interestingly enough… the first party api doesn’t do it either:
[as3]
var path:String = "//group/choice[../products/p=’"+pid+"’]";
var list:Array = mx.xpath.XPathAPI.selectNodeList( configurator.firstChild, path );
[/as3]
So… I’m very curious if anybody actually does these kinds of searches in Flash? They’re valid according to the W3C spec and they work in Java… for a language like Flash (which is currently handcuffed to XML as its only reasonable means of communication with the outside world) to have a broken XPath implementation is… not good. Sigh.

frash

I guess it’s something like official? I’m a Flash developer now. Kind of.

At least, I spent all day writing ActionScript today. It looks and feels like a slightly wonky version of Java. What did I accomplish? I have a simple application that reads in a bunch of XML data, parses the heck out of it, and functions as a rudimentary search engine (via an XPath API class). It’s really quite ugly, but the point of this exercise is the functionality, not the prettiness or efficiency.

Give me a few more weeks before I start playing around with stuff pretty enough to show off.