referencing existing sound objects on the timeline via actionscript 3 - actionscript-3

In Actionscript 3 / Flash 10, is it possible to programmatically reference a sound object that exists on the timeline? I've found lots of examples for referencing DisplayObjects via the following sytax:
var m:MovieClip = stage.getChildByName("SomeMovieClipClass");
var n:MovieClip = stage.getChildByIndex(1);
But this doesn't seem to include sound objects. Similarly, it seems straightforward to instantiate and play a sound that exists in the Library via Actionscript:
var s:SoundClip1 = new SoundClip1(); // exported in first frame via properties
s.play();
For my purposes, though, I'd like to reference sound clips (ideally in a specific layer, although that seems to be a design-time element) that designers have adjusted and arranged on the timeline, so that I can inspect their waveforms via code, at runtime. Something like this:
// Imaginary Code
sc = timeline.getSoundClipByName("SoundClip1");
sc.extract(waveform,sc.length/1000 * bitrate);
Is this possible? Thanks!

As of this date, no it is not possible to access the soundChannel generated by a timeline sound. It's a feature I would love to see implemented.
I was going to try to test the feasibility of using computeSpectrum to get the waveform of a timeline sound but I'm having problems importing mp3s right now. In absence of firsthand proof of concept, I searched around and found this thread:
http://www.kirupa.com/forum/showthread.php?t=329632
Which links to this solution
http://www.mail-archive.com/flashcoders#chattyfig.figleaf.com/msg43157.html
But of course this doesn't allow you to disambiguate between different timeline sounds. I'm pretty sure you won't be able to do that at all.
I have not ever used Sound.extract(), but if the sounds exist in the fla library this indicates to me that you can simply give them a Class name and at runtime use extract() to gather the waveform for your own purposes, yes? Then whenever the appropriate timeline sound plays, you can tap into the waveform from the Sound object. Perhaps a timeline callback or event would suffice for this?

Related

Model-view design in Flash

I'm creating a simple game to learn Flash programming. To have a clean model/view separation, I want to create a Player class which simply holds data relevant to the user. I'm also creating a StatusView class which extends MovieClip and which coresponds to a movie clip symbol which I've created in my Flash project. Basically the StatusView will display the data of my Player class onscreen.
I'm used to doing this sort of thing using listeners, so I've found the EventDispatcher class and added one as a member of my Player class. I'd like to have my StatusView movie clip add an event listener to my Player class so that it can receive messages whenever I change the data in my Player class.
The problem is, there doesn't seem to be anywhere for me to put my Player class so that the StatusView can find it (to add the listener). Everything in the project is created directly by one of the movie clips, and the runtime seems to create these movie clips in an arbitrary order. For example, say I create a MovieClip symbol called GameView and I create the instance of the Player there, and GameView is the parent of StatusView. When StatusView is constructed, I'd like to be able to access the Player from it's parent, but at that point GameView hasn't had it's constructor code run yet. This is true even if I wait for the ADDED_TO_STAGE event.
I could put the game model code in a singleton, but this seems like a hack to me. Is there a best practices way in Flash that lets me create and access my game model independent of all the MovieClip symbol stuff?
If you want to pass the reference of the Model to the constructor of the View, but are not calling the constructor yourself (because you do not create the object via code) you are out of luck here.
You could instead simply define a method on your View to pass a reference of the Model object:
public function setModel(value:Model):void
usage:
view.setModel(player);
There's no "law" that you have to pass the Model to the constructor of the View.
You can also create a set function for convenience:
public function set model(value:Model):void
usage:
view.model = player;
I feel like I have to disagree on the Singleton. The purpose of a Singleton is to guarantee that there's only one instance of it in existence. That's it.
It is not there to pass reference around easily (because the method to get the single instance is static). This is (IMO) a bad practice.
You could make anythign static in order to pass it around "easily". But this would make a mess and nobody does that.
But suddenly, just because the singleton pattern uses a static method, a lot of people think it's a clever way to get to the reference. I beg to differ.
First of all, you could implement Player class as singleton if you need just one instance. I don't think that that looks like a hack (for example, in PureMVC framework each model is a singleton).
At second, you can create instances of Player class in some general class (manager) and send them to views.
P.S. Also, I want to note that you can extend your Player class from EventDisptacher without creating specific field "eventDispatcher" in Player class. I don't know what way is better, but this one is simpler, imho.

On the use of frames and functions in Flash AS3

My question is, in a flash game I use different frames for levels. And I am confused on how functions work for this. My first frame works fine but I need help with using functions on other frames and keeping functions specific to one frame. Any help is appreciated, just a quick simple explanation
You cannot associate a function with a specific frame.
When you execute code on a frame, what actually happens is the MovieClip containing that frame will call a function called addFrameScript(), passing to it a representation of the code you write on the frame.
This means:
Until you visit a frame that defines a function, you cannot call said function.
Once you have visited a frame that defines a function, that function is attached to the parent MovieClip, and you are able to call the function at any point in the timeline that is earlier or later.
If you try to define a new function with the same name on a different frame, you will get a 1021: Duplicate function definition error.
Instead of making a new function for every frame or level, you should make a single function that is able to handle different information that is representative of a level, e.g.
function loadLevel(level:int):void
{
// Do stuff with the value of level.
// For example, this function might look at a data source that maps
// the level numbers to some level data representing tile placement.
}
This could be defined on the first frame, then on each subsequent frame:
loadLevel(1); // Frame 2
loadLevel(2); // Frame 3
// ...etc
All of this of course is not ideal and could be done better avoiding the timeline and instead using to OOP paradigm that AS3 provides.
I have found using multiple levels within the same scene causes no end to headaches for me.
I'm no expert & i'm sure its possible to do so in many cases and I have seen some great games created using 1 frame 1 scene & all code in an external .as.
However I find it much easier myself to just use 1 frame per level and put each level in a different Scene.

Loader.as returning blank bitmap

I have an application which pulls in Bitmap resources from a server - currently I use the Loader class to do this, then, once they're loaded, generate a BitmapData based on the loader dimensions and draw the instance of Loader directly to it (the BitmapData is used for Away3D textures as well as Bitmap instances, so I have no need for the Loader once fetched).
This has always worked for me, but recently I started getting 0x0 Loaders, and invalid BitmapData as a result.
I stopped doing this:
this.imageBitmap = new BitmapData(this.imageLoader.width, this.imageLoader.height, true, 0);
..and started doing this:
this.imageBitmap = new BitmapData(event.target.content.width, event.target.content.height, true, 0);
Where event is the Event.COMPLETE event fired by the loader. This fixed the dimension problem, but the BitmapData is just a plain white bitmap (and it's set to transparent by default, so this is being drawn into it). Frustratingly, this doesn't happen every time, if I refresh the application it works as it should around 25% of the time, otherwise it plays up like this.
I've got a tight deadline and I'm really screwing about this, if anyone could help or suggest a better way of doing it you'd really be saving my neck!
Sounds like you need to adjust the image decoding policy for the loader - to ensure it decodes the image before COMPLETE fires - then the width and height etc should be reliable.
To do it, just add a suitable LoaderContext object to the Loader.load method:
var loaderContext:LoaderContext = new LoaderContext();
//set decode policy
loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD;
//load image
loader.load(yourUrl, loaderContext);
The default decode policy is ImageDecodingPolicy.ON_DEMAND - which doesnt decode the image until it is actually required.
Lang docs: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/ImageDecodingPolicy.html
Fixed it, stupid oversight and bit of an obscure situation but I'll leave an answer in case anyone runs into something similar.
My loader is contained in an Asset class - when another object requires the internal bitmap, it queries this class - if the bitmap's present, it returns it, if not it loads it with a loader and registers a callback for a COMPLETE event which is fired when the Loader has loaded and transferred its contents to a BitmapData instance.
The stupid mistake I'd made was that, if several objects were querying the same (as-yet-unloaded) asset, it would start reloading the asset each time, creating a new Loader as it did so...so when the first Loader was complete, it would fire an event but no reference to it would exist, not only creating a memory leak but causing the Asset class to extract the BitmapData from the most-recently-created Loader, which was not complete! The asynchronous nature of Loader is the reason it worked sometimes, as on occasion the final Loader would be ready in time for BitmapData extraction.
Simple solution was to create an internal boolean, _isLoading, which is set to true the first time load() is called - any subsequent calls are ignored if it's true, but callbacks still registered, works a treat!

AS3: Handle BulkLoader.COMPLETE event on AS3 Preloader

I am trying to use BulkLoader (https://github.com/arthur-debert/BulkLoader) to preload all assets of my AS3/Flex application. Right now it is working and I am able to access the contents everywhere on my Main module (where my BulkLoader instance lives).
My problem: I need to handle the BulkLoader.COMPLETE event from my preloader (pre.as living next to Main.mxml on src/), to allow the user to exit the preloader and enter the application ONLY after BulkLoader.COMPLETE was fired.
Thanks!
Why not pass the reference to the BulkLoader instance?
Somethinglike this:
preloader.setLoader(_bulkLoaderInstance or name)
or
var preloader:Preloader = new Preloder(_bulkLoaderInstance or name)
BTW, the LoaderMax from Greensock is better (fewer bugs, more reliable events, nicer API).

How to have variables accessible across keyframes- AS3

I'm working on a portfolio suggestion application in Flash, which consists of two views: ask user for 3 to 4 points of information, and display recommendations based on that information.
The first view is going swimmingly, as all I need are the graphics to be created. However, I'm having trouble understanding how a AS3 variable can be seen across keyframes when it was declared and initialized on the first frame.
The only multi-view app I've done is a Restaurant Guide flash app that was described in Adobe Flash CS5 Classroom in a Book. In that example, the only AS function on four of the views
was a stop() function.
If I were to do the same in this app, and declare the variables as global in the first frame, will they be accessible throughout?
CLARIFICATION
Two comments have said that my question is unclear, so I hope this makes my question more understandable. I want to know how, if I gather all the user information on Frame 1 and then switch to a view on Frame 15, to access those variables on Frame 1.
This isn't really the way you're supposed to work in AS3. Each view should be an object in your library with an associated class. Your document should also have a class associated with it, and it is here that you would hold your common data. The document class would instantiate each view as it is required and pass in the relevant variables.
That said, if you want to work the old way you shouldn't have trouble declaring a variable on frame 1 like this:
var myVar:String = "Hello!";
and then accessing it on frame 15 of the same timeline like this:
trace(myVar);
If that's what you're doing and it's not working then you'll need to update your question with some code examples.