PageSourceSearch

https://www.hauteloire.fr/plugins/Lecteur_multimedia/soundmanager/soundmanager2.js

js hauteloire.fr collected 2026-10-02 07:33:16 UTC 29,367 bytes, 714 lines download raw bytes

1/*
2   SoundManager 2: Javascript Sound for the Web
3   --------------------------------------------
4   http://www.schillmania.com/projects/soundmanager2/
5
6   Copyright (c) 2007, Scott Schiller. All rights reserved.
7   Code licensed under the BSD License:
8   http://www.schillmania.com/projects/soundmanager2/license.txt
9
10   V2.0b.20070415
11*/
12
13function SoundManager(smURL,smID) {
14  var self = this;
15  this.version = 'V2.0b.20070415';
16  this.url = (smURL||'soundmanager2.swf');
17
18  this.debugMode = true;           // enable debugging output (div#soundmanager-debug, OR console if available + configured)
19  this.useConsole = true;          // use firebug/safari console.log()-type debug console if available
20  this.consoleOnly = false;        // if console is being used, do not create/write to #soundmanager-debug
21  this.nullURL = 'data/null.mp3';  // path to "null" (empty) MP3 file, used to unload sounds
22
23  this.defaultOptions = {
24    'autoLoad': false,             // enable automatic loading (otherwise .load() will be called on demand with .play(), the latter being nicer on bandwidth - if you want to .load yourself, you also can)
25    'stream': true,                // allows playing before entire file has loaded (recommended)
26    'autoPlay': false,             // enable playing of file as soon as possible (much faster if "stream" is true)
27    'onid3': null,                 // callback function for "ID3 data is added/available"
28    'onload': null,                // callback function for "load finished"
29    'whileloading': null,          // callback function for "download progress update" (X of Y bytes received)
30    'onplay': null,                // callback for "play" start
31    'whileplaying': null,          // callback during play (position update)
32    'onstop': null,                // callback for "user stop"
33    'onfinish': null,              // callback function for "sound finished playing"
34    'onbeforefinish': null,        // callback for "before sound finished playing (at [time])"
35    'onbeforefinishtime': 5000,    // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)
36    'onbeforefinishcomplete':null, // function to call when said sound finishes playing
37    'onjustbeforefinish':null,     // callback for [n] msec before end of current sound
38    'onjustbeforefinishtime':200,  // [n] - if not using, set to 0 (or null handler) and event will not fire.
39    'multiShot': true,             // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time
40    'pan': 0,                      // "pan" settings, left-to-right, -100 to 100
41    'volume': 100                  // self-explanatory. 0-100, the latter being the max.
42  }
43
44  this.allowPolling = true;        // allow flash to poll for status update (required for "while playing", "progress" etc. to work.)
45  this.enabled = false;
46  this.o = null;
47  this.id = (smID||'sm2movie');
48  this.oMC = null;
49  this.sounds = [];
50  this.soundIDs = [];
51  this.isIE = (navigator.userAgent.match(/MSIE/));
52  this.isSafari = (navigator.userAgent.match(/safari/i));
53  this.debugID = 'soundmanager-debug';
54  this._debugOpen = true;
55  this._didAppend = false;
56  this._appendSuccess = false;
57  this._didInit = false;
58  this._disabled = false;
59  this._hasConsole = (typeof console != 'undefined' && typeof console.log != 'undefined');
60  this._debugLevels = !self.isSafari?['debug','info','warn','error']:['log','log','log','log'];
61
62  // --- public methods ---
63
64  this.getMovie = function(smID) {
65    // return self.isIE?window[smID]:document[smID];
66    return self.isIE?window[smID]:(self.isSafari?document[smID+'-embed']:document.getElementById(smID+'-embed'));
67  }
68
69  this.loadFromXML = function(sXmlUrl) {
70    try {
71      self.o._loadFromXML(sXmlUrl);
72    } catch(e) {
73      self._failSafely();
74      return true;
75    }
76  }
77
78  this.createSound = function(oOptions) {
79    if (!self._didInit) throw new Error('soundManager.createSound(): Not loaded yet - wait for soundManager.onload() before calling sound-related methods');
80    if (arguments.length==2) {
81      // function overloading in JS! :) ..assume simple createSound(id,url) use case
82      oOptions = {'id':arguments[0],'url':arguments[1]}
83    }
84    var thisOptions = self._mergeObjects(oOptions);
85    self._writeDebug('soundManager.createSound(): "<a href="#" onclick="soundManager.play(\''+thisOptions.id+'\');return false" title="play this sound">'+thisOptions.id+'</a>" ('+thisOptions.url+')',1);
86    if (self._idCheck(thisOptions.id,true)) {
87      self._writeDebug('sound '+thisOptions.id+' already defined - exiting',2);
88      return false;
89    }
90    self.sounds[thisOptions.id] = new SMSound(self,thisOptions);
91    self.soundIDs[self.soundIDs.length] = thisOptions.id;
92    try {
93      self.o._createSound(thisOptions.id,thisOptions.onjustbeforefinishtime);
94    } catch(e) {
95      self._failSafely();
96      return true;
97    }
98    if (thisOptions.autoLoad || thisOptions.autoPlay) self.sounds[thisOptions.id].load(thisOptions);
99    if (thisOptions.autoPlay) self.sounds[thisOptions.id].playState = 1; // we can only assume this sound will be playing soon.
100  }
101
102  this.destroySound = function(sID) {
103    // explicitly destroy a sound before normal page unload, etc.
104    if (!self._idCheck(sID)) return false;
105    for (var i=self.soundIDs.length; i--;) {
106      if (self.soundIDs[i] == sID) {
107        delete self.soundIDs[i];
108        continue;
109      }
110    }
111    self.sounds[sID].unload();
112    delete self.sounds[sID];
113  }
114
115  this.load = function(sID,oOptions) {
116    if (!self._idCheck(sID)) return false;
117    self.sounds[sID].load(oOptions);
118  }
119
120  this.unload = function(sID) {
121    if (!self._idCheck(sID)) return false;
122    self.sounds[sID].unload();
123  }
124
125  this.play = function(sID,oOptions) {
126    if (!self._idCheck(sID)) {
127      if (typeof oOptions != 'Object') oOptions = {url:oOptions}; // overloading use case: play('mySound','/path/to/some.mp3');
128      if (oOptions && oOptions.url) {
129        // overloading use case, creation + playing of sound: .play('someID',{url:'/path/to.mp3'});
130        self._writeDebug('soundController.play(): attempting to create "'+sID+'"',1);
131        oOptions.id = sID;
132        self.createSound(oOptions);
133      } else {
134        return false;
135      }
136    }
137    self.sounds[sID].play(oOptions);
138  }
139
140  this.start = this.play; // just for convenience
141
142  this.setPosition = function(sID,nMsecOffset) {
143    if (!self._idCheck(sID)) return false;
144    self.sounds[sID].setPosition(nMsecOffset);
145  }
146
147  this.stop = function(sID) {
148    if (!self._idCheck(sID)) return false;
149    self._writeDebug('soundManager.stop('+sID+')',1);
150    self.sounds[sID].stop(); 
151  }
152
153  this.stopAll = function() {
154    self._writeDebug('soundManager.stopAll()',1);
155    for (var oSound in self.sounds) {
156      if (self.sounds[oSound] instanceof SMSound) self.sounds[oSound].stop(); // apply only to sound objects
157    }
158  }
159
160  this.pause = function(sID) {
161    if (!self._idCheck(sID)) return false;
162    self.sounds[sID].pause();
163  }
164
165  this.resume = function(sID) {
166    if (!self._idCheck(sID)) return false;
167    self.sounds[sID].resume();
168  }
169
170  this.togglePause = function(sID) {
171    if (!self._idCheck(sID)) return false;
172    self.sounds[sID].togglePause();
173  }
174
175  this.setPan = function(sID,nPan) {
176    if (!self._idCheck(sID)) return false;
177    self.sounds[sID].setPan(nPan);
178  }
179
180  this.setVolume = function(sID,nVol) {
181    if (!self._idCheck(sID)) return false;
182    self.sounds[sID].setVolume(nVol);
183  }
184
185  this.setPolling = function(bPolling) {
186    if (!self.o || !self.allowPolling) return false;
187    self._writeDebug('soundManager.setPolling('+bPolling+')');
188    self.o._setPolling(bPolling);
189  }
190
191  this.disable = function() {
192    // destroy all functions
193    if (self._disabled) return false;
194    self._disabled = true;
195    self._writeDebug('soundManager.disable(): Disabling all functions - future calls will return false.',1);
196    for (var i=self.soundIDs.length; i--;) {
197      self._disableObject(self.sounds[self.soundIDs[i]]);
198    }
199    self.initComplete(); // fire "complete", despite fail
200    self._disableObject(self);
201  }
202
203  this.getSoundById = function(sID,suppressDebug) {
204    if (!sID) throw new Error('SoundManager.getSoundById(): sID is null/undefined');
205    var result = self.sounds[sID];
206    if (!result && !suppressDebug) {
207      self._writeDebug('"'+sID+'" is an invalid sound ID.',2);
208      // soundManager._writeDebug('trace: '+arguments.callee.caller);
209    }
210    return result;
211  }
212
213  this.onload = function() {
214    // window.onload() equivalent for SM2, ready to create sounds etc.
215    // this is a stub - you can override this in your own external script, eg. soundManager.onload = function() {}
216    soundManager._writeDebug('<em>Warning</em>: soundManager.onload() is undefined.',2);
217  }
218
219  this.onerror = function() {
220    // stub for user handler, called when SM2 fails to load/init
221  }
222
223  // --- "private" methods ---
224
225  this._idCheck = this.getSoundById;
226
227  this._disableObject = function(o) {
228    for (var oProp in o) {
229      if (typeof o[oProp] == 'function' && typeof o[oProp]._protected == 'undefined') o[oProp] = function(){return false;}
230    }
231    oProp = null;
232  }
233
234  this._failSafely = function() {
235    // exception handler for "object doesn't support this property or method"
236    var flashCPLink = 'http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html';
237    var fpgssTitle = 'You may need to whitelist this location/domain eg. file:///C:/ or C:/ or mysite.com, or set ALWAYS ALLOW under the Flash Player Global Security Settings page. Note that this seems to apply only to file system viewing.';
238    var flashCPL = '<a href="'+flashCPLink+'" title="'+fpgssTitle+'">view/edit</a>';
239    var FPGSS = '<a href="'+flashCPLink+'" title="Flash Player Global Security Settings">FPGSS</a>';
240    if (!self._disabled) {
241      self._writeDebug('soundManager: JS-&gt;Flash communication failed. Possible causes: flash/browser security restrictions ('+flashCPL+'), insufficient browser/plugin support, or .swf not found',2);
242      self._writeDebug('Verify that the movie path of <em>'+self.url+'</em> is correct (<a href="'+self.url+'" title="If you get a 404/not found, fix it!">test link</a>)',1);
243      if (self._didAppend) {
244        if (!document.domain) {
245          self._writeDebug('Loading from local file system? (document.domain appears to be null, this URL path may need to be added to \'trusted locations\' in '+FPGSS+')',1);
246          self._writeDebug('Possible security/domain restrictions ('+flashCPL+'), should work when served by http on same domain',1);
247        }
248        // self._writeDebug('Note: Movie added via JS method, static object/embed in-page markup method may work instead.');
249      }
250      self.disable();
251    }
252  }
253
254  this._createMovie = function(smID,smURL) {
255    if (self._didAppend && self._appendSuccess) return false; // ignore if already succeeded
256    if (window.location.href.indexOf('debug=1')+1) self.debugMode = true; // allow force of debug mode via URL
257    self._didAppend = true;
258    var html = ['<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="16" height="16" id="'+smID+'"><param name="movie" value="'+smURL+'"><param name="quality" value="high"><param name="allowScriptAccess" value="always" /></object>','<embed name="'+smID+'-embed" id="'+smID+'-embed" src="'+smURL+'" width="1" height="1" quality="high" allowScriptAccess="always" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed>'];
259    var toggleElement = '<div id="'+self.debugID+'-toggle" style="position:fixed;_position:absolute;right:0px;bottom:0px;_top:0px;width:1.2em;height:1.2em;line-height:1.2em;margin:2px;padding:0px;text-align:center;border:1px solid #999;cursor:pointer;background:#fff;color:#333;z-index:706" title="Toggle SM2 debug console" onclick="soundManager._toggleDebug()">-</div>';
260    var debugHTML = '<div id="'+self.debugID+'" style="display:'+(self.debugMode && ((!self._hasConsole||!self.useConsole)||(self.useConsole && self._hasConsole && !self.consoleOnly))?'block':'none')+';opacity:0.85"></div>';
261    var appXHTML = 'soundManager._createMovie(): appendChild/innerHTML set failed. Serving application/xhtml+xml MIME type? Browser may be enforcing strict rules, not allowing write to innerHTML. (PS: If so, this means your commitment to XML validation is going to break stuff now, because this part isn\'t finished yet. ;))';
262
263    var sHTML = '<div style="position:absolute;left:-256px;top:-256px;width:1px;height:1px" class="movieContainer">'+html[self.isIE?0:1]+'</div>'+(self.debugMode && ((!self._hasConsole||!self.useConsole)||(self.useConsole && self._hasConsole && !self.consoleOnly)) && !document.getElementById(self.debugID)?'x'+debugHTML+toggleElement:'');
264
265    var oTarget = (document.body?document.body:document.getElementsByTagName('div')[0]);
266    if (oTarget) {
267      self.oMC = document.createElement('div');
268      self.oMC.className = 'movieContainer';
269      // "hide" flash movie
270      self.oMC.style.position = 'absolute';
271      self.oMC.style.left = '-256px';
272      self.oMC.style.width = '1px';
273      self.oMC.style.height = '1px';
274      try {
275        oTarget.appendChild(self.oMC);
276        self.oMC.innerHTML = html[self.isIE?0:1];
277        self._appendSuccess = true;
278      } catch(e) {
279        // may fail under app/xhtml+xml - has yet to be tested
280        throw new Error(appXHTML);
281      }
282      if (!document.getElementById(self.debugID) && ((!self._hasConsole||!self.useConsole)||(self.useConsole && self._hasConsole && !self.consoleOnly))) {
283        var oDebug = document.createElement('div');
284        oDebug.id = self.debugID;
285        oDebug.style.display = (self.debugMode?'block':'none');
286        if (self.debugMode) {
287          try {
288            var oD = document.createElement('div');
289            oTarget.appendChild(oD);
290            oD.innerHTML = toggleElement;
291          } catch(e) {
292            throw new Error(appXHTML);
293          }
294        }
295        oTarget.appendChild(oDebug);
296      }
297      oTarget = null;
298    }
299    self._writeDebug('-- SoundManager 2 Version '+self.version.substr(1)+' --',1);
300    self._writeDebug('soundManager._createMovie(): trying to load <a href="'+smURL+'" title="Test this link (404=bad)">'+smURL+'</a>',1);
301  }
302
303  this._writeDebug = function(sText,sType) {
304    if (!self.debugMode) return false;
305    if (self._hasConsole && self.useConsole) {
306      console[self._debugLevels[sType]||'log'](sText); // firebug et al
307      if (self.useConsoleOnly) return true;
308    }
309    var sDID = 'soundmanager-debug';
310    try {
311      var o = document.getElementById(sDID);
312      if (!o) return false;
313      var p = document.createElement('div');
314      p.innerHTML = sText;
315      // o.appendChild(p); // top-to-bottom
316      o.insertBefore(p,o.firstChild); // bottom-to-top
317    } catch(e) {
318      // oh well
319    }
320    o = null;
321  }
322  this._writeDebug._protected = true;
323
324  this._writeDebugAlert = function(sText) { alert(sText); }
325
326  if (window.location.href.indexOf('debug=alert')+1) {
327    self.debugMode = true;
328    self._writeDebug = self._writeDebugAlert;
329  }
330
331  this._toggleDebug = function() {
332    var o = document.getElementById(self.debugID);
333    var oT = document.getElementById(self.debugID+'-toggle');
334    if (!o) return false;
335    if (self._debugOpen) {
336      // minimize
337      oT.innerHTML = '+';
338      o.style.display = 'none';
339    } else {
340      oT.innerHTML = '-';
341      o.style.display = 'block';
342    }
343    self._debugOpen = !self._debugOpen;
344  }
345
346  this._toggleDebug._protected = true;
347
348  this._debug = function() {
349    self._writeDebug('soundManager._debug(): sounds by id/url:',0);
350    for (var i=0,j=self.soundIDs.length; i<j; i++) {
351      self._writeDebug(self.sounds[self.soundIDs[i]].sID+' | '+self.sounds[self.soundIDs[i]].url,0);
352    }
353  }
354
355  this._mergeObjects = function(oMain,oAdd) {
356    // non-destructive merge
357    var o1 = oMain;
358    var o2 = (typeof oAdd == 'undefined'?self.defaultOptions:oAdd);
359    for (var o in o2) {
360      if (typeof o1[o] == 'undefined') o1[o] = o2[o];
361    }
362    return o1;
363  }
364
365  this.createMovie = function(sURL) {
366    if (sURL) self.url = sURL;
367    self._initMovie();
368  }
369
370  this._initMovie = function() {
371    // attempt to get, or create, movie
372    if (self.o) return false; // pre-init may have fired this function before window.onload(), may already exist
373    self.o = self.getMovie(self.id); // try to get flash movie (inline markup)
374    if (!self.o) {
375      // try to create
376      self._createMovie(self.id,self.url);
377      self.o = self.getMovie(self.id);
378    }
379    if (self.o) {
380      self._writeDebug('soundManager._initMovie(): Got '+self.o.nodeName+' element ('+(self._didAppend?'created via JS':'static HTML')+')',1);
381    }
382  }
383
384  this.initComplete = function() {
385    if (self._didInit) return false;
386    self._didInit = true;
387    self._writeDebug('-- SoundManager 2 '+(self._disabled?'failed to load':'loaded')+' ('+(self._disabled?'security/load error':'OK')+') --',1);
388    if (self._disabled) {
389      self._writeDebug('soundManager.initComplete(): calling soundManager.onerror()',1);
390      self.onerror.apply(window);
391      return false;
392    }
393    self._writeDebug('soundManager.initComplete(): calling soundManager.onload()',1);
394    try {
395      // call user-defined "onload", scoped to window
396      self.onload.apply(window);
397    } catch(e) {
398      // something broke (likely JS error in user function)
399      self._writeDebug('soundManager.onload() threw an exception: '+e.message,2);
400      throw e; // (so browser/console gets message)
401    }
402    self._writeDebug('soundManager.onload() complete',1);
403  }
404
405  this.init = function() {
406    // called after onload()
407    // self._initMovie();
408    // event cleanup
409    if (window.removeEventListener) {
410      window.removeEventListener('load',self.beginInit,false);
411    } else if (window.detachEvent) {
412      window.detachEvent('onload',self.beginInit);
413    }
414    try {
415      self.o._externalInterfaceTest(); // attempt to talk to Flash
416      self._writeDebug('Flash ExternalInterface call (JS -&gt; Flash) succeeded.',1);
417      if (!self.allowPolling) self._writeDebug('Polling (whileloading/whileplaying support) is disabled.',1);
418      self.setPolling(true);
419      self.enabled = true;
420    }  catch(e) {
421      self._failSafely();
422      self.initComplete();
423      return false;
424    }
425    self.initComplete();
426  }
427
428  this.beginDelayedInit = function() {
429    setTimeout(self.beginInit,200);
430  }
431
432  this.beginInit = function() {
433    self.createMovie(); // ensure creation if not already done
434    self._initMovie();
435    setTimeout(self.init,1000); // some delay required, otherwise JS<->Flash/ExternalInterface communication fails under non-IE (?!)
436  }
437
438  this.destruct = function() {
439    if (self.isSafari) {
440      /* --
441        Safari 1.3.2 (v312.6)/OSX 10.3.9 and perhaps newer will crash if a sound is actively loading when user exits/refreshes/leaves page
442       (Apparently related to ExternalInterface making calls to an unloading/unloaded page?)
443       Unloading sounds (detaching handlers and so on) may help to prevent this
444      -- */
445      for (var i=self.soundIDs.length; i--;) {
446        if (self.sounds[self.soundIDs[i]].readyState == 1) self.sounds[self.soundIDs[i]].unload();
447      }
448    }
449    self.disable();
450    // self.o = null;
451    // self.oMC = null;
452  }
453
454}
455
456function SMSound(oSM,oOptions) {
457  var self = this;
458  var sm = oSM;
459  this.sID = oOptions.id;
460  this.url = oOptions.url;
461  this.options = sm._mergeObjects(oOptions);
462  this.id3 = {
463   /* 
464    Name/value pairs set via Flash when available - see reference for names:
465    http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001567.html
466    (eg., this.id3.songname or this.id3['songname'])
467   */
468  }
469
470  self.resetProperties = function(bLoaded) {
471    self.bytesLoaded = null;
472    self.bytesTotal = null;
473    self.position = null;
474    self.duration = null;
475    self.durationEstimate = null;
476    self.loaded = false;
477    self.loadSuccess = null;
478    self.playState = 0;
479    self.paused = false;
480    self.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success
481    self.didBeforeFinish = false;
482    self.didJustBeforeFinish = false;
483  }
484
485  self.resetProperties();
486
487  // --- public methods ---
488
489  this.load = function(oOptions) {
490    self.loaded = false;
491    self.loadSuccess = null;
492    self.readyState = 1;
493    self.playState = (oOptions.autoPlay||false); // if autoPlay, assume "playing" is true (no way to detect when it actually starts in Flash unless onPlay is watched?)
494    var thisOptions = sm._mergeObjects(oOptions);
495    if (typeof thisOptions.url == 'undefined') thisOptions.url = self.url;
496    try {
497      sm._writeDebug('loading '+thisOptions.url,1);
498      sm.o._load(self.sID,thisOptions.url,thisOptions.stream,thisOptions.autoPlay,thisOptions.whileloading?1:0);
499    } catch(e) {
500      sm._writeDebug('SMSound().load(): JS-&gt;Flash communication failed.',2);
501    }
502  }
503
504  this.unload = function() {
505    // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3
506    sm._writeDebug('SMSound().unload(): "'+self.sID+'"');
507    self.setPosition(0); // reset current sound positioning
508    sm.o._unload(self.sID,sm.nullURL);
509    // reset load/status flags
510    self.resetProperties();
511  }
512
513  this.play = function(oOptions) {
514    if (!oOptions) oOptions = {};
515
516    // --- TODO: make event handlers specified via oOptions only apply to this instance of play() (eg. onfinish applies but will reset to default on finish)
517    if (oOptions.onfinish) self.options.onfinish = oOptions.onfinish;
518    if (oOptions.onbeforefinish) self.options.onbeforefinish = oOptions.onbeforefinish;
519    if (oOptions.onjustbeforefinish) self.options.onjustbeforefinish = oOptions.onjustbeforefinish;
520    // ---
521
522    var thisOptions = sm._mergeObjects(oOptions);
523    if (self.playState == 1) {
524      // var allowMulti = typeof oOptions.multiShot!='undefined'?oOptions.multiShot:sm.defaultOptions.multiShot;
525      var allowMulti = thisOptions.multiShot;
526      if (!allowMulti) {
527        sm._writeDebug('SMSound.play(): "'+self.sID+'" already playing? (one-shot)',1);
528        return false;
529      } else {
530        sm._writeDebug('SMSound.play(): "'+self.sID+'" already playing (multi-shot)',1);
531      }
532    }
533    if (!self.loaded) {
534      if (self.readyState == 0) {
535        sm._writeDebug('SMSound.play(): .play() before load request. Attempting to load "'+self.sID+'"',1);
536        // try to get this sound playing ASAP
537        thisOptions.stream = true;
538        thisOptions.autoPlay = true;
539        // TODO: need to investigate when false, double-playing
540        // if (typeof oOptions.autoPlay=='undefined') thisOptions.autoPlay = true; // only set autoPlay if unspecified here
541        self.load(thisOptions); // try to get this sound playing ASAP
542      } else if (self.readyState == 2) {
543        sm._writeDebug('SMSound.play(): Could not load "'+self.sID+'" - exiting',2);
544        return false;
545      } else {
546        sm._writeDebug('SMSound.play(): "'+self.sID+'" is loading - attempting to play..',1);
547      }
548    } else {
549      sm._writeDebug('SMSound.play(): "'+self.sID+'"');
550    }
551    if (self.paused) {
552      self.resume();
553    } else {
554      self.playState = 1;
555      self.position = (thisOptions.offset||0);
556      if (thisOptions.onplay) thisOptions.onplay.apply(self);
557      self.setVolume(thisOptions.volume);
558      self.setPan(thisOptions.pan);
559      if (!thisOptions.autoPlay) {
560        // sm._writeDebug('starting sound '+self.sID);
561        sm.o._start(self.sID,thisOptions.loop||1,self.position); // TODO: verify !autoPlay doesn't cause issue
562      }
563    }
564  }
565
566  this.start = this.play; // just for convenience
567
568  this.stop = function(bAll) {
569    if (self.playState == 1) {
570      self.playState = 0;
571      self.paused = false;
572      if (sm.defaultOptions.onstop) sm.defaultOptions.onstop.apply(self);
573      sm.o._stop(self.sID);
574    }
575  }
576
577  this.setPosition = function(nMsecOffset) {
578    // sm._writeDebug('setPosition('+nMsecOffset+')');
579    sm.o._setPosition(self.sID,nMsecOffset/1000,self.paused||!self.playState); // if paused or not playing, will not resume (by playing)
580  }
581
582  this.pause = function() {
583    if (self.paused) return false;
584    sm._writeDebug('SMSound.pause()');
585    self.paused = true;
586    sm.o._pause(self.sID);
587  }
588
589  this.resume = function() {
590    if (!self.paused) return false;
591    sm._writeDebug('SMSound.resume()');
592    self.paused = false;
593    sm.o._pause(self.sID); // flash method is toggle-based (pause/resume)
594  }
595
596  this.togglePause = function() {
597    // if playing, pauses - if paused, resumes playing.
598    sm._writeDebug('SMSound.togglePause()');
599    if (!self.playState) {
600      // self.setPosition();
601      self.play({offset:self.position/1000});
602      return false;
603    }
604    if (self.paused) {
605      sm._writeDebug('SMSound.togglePause(): resuming..');
606      self.resume();
607    } else {
608      sm._writeDebug('SMSound.togglePause(): pausing..');
609      self.pause();
610    }
611  }
612
613  this.setPan = function(nPan) {
614    if (typeof nPan == 'undefined') nPan = 0;
615    sm.o._setPan(self.sID,nPan);
616    self.options.pan = nPan;
617  }
618
619  this.setVolume = function(nVol) {
620    if (typeof nVol == 'undefined') nVol = 100;
621    sm.o._setVolume(self.sID,nVol);
622    self.options.volume = nVol;
623  }
624
625  // --- "private" methods called by Flash ---
626
627  this._whileloading = function(nBytesLoaded,nBytesTotal,nDuration) {
628    self.bytesLoaded = nBytesLoaded;
629    self.bytesTotal = nBytesTotal;
630    self.duration = nDuration;
631    self.durationEstimate = parseInt((self.bytesTotal/self.bytesLoaded)*self.duration); // estimate total time (will only be accurate with CBR MP3s.)
632    if (self.readyState != 3 && self.options.whileloading) self.options.whileloading.apply(self);
633    // soundManager._writeDebug('duration/durationEst: '+self.duration+' / '+self.durationEstimate);
634  }
635
636  this._onid3 = function(oID3PropNames,oID3Data) {
637    // oID3PropNames: string array (names)
638    // ID3Data: string array (data)
639    sm._writeDebug('SMSound()._onid3(): "'+this.sID+'" ID3 data received.');
640    var oData = [];
641    for (var i=0,j=oID3PropNames.length; i<j; i++) {
642      oData[oID3PropNames[i]] = oID3Data[i];
643      // sm._writeDebug(oID3PropNames[i]+': '+oID3Data[i]);
644    }
645    self.id3 = sm._mergeObjects(self.id3,oData);
646    if (self.options.onid3) self.options.onid3.apply(self);
647  }
648
649  this._whileplaying = function(nPosition) {
650    if (isNaN(nPosition) || nPosition == null) return false; // Flash may return NaN at times
651    self.position = nPosition;
652    if (self.playState == 1) {
653      if (self.options.whileplaying) self.options.whileplaying.apply(self); // flash may call after actual finish
654      if (self.loaded && self.options.onbeforefinish && self.options.onbeforefinishtime && !self.didBeforeFinish && self.duration-self.position <= self.options.onbeforefinishtime) {
655        sm._writeDebug('duration-position &lt;= onbeforefinishtime: '+self.duration+' - '+self.position+' &lt= '+self.options.onbeforefinishtime+' ('+(self.duration-self.position)+')');
656        self._onbeforefinish();
657      }
658    }
659  }
660
661  this._onload = function(bSuccess) {
662    bSuccess = (bSuccess==1?true:false);
663    sm._writeDebug('SMSound._onload(): "'+self.sID+'"'+(bSuccess?' loaded.':' failed to load (or loaded from cache - weird bug) - [<a href="'+self.url+'">test URL</a>]'));
664    self.loaded = bSuccess;
665    self.loadSuccess = bSuccess;
666    self.readyState = bSuccess?3:2;
667    if (self.options.onload) self.options.onload.apply(self);
668  }
669
670  this._onbeforefinish = function() {
671    if (!self.didBeforeFinish) {
672      self.didBeforeFinish = true;
673      if (self.options.onbeforefinish) self.options.onbeforefinish.apply(self);
674    }
675  }
676
677  this._onjustbeforefinish = function(msOffset) {
678    // msOffset: "end of sound" delay actual value (eg. 200 msec, value at event fire time was 187)
679    if (!self.didJustBeforeFinish) {
680      self.didJustBeforeFinish = true;
681      // soundManager._writeDebug('SMSound._onjustbeforefinish()');
682      if (self.options.onjustbeforefinish) self.options.onjustbeforefinish.apply(self);;
683    }
684  }
685
686  this._onfinish = function() {
687    // sound has finished playing
688    sm._writeDebug('SMSound._onfinish(): "'+self.sID+'"');
689    self.playState = 0;
690    self.paused = false;
691    if (self.options.onfinish) self.options.onfinish.apply(self);
692    if (self.options.onbeforefinishcomplete) self.options.onbeforefinishcomplete.apply(self);
693    // reset some state items
694    self.setPosition(0);
695    self.didBeforeFinish = false;
696    self.didJustBeforeFinish = false;
697  }
698
699}
700
701var soundManager = new SoundManager();
702
703// attach onload handler
704if (window.addEventListener) {
705  window.addEventListener('load',soundManager.beginDelayedInit,false);
706  window.addEventListener('beforeunload',soundManager.destruct,false);
707} else if (window.attachEvent) {
708  window.attachEvent('onload',soundManager.beginInit);
709  window.attachEvent('beforeunload',soundManager.destruct);
710} else {
711  // no add/attachevent support - safe to assume no JS->Flash either.
712  soundManager.onerror();
713  soundManager.disable();
714}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.