SHARE
TWEET

SoundManager

ulfben Dec 3rd, 2011 158 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * SoundManager
  3.  * Loads a tracklist and handles all SFX and music needs for our games.
  4.  *      see tracklist.xml (http://pastebin.com/1imV9pM0) for examples of all the features:
  5.  *      track stitching, looping, offsets, volume, fadein/out, audio position with owner movieclips etc.
  6.  *
  7.  * The "event" system is an idea borrowed from FMOD.
  8.  *
  9.  * Ulf Benjaminsson, 2009-06-15
  10.  * */
  11.  
  12. import com.ulfben.noname.utils.SuperSound;
  13. import com.ulfben.noname.utils.TextLoader;
  14. import com.ulfben.noname.utils.Utils;
  15.  
  16.  class com.ulfben.noname.utils.SoundManager extends com.ulfben.noname.utils.Broadcaster {
  17.         private var _tracklistURL:String = "xml/tracklist.xml";
  18.         private var _tracks:Object;
  19.         private var _basedir:String;
  20.         private var _owners:Array;
  21.         private var _playCount:Object;
  22.         public static var DEFAULT_OWNER:MovieClip;
  23.  
  24.         public function SoundManager() {
  25.                 _global["SoundManager"] = this;
  26.                 _root["SoundManager"] = this;
  27.                 _basedir = "";
  28.                 _playCount = { };
  29.                 DEFAULT_OWNER = _root.createEmptyMovieClip("soundman", _root.getNextHighestDepth());
  30.                 var tl:TextLoader = new TextLoader(_tracklistURL);
  31.                 tl.addEventListener("onLoad", this, "onTrackListAvaliable");
  32.                 tl.loadFile();
  33.         }
  34.  
  35.         public static function get():SoundManager{
  36.                 if (_global["SoundManager"] == undefined) {
  37.                         _global["SoundManager"] = new SoundManager();
  38.                 }
  39.                 return SoundManager(_global["SoundManager"]);
  40.         }
  41.  
  42.         public function playEvent(name:String, owner:MovieClip):Void {
  43.                 if (!canPlayMore(name)) { return; }
  44.                 if (owner == undefined) { owner = DEFAULT_OWNER; }
  45.                 var event:Object = getEventForOwner(name, owner);
  46.                 var s:SuperSound = event._s;
  47.                 if (s == undefined) { return; }
  48.                 replaces(name, owner); //stop all events this one replaces.
  49.                 if (event._stream && _tracks[name][owner]._offset == 0) {
  50.                         s.setLoopsForStream(event._loops);
  51.                         s.loadSound(true);//stream whenever we can; offsets (somewhat...) our lack of preloading.
  52.                 }else {
  53.                         if (!s.isLoaded()) { //if it hasn't made it to the cache yet
  54.                                 s.loadSound(false); //request it again.
  55.                         }
  56.                         s.setOffset(event._offset);
  57.                         s.start(event._loops); //push the button and pray it is in place and will play.
  58.                 }
  59.                 if (event._maxcount > 0 && s.isPlaying()) {
  60.                         _playCount[name] = isNaN(_playCount[name]) ? 1 : _playCount[name] += 1;
  61.                 }
  62.                 if(event._fadein > 0) {
  63.                         fadeIn(name, owner, event._volume, event._fadein);
  64.                 }else{
  65.                         s.setVolume(event._volume);
  66.                 }
  67.                 if(event._follow) {
  68.                         s.panWith(owner);
  69.                 }
  70.                 if(event._leadsto != "") { //stitch events together
  71.                         s.addEventListener("onSoundComplete", this, "playNextInQue");
  72.                 }
  73.                 if(event._maxcount > 0) {
  74.                         s.addEventListener("onSoundComplete", this, "decreasePlayCount");
  75.                         s.addEventListener("onSoundStop", this, "decreasePlayCount");
  76.                 }
  77.         }
  78.  
  79.         public function stopAll():Void {
  80.                 for (var i:Number = 0; i < _tracks.length; i++) {
  81.                         var event:String = _tracks[DEFAULT_OWNER]._name;
  82.                         for (var j in _tracks) {
  83.                                 stopEvent(event, j);
  84.                         }
  85.                 }
  86.                 _playCount = { };
  87.         }
  88.  
  89.         public function stopEvent(name:String, owner:MovieClip):Void {
  90.                 if (owner == undefined) {
  91.                         for (var i:Number = _owners.length; i >= 0; i--) {
  92.                                 if (_owners == undefined) { continue;}
  93.                                 stopEvent(name, _owners);
  94.                         }
  95.                         stopEvent(name, DEFAULT_OWNER);
  96.                 }
  97.                 var s:SuperSound = _tracks[name][owner]._s;
  98.                 s.removeEventListener("onSoundComplete", this, "playNextInQue");
  99.                 s.removeEventListener("onSoundComplete", this, "decreasePlayCount");
  100.                 if (_tracks[name][owner]._fadeout == 0) {
  101.                         s.stop();       //calls decreasePlayCount for us
  102.                 }else {
  103.                         fadeOutAndStop(name, owner, _tracks[name][owner]._fadeout);
  104.                 }
  105.         }      
  106.  
  107.         public function unregisterAllOwners():Void {
  108.                 for (var i:Number = _owners.length; i >= 0; i--) {
  109.                         unregisterMe(_owners, i);
  110.                 }
  111.                 _owners = [];
  112.         }
  113.  
  114.         public function unregisterMe(owner:MovieClip, pruneIndex:Number):Void {
  115.                 if (owner == DEFAULT_OWNER || owner == undefined) { return; }
  116.                 if(pruneIndex == undefined){
  117.                         pruneIndex = Utils.Find(owner, _owners);
  118.                 }
  119.                 if (owner == _owners[pruneIndex]) {
  120.                         _owners.splice(pruneIndex, 1);
  121.                 }
  122.                 for (var i:Number = 0; i < _tracks.length; i++) {
  123.                         _tracks[owner] = undefined;
  124.                 }
  125.         }      
  126.  
  127.         public function fadeOutAndStop(name:String, owner:MovieClip, time:Number):Void {
  128.                 if (time == undefined) { time = 0.5; }
  129.                 if (owner == undefined) { owner = DEFAULT_OWNER; }
  130.                 _tracks[name][owner]._s.fadeTo(0, time, true);
  131.         }
  132.  
  133.         public function fadeIn(name:String, owner:MovieClip, target:Number, time:Number):Void {
  134.                 if (time == undefined) { time = 0.5; }
  135.                 var event:Object = _tracks[name][owner];
  136.                 event._s.setVolume(0);
  137.                 event._s.fadeTo(target, time, false);
  138.         }      
  139.  
  140.         public function fadeTo(name:String, owner:MovieClip, target:Number, time:Number) {
  141.                 _tracks[name][owner]._s.fadeTo(target, time, false);
  142.         }      
  143.  
  144.         public function playEventDelayed(name:String, owner:MovieClip, delay:Number):Void {
  145.                 _global.setTimeout(this, "playEvent", delay, name);//todo, how do we pass owner?
  146.         }
  147.  
  148.         private function getEventForOwner(name:String, owner:MovieClip):Object {
  149.                 if (owner == undefined) { owner = DEFAULT_OWNER;}
  150.                 var event:Object = _tracks[name][owner];
  151.                 if (event != undefined) {
  152.                         return event;
  153.                 }
  154.                 if (_tracks[name][DEFAULT_OWNER] == undefined) { return; } //don't load events we haven't defined.
  155.  
  156.                 var newEvent:Object = cloneEvent(_tracks[name][DEFAULT_OWNER]);
  157.                 _owners.push(owner);
  158.                 newEvent._owner = owner;
  159.                 newEvent._s = new SuperSound(newEvent._name, _basedir + newEvent._file, owner);
  160.                 _tracks[name][owner] = newEvent;
  161.                 return newEvent;
  162.         }
  163.  
  164.         private function canPlayMore(name:String):Boolean {
  165.                 var max:Number = _tracks[name][DEFAULT_OWNER]._maxcount;
  166.                 if (max == 0) { return true; }
  167.                 if (isNaN(_playCount[name])) { _playCount[name] = 0; }
  168.                 return (_playCount[name] < max);
  169.         }
  170.  
  171.         private function decreasePlayCount(s:SuperSound):Void {
  172.                 s.removeEventListener("onSoundComplete", this, "decreasePlayCount");
  173.                 s.removeEventListener("onSoundStop", this, "decreasePlayCount");
  174.                 if(isNaN(_playCount[s.getName()])) { _playCount[s.getName()] = 0; }
  175.                 if(_playCount[s.getName()] > 0){
  176.                         _playCount[s.getName()]--;
  177.                 }
  178.         }
  179.  
  180.         private function replaces(name:String, owner:MovieClip):Void {
  181.                 var replaces:Array = _tracks[name][owner]._ends.split("|");
  182.                 for (var i:Number = 0; i < replaces.length; i++) {
  183.                         if (replaces == "") { continue; }
  184.                         stopEvent(replaces, owner);
  185.                 }
  186.         }      
  187.  
  188.         private function playNextInQue(s:SuperSound) {
  189.                 s.removeEventListener("onSoundComplete", this, "playNextInQue");
  190.                 var next:String = validateOrDefaultString(_tracks[s.getName()][s.getOwner()]._leadsto);
  191.                 if (next == "") { return; }
  192.                 playEvent(next, s.getOwner());
  193.         }              
  194.  
  195.         private function cloneEvent(o:Object):Object {
  196.                 var event:Object = { };
  197.                 for (var i in o) {
  198.                         event = o;
  199.                 }
  200.                 event._s = null;
  201.                 return event;
  202.         }
  203.  
  204.         private function onTrackListAvaliable(tl:TextLoader):Void {
  205.                 if(!tl.isLoaded()){
  206.                         trace("SoundManager: could not load tracklist.");
  207.                         return;
  208.                 }
  209.                 _tracks = { };
  210.                 _owners = [];
  211.                 var tracklist:Object = tl.getDataObject().tracklist;
  212.                 _basedir = Utils.isValidString(tracklist.attributes.basedir) ? tracklist.attributes.basedir : _basedir;
  213.                 for (var i:Number = 0; i < tracklist.track.length; i++) {
  214.                         var attr:Object = tracklist.track.attributes;
  215.                         if (_tracks[attr.eventname] != undefined) {
  216.                                 continue; //duplicate
  217.                         }
  218.                         _tracks = _tracks[attr.eventname] = {};
  219.                         _tracks[DEFAULT_OWNER] = {
  220.                                 _name: validateOrDefaultString(attr.eventname),
  221.                                 _file: validateOrDefaultString(attr.file),
  222.                                 _volume: validateOrDefaultNumber(attr.volume,100),
  223.                                 _loops: validateOrDefaultNumber(attr.loops,1),
  224.                                 _fadein: validateOrDefaultNumber(attr.fadein,0),
  225.                                 _fadeout: validateOrDefaultNumber(attr.fadeout,0),
  226.                                 _ends: validateOrDefaultString(attr.ends),
  227.                                 _leadsto: validateOrDefaultString(attr.leadsto),
  228.                                 _offset: validateOrDefaultNumber(attr.offset,0),
  229.                                 _follow: validateOrDefaultBool(attr.followowner,false),
  230.                                 _stream: validateOrDefaultBool(attr.stream,true),
  231.                                 _maxcount: validateOrDefaultNumber(attr.maxcount,0),
  232.                                 _owner: DEFAULT_OWNER
  233.                         };
  234.                         _tracks[DEFAULT_OWNER]._loops = _tracks[DEFAULT_OWNER]._loops > 0 ? _tracks[DEFAULT_OWNER]._loops : 10000; //loop indefinetly if 0 or less
  235.                         _tracks[DEFAULT_OWNER]._s = new SuperSound(_tracks[DEFAULT_OWNER]._name, _basedir + _tracks[DEFAULT_OWNER]._file, _tracks[DEFAULT_OWNER]._owner);
  236.                         _tracks[DEFAULT_OWNER]._s.loadSound(false); //"preload"
  237.                 }
  238.                 _tracks.length = tracklist.track.length;
  239.         }
  240.  
  241.         private function validateOrDefaultBool(s:String, d:Boolean):Boolean {
  242.                 if (s == undefined || s.length == 0) { return d; }
  243.                 s = s.toLowerCase();
  244.                 return (s == "true" || s == "yes" || s =="y") ? true : false;
  245.         }
  246.  
  247.         private function validateOrDefaultNumber(s:String, d:Number):Number {
  248.                 var n:Number = Number(s);
  249.                 if (!isNaN(n)) {
  250.                         return n;
  251.                 }
  252.                 if(d == undefined){
  253.                         return 0;
  254.                 }
  255.                 return d;
  256.         }
  257.  
  258.         private function validateOrDefaultString(s:String):String {
  259.                 if(s != undefined && s != "undefined" && s != null) {
  260.                         return s;
  261.                 }
  262.                 return "";
  263.         }
  264.  }
RAW Paste Data
Pastebin PRO Summer Special!
Get 60% OFF on Pastebin PRO accounts!
Top