/*
* SoundManager
* Loads a tracklist and handles all SFX and music needs for our games.
* see tracklist.xml (http://pastebin.com/1imV9pM0) for examples of all the features:
* track stitching, looping, offsets, volume, fadein/out, audio position with owner movieclips etc.
*
* The "event" system is an idea borrowed from FMOD.
*
* Ulf Benjaminsson, 2009-06-15
* */
import com.ulfben.noname.utils.SuperSound;
import com.ulfben.noname.utils.TextLoader;
import com.ulfben.noname.utils.Utils;
class com.ulfben.noname.utils.SoundManager extends com.ulfben.noname.utils.Broadcaster {
private var _tracklistURL:String = "xml/tracklist.xml";
private var _tracks:Object;
private var _basedir:String;
private var _owners:Array;
private var _playCount:Object;
public static var DEFAULT_OWNER:MovieClip;
public function SoundManager() {
_global["SoundManager"] = this;
_root["SoundManager"] = this;
_basedir = "";
_playCount = { };
DEFAULT_OWNER = _root.createEmptyMovieClip("soundman", _root.getNextHighestDepth());
var tl:TextLoader = new TextLoader(_tracklistURL);
tl.addEventListener("onLoad", this, "onTrackListAvaliable");
tl.loadFile();
}
public static function get():SoundManager{
if (_global["SoundManager"] == undefined) {
_global["SoundManager"] = new SoundManager();
}
return SoundManager(_global["SoundManager"]);
}
public function playEvent(name:String, owner:MovieClip):Void {
if (!canPlayMore(name)) { return; }
if (owner == undefined) { owner = DEFAULT_OWNER; }
var event:Object = getEventForOwner(name, owner);
var s:SuperSound = event._s;
if (s == undefined) { return; }
replaces(name, owner); //stop all events this one replaces.
if (event._stream && _tracks[name][owner]._offset == 0) {
s.setLoopsForStream(event._loops);
s.loadSound(true);//stream whenever we can; offsets (somewhat...) our lack of preloading.
}else {
if (!s.isLoaded()) { //if it hasn't made it to the cache yet
s.loadSound(false); //request it again.
}
s.setOffset(event._offset);
s.start(event._loops); //push the button and pray it is in place and will play.
}
if (event._maxcount > 0 && s.isPlaying()) {
_playCount[name] = isNaN(_playCount[name]) ? 1 : _playCount[name] += 1;
}
if(event._fadein > 0) {
fadeIn(name, owner, event._volume, event._fadein);
}else{
s.setVolume(event._volume);
}
if(event._follow) {
s.panWith(owner);
}
if(event._leadsto != "") { //stitch events together
s.addEventListener("onSoundComplete", this, "playNextInQue");
}
if(event._maxcount > 0) {
s.addEventListener("onSoundComplete", this, "decreasePlayCount");
s.addEventListener("onSoundStop", this, "decreasePlayCount");
}
}
public function stopAll():Void {
for (var i:Number = 0; i < _tracks.length; i++) {
var event:String = _tracks[DEFAULT_OWNER]._name;
for (var j in _tracks) {
stopEvent(event, j);
}
}
_playCount = { };
}
public function stopEvent(name:String, owner:MovieClip):Void {
if (owner == undefined) {
for (var i:Number = _owners.length; i >= 0; i--) {
if (_owners == undefined) { continue;}
stopEvent(name, _owners);
}
stopEvent(name, DEFAULT_OWNER);
}
var s:SuperSound = _tracks[name][owner]._s;
s.removeEventListener("onSoundComplete", this, "playNextInQue");
s.removeEventListener("onSoundComplete", this, "decreasePlayCount");
if (_tracks[name][owner]._fadeout == 0) {
s.stop(); //calls decreasePlayCount for us
}else {
fadeOutAndStop(name, owner, _tracks[name][owner]._fadeout);
}
}
public function unregisterAllOwners():Void {
for (var i:Number = _owners.length; i >= 0; i--) {
unregisterMe(_owners, i);
}
_owners = [];
}
public function unregisterMe(owner:MovieClip, pruneIndex:Number):Void {
if (owner == DEFAULT_OWNER || owner == undefined) { return; }
if(pruneIndex == undefined){
pruneIndex = Utils.Find(owner, _owners);
}
if (owner == _owners[pruneIndex]) {
_owners.splice(pruneIndex, 1);
}
for (var i:Number = 0; i < _tracks.length; i++) {
_tracks[owner] = undefined;
}
}
public function fadeOutAndStop(name:String, owner:MovieClip, time:Number):Void {
if (time == undefined) { time = 0.5; }
if (owner == undefined) { owner = DEFAULT_OWNER; }
_tracks[name][owner]._s.fadeTo(0, time, true);
}
public function fadeIn(name:String, owner:MovieClip, target:Number, time:Number):Void {
if (time == undefined) { time = 0.5; }
var event:Object = _tracks[name][owner];
event._s.setVolume(0);
event._s.fadeTo(target, time, false);
}
public function fadeTo(name:String, owner:MovieClip, target:Number, time:Number) {
_tracks[name][owner]._s.fadeTo(target, time, false);
}
public function playEventDelayed(name:String, owner:MovieClip, delay:Number):Void {
_global.setTimeout(this, "playEvent", delay, name);//todo, how do we pass owner?
}
private function getEventForOwner(name:String, owner:MovieClip):Object {
if (owner == undefined) { owner = DEFAULT_OWNER;}
var event:Object = _tracks[name][owner];
if (event != undefined) {
return event;
}
if (_tracks[name][DEFAULT_OWNER] == undefined) { return; } //don't load events we haven't defined.
var newEvent:Object = cloneEvent(_tracks[name][DEFAULT_OWNER]);
_owners.push(owner);
newEvent._owner = owner;
newEvent._s = new SuperSound(newEvent._name, _basedir + newEvent._file, owner);
_tracks[name][owner] = newEvent;
return newEvent;
}
private function canPlayMore(name:String):Boolean {
var max:Number = _tracks[name][DEFAULT_OWNER]._maxcount;
if (max == 0) { return true; }
if (isNaN(_playCount[name])) { _playCount[name] = 0; }
return (_playCount[name] < max);
}
private function decreasePlayCount(s:SuperSound):Void {
s.removeEventListener("onSoundComplete", this, "decreasePlayCount");
s.removeEventListener("onSoundStop", this, "decreasePlayCount");
if(isNaN(_playCount[s.getName()])) { _playCount[s.getName()] = 0; }
if(_playCount[s.getName()] > 0){
_playCount[s.getName()]--;
}
}
private function replaces(name:String, owner:MovieClip):Void {
var replaces:Array = _tracks[name][owner]._ends.split("|");
for (var i:Number = 0; i < replaces.length; i++) {
if (replaces == "") { continue; }
stopEvent(replaces, owner);
}
}
private function playNextInQue(s:SuperSound) {
s.removeEventListener("onSoundComplete", this, "playNextInQue");
var next:String = validateOrDefaultString(_tracks[s.getName()][s.getOwner()]._leadsto);
if (next == "") { return; }
playEvent(next, s.getOwner());
}
private function cloneEvent(o:Object):Object {
var event:Object = { };
for (var i in o) {
event = o;
}
event._s = null;
return event;
}
private function onTrackListAvaliable(tl:TextLoader):Void {
if(!tl.isLoaded()){
trace("SoundManager: could not load tracklist.");
return;
}
_tracks = { };
_owners = [];
var tracklist:Object = tl.getDataObject().tracklist;
_basedir = Utils.isValidString(tracklist.attributes.basedir) ? tracklist.attributes.basedir : _basedir;
for (var i:Number = 0; i < tracklist.track.length; i++) {
var attr:Object = tracklist.track.attributes;
if (_tracks[attr.eventname] != undefined) {
continue; //duplicate
}
_tracks = _tracks[attr.eventname] = {};
_tracks[DEFAULT_OWNER] = {
_name: validateOrDefaultString(attr.eventname),
_file: validateOrDefaultString(attr.file),
_volume: validateOrDefaultNumber(attr.volume,100),
_loops: validateOrDefaultNumber(attr.loops,1),
_fadein: validateOrDefaultNumber(attr.fadein,0),
_fadeout: validateOrDefaultNumber(attr.fadeout,0),
_ends: validateOrDefaultString(attr.ends),
_leadsto: validateOrDefaultString(attr.leadsto),
_offset: validateOrDefaultNumber(attr.offset,0),
_follow: validateOrDefaultBool(attr.followowner,false),
_stream: validateOrDefaultBool(attr.stream,true),
_maxcount: validateOrDefaultNumber(attr.maxcount,0),
_owner: DEFAULT_OWNER
};
_tracks[DEFAULT_OWNER]._loops = _tracks[DEFAULT_OWNER]._loops > 0 ? _tracks[DEFAULT_OWNER]._loops : 10000; //loop indefinetly if 0 or less
_tracks[DEFAULT_OWNER]._s = new SuperSound(_tracks[DEFAULT_OWNER]._name, _basedir + _tracks[DEFAULT_OWNER]._file, _tracks[DEFAULT_OWNER]._owner);
_tracks[DEFAULT_OWNER]._s.loadSound(false); //"preload"
}
_tracks.length = tracklist.track.length;
}
private function validateOrDefaultBool(s:String, d:Boolean):Boolean {
if (s == undefined || s.length == 0) { return d; }
s = s.toLowerCase();
return (s == "true" || s == "yes" || s =="y") ? true : false;
}
private function validateOrDefaultNumber(s:String, d:Number):Number {
var n:Number = Number(s);
if (!isNaN(n)) {
return n;
}
if(d == undefined){
return 0;
}
return d;
}
private function validateOrDefaultString(s:String):String {
if(s != undefined && s != "undefined" && s != null) {
return s;
}
return "";
}
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|0 👍
/0 👎
0 B
|👍
/👎
0 B
|👍
/👎