]> jfr.im git - irc/quakenet/qwebirc.git/blob - static/js/soundmanager2.js
508d461770d04696ed1872fe7517fd30834ae327
[irc/quakenet/qwebirc.git] / static / js / soundmanager2.js
1 /*!
2 SoundManager 2: Javascript Sound for the Web
3 --------------------------------------------
4 http://schillmania.com/projects/soundmanager2/
5
6 Copyright (c) 2008, Scott Schiller. All rights reserved.
7 Code licensed under the BSD License:
8 http://schillmania.com/projects/soundmanager2/license.txt
9
10 V2.93a.20090117
11 */
12
13 var soundManager = null;
14
15 function SoundManager(smURL,smID) {
16
17 this.flashVersion = 8; // version of flash to require, either 8 or 9. Some API features require Flash 9.
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.waitForWindowLoad = false; // force SM2 to wait for window.onload() before trying to call soundManager.onload()
22 this.nullURL = 'null.mp3'; // path to "null" (empty) MP3 file, used to unload sounds (Flash 8 only)
23 this.allowPolling = true; // allow flash to poll for status update (required for "while playing", peak, sound spectrum functions to work.)
24 this.useMovieStar = false; // enable support for Flash 9.0r115+ (codename "MovieStar") MPEG4 audio + video formats (AAC, M4V, FLV, MOV etc.)
25 this.bgColor = '#ffffff'; // movie (.swf) background color, useful if showing on-screen for video etc.
26 this.useHighPerformance = true; // position:fixed flash movie gives increased js/flash speed, but buggy and disabled for firefox/win32 by default (set value to 'always' to override)
27
28 this.defaultOptions = {
29 '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)
30 'stream': true, // allows playing before entire file has loaded (recommended)
31 'autoPlay': false, // enable playing of file as soon as possible (much faster if "stream" is true)
32 'onid3': null, // callback function for "ID3 data is added/available"
33 'onload': null, // callback function for "load finished"
34 'whileloading': null, // callback function for "download progress update" (X of Y bytes received)
35 'onplay': null, // callback for "play" start
36 'onpause': null, // callback for "pause"
37 'onresume': null, // callback for "resume" (pause toggle)
38 'whileplaying': null, // callback during play (position update)
39 'onstop': null, // callback for "user stop"
40 'onfinish': null, // callback function for "sound finished playing"
41 'onbeforefinish': null, // callback for "before sound finished playing (at [time])"
42 'onbeforefinishtime': 5000, // offset (milliseconds) before end of sound to trigger beforefinish (eg. 1000 msec = 1 second)
43 'onbeforefinishcomplete':null, // function to call when said sound finishes playing
44 'onjustbeforefinish':null, // callback for [n] msec before end of current sound
45 'onjustbeforefinishtime':200, // [n] - if not using, set to 0 (or null handler) and event will not fire.
46 'multiShot': true, // let sounds "restart" or layer on top of each other when played multiple times, rather than one-shot/one at a time
47 'position': null, // offset (milliseconds) to seek to within loaded sound data.
48 'pan': 0, // "pan" settings, left-to-right, -100 to 100
49 'volume': 100 // self-explanatory. 0-100, the latter being the max.
50 };
51
52 this.flash9Options = { // flash 9-only options, merged into defaultOptions if flash 9 is being used
53 'isMovieStar': null, // "MovieStar" MPEG4 audio/video mode. Null (default) = auto detect MP4, AAC etc. based on URL. true = force on, ignore URL
54 'usePeakData': false, // enable left/right channel peak (level) data
55 'useWaveformData': false, // enable sound spectrum (raw waveform data) - WARNING: CPU-INTENSIVE: may set CPUs on fire.
56 'useEQData': false // enable sound EQ (frequency spectrum data) - WARNING: Also CPU-intensive.
57 };
58
59 this.movieStarOptions = { // flash 9.0r115+ MPEG4 audio/video options, merged into defaultOptions if flash 9 + movieStar mode is enabled
60 'onmetadata': null, // callback for when video width/height etc. are received
61 'useVideo': false // if loading movieStar content, whether to show video
62 };
63
64 // jslint global declarations
65 /*global sm2Debugger, alert, console, document, navigator, setTimeout, window */
66
67 var SMSound = null; // defined later
68
69 var _s = this;
70 this.version = null;
71 this.versionNumber = 'V2.93a.20090117';
72 this.movieURL = null;
73 this.url = null;
74 this.altURL = null;
75 this.swfLoaded = false;
76 this.enabled = false;
77 this.o = null;
78 this.id = (smID||'sm2movie');
79 this.oMC = null;
80 this.sounds = {};
81 this.soundIDs = [];
82 this.muted = false;
83 this.isIE = (navigator.userAgent.match(/MSIE/i));
84 this.isSafari = (navigator.userAgent.match(/safari/i));
85 this.isGecko = (navigator.userAgent.match(/gecko/i));
86 this.debugID = 'soundmanager-debug';
87 this._debugOpen = true;
88 this._didAppend = false;
89 this._appendSuccess = false;
90 this._didInit = false;
91 this._disabled = false;
92 this._windowLoaded = false;
93 this._hasConsole = (typeof console != 'undefined' && typeof console.log != 'undefined');
94 this._debugLevels = ['log','info','warn','error'];
95 this._defaultFlashVersion = 8;
96
97 this.filePatterns = {
98 flash8: /\.mp3(\?.*)?$/i,
99 flash9: /\.mp3(\?.*)?$/i
100 };
101
102 this.netStreamTypes = ['aac','flv','mov','mp4','m4v','f4v','m4a','mp4v','3gp','3g2']; // Flash v9.0r115+ "moviestar" formats
103 this.netStreamPattern = new RegExp('\\.('+this.netStreamTypes.join('|')+')(\\?.*)?$','i');
104
105 this.filePattern = null;
106 this.features = {
107 peakData: false,
108 waveformData: false,
109 eqData: false,
110 movieStar: false
111 };
112
113 this.sandbox = {
114 'type': null,
115 'types': {
116 'remote': 'remote (domain-based) rules',
117 'localWithFile': 'local with file access (no internet access)',
118 'localWithNetwork': 'local with network (internet access only, no local access)',
119 'localTrusted': 'local, trusted (local + internet access)'
120 },
121 'description': null,
122 'noRemote': null,
123 'noLocal': null
124 };
125
126 this._setVersionInfo = function() {
127 if (_s.flashVersion != 8 && _s.flashVersion != 9) {
128 alert('soundManager.flashVersion must be 8 or 9. "'+_s.flashVersion+'" is invalid. Reverting to '+_s._defaultFlashVersion+'.');
129 _s.flashVersion = _s._defaultFlashVersion;
130 }
131 _s.version = _s.versionNumber+(_s.flashVersion==9?' (AS3/Flash 9)':' (AS2/Flash 8)');
132 // set up default options
133 if (_s.flashVersion > 8) {
134 _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.flash9Options);
135 }
136 if (_s.flashVersion > 8 && _s.useMovieStar) {
137 // flash 9+ support for movieStar formats as well as MP3
138 _s.defaultOptions = _s._mergeObjects(_s.defaultOptions,_s.movieStarOptions);
139 _s.filePatterns.flash9 = new RegExp('\\.(mp3|'+_s.netStreamTypes.join('|')+')(\\?.*)?$','i');
140 _s.features.movieStar = true;
141 } else {
142 _s.useMovieStar = false;
143 _s.features.movieStar = false;
144 }
145 _s.filePattern = _s.filePatterns[(_s.flashVersion!=8?'flash9':'flash8')];
146 _s.movieURL = (_s.flashVersion==8?'soundmanager2.swf':'soundmanager2_flash9.swf');
147 _s.features.peakData = _s.features.waveformData = _s.features.eqData = (_s.flashVersion==9);
148 };
149
150 this._overHTTP = (document.location?document.location.protocol.match(/http/i):null);
151 this._waitingforEI = false;
152 this._initPending = false;
153 this._tryInitOnFocus = (this.isSafari && typeof document.hasFocus == 'undefined');
154 this._isFocused = (typeof document.hasFocus != 'undefined'?document.hasFocus():null);
155 this._okToDisable = !this._tryInitOnFocus;
156
157 this.useAltURL = !this._overHTTP; // use altURL if not "online"
158
159 var flashCPLink = 'http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html';
160
161 // --- public methods ---
162
163 this.supported = function() {
164 return (_s._didInit && !_s._disabled);
165 };
166
167 this.getMovie = function(smID) {
168 return _s.isIE?window[smID]:(_s.isSafari?document.getElementById(smID)||document[smID]:document.getElementById(smID));
169 };
170
171 this.loadFromXML = function(sXmlUrl) {
172 try {
173 _s.o._loadFromXML(sXmlUrl);
174 } catch(e) {
175 _s._failSafely();
176 return true;
177 }
178 };
179
180 this.createSound = function(oOptions) {
181 if (!_s._didInit) {
182 throw new Error('soundManager.createSound(): Not loaded yet - wait for soundManager.onload() before calling sound-related methods');
183 }
184 if (arguments.length == 2) {
185 // function overloading in JS! :) ..assume simple createSound(id,url) use case
186 oOptions = {'id':arguments[0],'url':arguments[1]};
187 }
188 var thisOptions = _s._mergeObjects(oOptions); // inherit SM2 defaults
189 var _tO = thisOptions; // alias
190 _s._wD('soundManager.createSound(): '+_tO.id+' ('+_tO.url+')',1);
191 if (_s._idCheck(_tO.id,true)) {
192 _s._wD('soundManager.createSound(): '+_tO.id+' exists',1);
193 return _s.sounds[_tO.id];
194 }
195 if (_s.flashVersion > 8 && _s.useMovieStar) {
196 if (_tO.isMovieStar === null) {
197 _tO.isMovieStar = (_tO.url.match(_s.netStreamPattern)?true:false);
198 }
199 if (_tO.isMovieStar) {
200 _s._wD('soundManager.createSound(): using MovieStar handling');
201 }
202 if (_tO.isMovieStar && (_tO.usePeakData || _tO.useWaveformData || _tO.useEQData)) {
203 _s._wD('Warning: peak/waveform/eqData features unsupported for non-MP3 formats');
204 _tO.usePeakData = false;
205 _tO.useWaveformData = false;
206 _tO.useEQData = false;
207 }
208 }
209 _s.sounds[_tO.id] = new SMSound(_tO);
210 _s.soundIDs[_s.soundIDs.length] = _tO.id;
211 // AS2:
212 if (_s.flashVersion == 8) {
213 _s.o._createSound(_tO.id,_tO.onjustbeforefinishtime);
214 } else {
215 _s.o._createSound(_tO.id,_tO.url,_tO.onjustbeforefinishtime,_tO.usePeakData,_tO.useWaveformData,_tO.useEQData,_tO.isMovieStar,(_tO.isMovieStar?_tO.useVideo:false));
216 }
217 if (_tO.autoLoad || _tO.autoPlay) {
218 // TODO: does removing timeout here cause problems?
219 if (_s.sounds[_tO.id]) {
220 _s.sounds[_tO.id].load(_tO);
221 }
222 }
223 if (_tO.autoPlay) {
224 _s.sounds[_tO.id].play();
225 }
226 return _s.sounds[_tO.id];
227 };
228
229 this.createVideo = function(oOptions) {
230 if (arguments.length==2) {
231 oOptions = {'id':arguments[0],'url':arguments[1]};
232 }
233 if (_s.flashVersion >= 9) {
234 oOptions.isMovieStar = true;
235 oOptions.useVideo = true;
236 } else {
237 _s._wD('soundManager.createVideo(): flash 9 required for video. Exiting.',2);
238 return false;
239 }
240 if (!_s.useMovieStar) {
241 _s._wD('soundManager.createVideo(): MovieStar mode not enabled. Exiting.',2);
242 }
243 return _s.createSound(oOptions);
244 };
245
246 this.destroySound = function(sID,bFromSound) {
247 // explicitly destroy a sound before normal page unload, etc.
248 if (!_s._idCheck(sID)) {
249 return false;
250 }
251 for (var i=0; i<_s.soundIDs.length; i++) {
252 if (_s.soundIDs[i] == sID) {
253 _s.soundIDs.splice(i,1);
254 continue;
255 }
256 }
257 // conservative option: avoid crash with ze flash 8
258 // calling destroySound() within a sound onload() might crash firefox, certain flavours of winXP + flash 8??
259 // if (_s.flashVersion != 8) {
260 _s.sounds[sID].unload();
261 // }
262 if (!bFromSound) {
263 // ignore if being called from SMSound instance
264 _s.sounds[sID].destruct();
265 }
266 delete _s.sounds[sID];
267 };
268
269 this.destroyVideo = this.destroySound;
270
271 this.load = function(sID,oOptions) {
272 if (!_s._idCheck(sID)) {
273 return false;
274 }
275 _s.sounds[sID].load(oOptions);
276 };
277
278 this.unload = function(sID) {
279 if (!_s._idCheck(sID)) {
280 return false;
281 }
282 _s.sounds[sID].unload();
283 };
284
285 this.play = function(sID,oOptions) {
286 if (!_s._idCheck(sID)) {
287 if (typeof oOptions != 'Object') {
288 oOptions = {url:oOptions}; // overloading use case: play('mySound','/path/to/some.mp3');
289 }
290 if (oOptions && oOptions.url) {
291 // overloading use case, creation + playing of sound: .play('someID',{url:'/path/to.mp3'});
292 _s._wD('soundController.play(): attempting to create "'+sID+'"',1);
293 oOptions.id = sID;
294 _s.createSound(oOptions);
295 } else {
296 return false;
297 }
298 }
299 _s.sounds[sID].play(oOptions);
300 };
301
302 this.start = this.play; // just for convenience
303
304 this.setPosition = function(sID,nMsecOffset) {
305 if (!_s._idCheck(sID)) {
306 return false;
307 }
308 _s.sounds[sID].setPosition(nMsecOffset);
309 };
310
311 this.stop = function(sID) {
312 if (!_s._idCheck(sID)) {
313 return false;
314 }
315 _s._wD('soundManager.stop('+sID+')',1);
316 _s.sounds[sID].stop();
317 };
318
319 this.stopAll = function() {
320 _s._wD('soundManager.stopAll()',1);
321 for (var oSound in _s.sounds) {
322 if (_s.sounds[oSound] instanceof SMSound) {
323 _s.sounds[oSound].stop(); // apply only to sound objects
324 }
325 }
326 };
327
328 this.pause = function(sID) {
329 if (!_s._idCheck(sID)) {
330 return false;
331 }
332 _s.sounds[sID].pause();
333 };
334
335 this.pauseAll = function() {
336 for (var i=_s.soundIDs.length; i--;) {
337 _s.sounds[_s.soundIDs[i]].pause();
338 }
339 };
340
341 this.resume = function(sID) {
342 if (!_s._idCheck(sID)) {
343 return false;
344 }
345 _s.sounds[sID].resume();
346 };
347
348 this.resumeAll = function() {
349 for (var i=_s.soundIDs.length; i--;) {
350 _s.sounds[_s.soundIDs[i]].resume();
351 }
352 };
353
354 this.togglePause = function(sID) {
355 if (!_s._idCheck(sID)) {
356 return false;
357 }
358 _s.sounds[sID].togglePause();
359 };
360
361 this.setPan = function(sID,nPan) {
362 if (!_s._idCheck(sID)) {
363 return false;
364 }
365 _s.sounds[sID].setPan(nPan);
366 };
367
368 this.setVolume = function(sID,nVol) {
369 if (!_s._idCheck(sID)) {
370 return false;
371 }
372 _s.sounds[sID].setVolume(nVol);
373 };
374
375 this.mute = function(sID) {
376 if (typeof sID != 'string') {
377 sID = null;
378 }
379 if (!sID) {
380 _s._wD('soundManager.mute(): Muting all sounds');
381 for (var i=_s.soundIDs.length; i--;) {
382 _s.sounds[_s.soundIDs[i]].mute();
383 }
384 _s.muted = true;
385 } else {
386 if (!_s._idCheck(sID)) {
387 return false;
388 }
389 _s._wD('soundManager.mute(): Muting "'+sID+'"');
390 _s.sounds[sID].mute();
391 }
392 };
393
394 this.muteAll = function() {
395 _s.mute();
396 };
397
398 this.unmute = function(sID) {
399 if (typeof sID != 'string') {
400 sID = null;
401 }
402 if (!sID) {
403 _s._wD('soundManager.unmute(): Unmuting all sounds');
404 for (var i=_s.soundIDs.length; i--;) {
405 _s.sounds[_s.soundIDs[i]].unmute();
406 }
407 _s.muted = false;
408 } else {
409 if (!_s._idCheck(sID)) {
410 return false;
411 }
412 _s._wD('soundManager.unmute(): Unmuting "'+sID+'"');
413 _s.sounds[sID].unmute();
414 }
415 };
416
417 this.unmuteAll = function() {
418 _s.unmute();
419 };
420
421 this.getMemoryUse = function() {
422 if (_s.flashVersion == 8) {
423 // not supported in Flash 8
424 return 0;
425 }
426 if (_s.o) {
427 return parseInt(_s.o._getMemoryUse(),10);
428 }
429 };
430
431 this.setPolling = function(bPolling) {
432 if (!_s.o || !_s.allowPolling) {
433 return false;
434 }
435 // _s._wD('soundManager.setPolling('+bPolling+')');
436 _s.o._setPolling(bPolling);
437 };
438
439 this.disable = function(bUnload) {
440 // destroy all functions
441 if (_s._disabled) {
442 return false;
443 }
444 _s._disabled = true;
445 _s._wD('soundManager.disable(): Disabling all functions - future calls will return false.',1);
446 for (var i=_s.soundIDs.length; i--;) {
447 _s._disableObject(_s.sounds[_s.soundIDs[i]]);
448 }
449 _s.initComplete(); // fire "complete", despite fail
450 _s._disableObject(_s);
451 };
452
453 this.canPlayURL = function(sURL) {
454 return (sURL?(sURL.match(_s.filePattern)?true:false):null);
455 };
456
457 this.getSoundById = function(sID,suppressDebug) {
458 if (!sID) {
459 throw new Error('SoundManager.getSoundById(): sID is null/undefined');
460 }
461 var result = _s.sounds[sID];
462 if (!result && !suppressDebug) {
463 _s._wD('"'+sID+'" is an invalid sound ID.',2);
464 // soundManager._wD('trace: '+arguments.callee.caller);
465 }
466 return result;
467 };
468
469 this.onload = function() {
470 // window.onload() equivalent for SM2, ready to create sounds etc.
471 // this is a stub - you can override this in your own external script, eg. soundManager.onload = function() {}
472 soundManager._wD('<em>Warning</em>: soundManager.onload() is undefined.',2);
473 };
474
475 this.onerror = function() {
476 // stub for user handler, called when SM2 fails to load/init
477 };
478
479 // --- "private" methods ---
480
481 this._idCheck = this.getSoundById;
482
483 var _doNothing = function() {
484 return false;
485 };
486 _doNothing._protected = true;
487
488 this._disableObject = function(o) {
489 for (var oProp in o) {
490 if (typeof o[oProp] == 'function' && typeof o[oProp]._protected == 'undefined') {
491 o[oProp] = _doNothing;
492 }
493 }
494 oProp = null;
495 };
496
497 this._failSafely = function() {
498 // exception handler for "object doesn't support this property or method" or general failure
499 if (!_s._disabled) {
500 _s._wD('soundManager: Failed to initialise.',2);
501 _s.disable();
502 }
503 };
504
505 this._normalizeMovieURL = function(smURL) {
506 var urlParams = null;
507 if (smURL) {
508 if (smURL.match(/\.swf(\?.*)?$/i)) {
509 urlParams = smURL.substr(smURL.toLowerCase().lastIndexOf('.swf?')+4);
510 if (urlParams) {
511 return smURL; // assume user knows what they're doing
512 }
513 } else if (smURL.lastIndexOf('/') != smURL.length-1) {
514 smURL = smURL+'/';
515 }
516 }
517 return(smURL && smURL.lastIndexOf('/')!=-1?smURL.substr(0,smURL.lastIndexOf('/')+1):'./')+_s.movieURL;
518 };
519
520 this._getDocument = function() {
521 return (document.body?document.body:(document.documentElement?document.documentElement:document.getElementsByTagName('div')[0]));
522 };
523
524 this._getDocument._protected = true;
525
526 this._createMovie = function(smID,smURL) {
527 if (_s._didAppend && _s._appendSuccess) {
528 return false; // ignore if already succeeded
529 }
530 if (window.location.href.indexOf('debug=1')+1) {
531 _s.debugMode = true; // allow force of debug mode via URL
532 }
533 _s._didAppend = true;
534
535 // safety check for legacy (change to Flash 9 URL)
536 _s._setVersionInfo();
537 var remoteURL = (smURL?smURL:_s.url);
538 var localURL = (_s.altURL?_s.altURL:remoteURL);
539 _s.url = _s._normalizeMovieURL(_s._overHTTP?remoteURL:localURL);
540 smURL = _s.url;
541
542 var specialCase = null;
543 if (_s.useHighPerformance && _s.useHighPerformance != 'always' && navigator.platform.match(/win32/i) && navigator.userAgent.match(/firefox/i)) {
544 specialCase = 'Note: disabling highPerformance, known issues with this browser/OS combo.';
545 _s.useHighPerformance = false;
546 }
547
548 if (_s.useHighPerformance && _s.useMovieStar) {
549 specialCase = 'Note: disabling highPerformance, not applicable with movieStar mode on';
550 _s.useHighPerformance = false;
551 }
552
553 var oEmbed = {
554 name: smID,
555 id: smID,
556 src: smURL,
557 width: '100%',
558 height: '100%',
559 quality: 'high',
560 allowScriptAccess: 'always',
561 bgcolor: _s.bgColor,
562 pluginspage: 'http://www.macromedia.com/go/getflashplayer',
563 type: 'application/x-shockwave-flash'
564 };
565
566 var oObject = {
567 id: smID,
568 data: smURL,
569 type: 'application/x-shockwave-flash',
570 width: '100%',
571 height: '100%'
572 };
573
574 var oObjectParams = {
575 movie: smURL,
576 AllowScriptAccess: 'always',
577 quality: 'high',
578 bgcolor: _s.bgColor
579 };
580
581 if (_s.useHighPerformance && !_s.useMovieStar) {
582 oEmbed.wmode = 'transparent';
583 oObjectParams.wmode = 'transparent';
584 }
585
586 var oMovie = null;
587 var tmp = null;
588
589 if (_s.isIE) {
590 // IE is "special".
591 oMovie = document.createElement('div');
592 var movieHTML = '<object id="'+smID+'" data="'+smURL+'" type="application/x-shockwave-flash" width="100%" height="100%"><param name="movie" value="'+smURL+'" /><param name="AllowScriptAccess" value="always" /><param name="quality" value="high" />'+(_s.useHighPerformance && !_s.useMovieStar?'<param name="wmode" value="transparent" /> ':'')+'<param name="bgcolor" value="'+_s.bgColor+'" /><!-- --></object>';
593 } else {
594 oMovie = document.createElement('embed');
595 for (tmp in oEmbed) {
596 if (oEmbed.hasOwnProperty(tmp)) {
597 oMovie.setAttribute(tmp,oEmbed[tmp]);
598 }
599 }
600 }
601
602 var oD = document.createElement('div');
603 oD.id = _s.debugID+'-toggle';
604 var oToggle = {
605 position: 'fixed',
606 bottom: '0px',
607 right: '0px',
608 width: '1.2em',
609 height: '1.2em',
610 lineHeight: '1.2em',
611 margin: '2px',
612 textAlign: 'center',
613 border: '1px solid #999',
614 cursor: 'pointer',
615 background: '#fff',
616 color: '#333',
617 zIndex: 10001
618 };
619
620 oD.appendChild(document.createTextNode('-'));
621 oD.onclick = _s._toggleDebug;
622 oD.title = 'Toggle SM2 debug console';
623
624 if (navigator.userAgent.match(/msie 6/i)) {
625 oD.style.position = 'absolute';
626 oD.style.cursor = 'hand';
627 }
628
629 for (tmp in oToggle) {
630 if (oToggle.hasOwnProperty(tmp)) {
631 oD.style[tmp] = oToggle[tmp];
632 }
633 }
634
635 var appXHTML = 'soundManager._createMovie(): appendChild/innerHTML set failed. May be app/xhtml+xml DOM-related.';
636
637 var oTarget = _s._getDocument();
638
639 if (oTarget) {
640
641 _s.oMC = document.getElementById('sm2-container')?document.getElementById('sm2-container'):document.createElement('div');
642
643 if (!_s.oMC.id) {
644 _s.oMC.id = 'sm2-container';
645 _s.oMC.className = 'movieContainer';
646 // "hide" flash movie
647 var s = null;
648 var oEl = null;
649 if (_s.useHighPerformance) {
650 s = {
651 position: 'fixed',
652 width: '8px',
653 height: '8px', // must be at least 6px for flash to run fast. odd? yes.
654 bottom: '0px',
655 left: '0px',
656 zIndex:-1 // sit behind everything else
657 };
658 } else {
659 s = {
660 position: 'absolute',
661 width: '1px',
662 height: '1px',
663 bottom: '0px',
664 left: '0px'
665 };
666 }
667 var x = null;
668 for (x in s) {
669 if (s.hasOwnProperty(x)) {
670 _s.oMC.style[x] = s[x];
671 }
672 }
673 try {
674 if (!_s.isIE) {
675 _s.oMC.appendChild(oMovie);
676 }
677 oTarget.appendChild(_s.oMC);
678 if (_s.isIE) {
679 oEl = _s.oMC.appendChild(document.createElement('div'));
680 oEl.className = 'sm2-object-box';
681 oEl.innerHTML = movieHTML;
682 }
683 _s._appendSuccess = true;
684 } catch(e) {
685 throw new Error(appXHTML);
686 }
687 } else {
688 // it's already in the document.
689 _s.oMC.appendChild(oMovie);
690 if (_s.isIE) {
691 oEl = _s.oMC.appendChild(document.createElement('div'));
692 oEl.className = 'sm2-object-box';
693 oEl.innerHTML = movieHTML;
694 }
695 _s._appendSuccess = true;
696 }
697
698 if (!document.getElementById(_s.debugID) && ((!_s._hasConsole||!_s.useConsole)||(_s.useConsole && _s._hasConsole && !_s.consoleOnly))) {
699 var oDebug = document.createElement('div');
700 oDebug.id = _s.debugID;
701 oDebug.style.display = (_s.debugMode?'block':'none');
702 if (_s.debugMode) {
703 try {
704 oTarget.appendChild(oD);
705 } catch(e2) {
706 throw new Error(appXHTML);
707 }
708 }
709 oTarget.appendChild(oDebug);
710 }
711 oTarget = null;
712 }
713
714 if (specialCase) {
715 _s._wD(specialCase);
716 }
717
718 _s._wD('-- SoundManager 2 '+_s.version+(_s.useMovieStar?', MovieStar mode':'')+(_s.useHighPerformance?', high performance mode':'')+' --',1);
719 _s._wD('soundManager._createMovie(): Trying to load '+smURL+(!_s._overHTTP && _s.altURL?'(alternate URL)':''),1);
720 };
721
722 // aliased to this._wD()
723 this._writeDebug = function(sText,sType,bTimestamp) {
724 if (!_s.debugMode) {
725 return false;
726 }
727 if (typeof bTimestamp != 'undefined' && bTimestamp) {
728 sText = sText + ' | '+new Date().getTime();
729 }
730 if (_s._hasConsole && _s.useConsole) {
731 var sMethod = _s._debugLevels[sType];
732 if (typeof console[sMethod] != 'undefined') {
733 console[sMethod].apply(console,[sText]); // apply() fix for firebug 1.3, so "this" == console
734 } else {
735 console.log(sText);
736 }
737 if (_s.useConsoleOnly) {
738 return true;
739 }
740 }
741 var sDID = 'soundmanager-debug';
742 try {
743 var o = document.getElementById(sDID);
744 if (!o) {
745 return false;
746 }
747 var oItem = document.createElement('div');
748 // sText = sText.replace(/\n/g,'<br />');
749 if (typeof sType == 'undefined') {
750 sType = 0;
751 } else {
752 sType = parseInt(sType,10);
753 }
754 oItem.appendChild(document.createTextNode(sText));
755 if (sType) {
756 if (sType >= 2) {
757 oItem.style.fontWeight = 'bold';
758 }
759 if (sType == 3) {
760 oItem.style.color = '#ff3333';
761 }
762 }
763 // o.appendChild(oItem); // top-to-bottom
764 o.insertBefore(oItem,o.firstChild); // bottom-to-top
765 } catch(e) {
766 // oh well
767 }
768 o = null;
769 };
770 this._writeDebug._protected = true;
771 this._wD = this._writeDebug;
772
773 this._wDAlert = function(sText) { alert(sText); };
774
775 if (window.location.href.indexOf('debug=alert')+1 && _s.debugMode) {
776 _s._wD = _s._wDAlert;
777 }
778
779 this._toggleDebug = function() {
780 var o = document.getElementById(_s.debugID);
781 var oT = document.getElementById(_s.debugID+'-toggle');
782 if (!o) {
783 return false;
784 }
785 if (_s._debugOpen) {
786 // minimize
787 oT.innerHTML = '+';
788 o.style.display = 'none';
789 } else {
790 oT.innerHTML = '-';
791 o.style.display = 'block';
792 }
793 _s._debugOpen = !_s._debugOpen;
794 };
795
796 this._toggleDebug._protected = true;
797
798 this._debug = function() {
799 _s._wD('--- soundManager._debug(): Current sound objects ---',1);
800 for (var i=0,j=_s.soundIDs.length; i<j; i++) {
801 _s.sounds[_s.soundIDs[i]]._debug();
802 }
803 };
804
805 this._debugTS = function(sEventType,bSuccess,sMessage) {
806 // troubleshooter debug hooks
807 if (typeof sm2Debugger != 'undefined') {
808 try {
809 sm2Debugger.handleEvent(sEventType,bSuccess,sMessage);
810 } catch(e) {
811 // oh well
812 }
813 }
814 };
815
816 this._debugTS._protected = true;
817
818 this._mergeObjects = function(oMain,oAdd) {
819 // non-destructive merge
820 var o1 = {}; // clone o1
821 for (var i in oMain) {
822 if (oMain.hasOwnProperty(i)) {
823 o1[i] = oMain[i];
824 }
825 }
826 var o2 = (typeof oAdd == 'undefined'?_s.defaultOptions:oAdd);
827 for (var o in o2) {
828 if (o2.hasOwnProperty(o) && typeof o1[o] == 'undefined') {
829 o1[o] = o2[o];
830 }
831 }
832 return o1;
833 };
834
835 this.createMovie = function(sURL) {
836 if (sURL) {
837 _s.url = sURL;
838 }
839 _s._initMovie();
840 };
841
842 this.go = this.createMovie; // nice alias
843
844 this._initMovie = function() {
845 // attempt to get, or create, movie
846 if (_s.o) {
847 return false; // pre-init may have fired this function before window.onload(), may already exist
848 }
849 _s.o = _s.getMovie(_s.id); // try to get flash movie (inline markup)
850 if (!_s.o) {
851 // try to create
852 _s._createMovie(_s.id,_s.url);
853 _s.o = _s.getMovie(_s.id);
854 }
855 if (_s.o) {
856 _s._wD('soundManager._initMovie(): Got '+_s.o.nodeName+' element ('+(_s._didAppend?'created via JS':'static HTML')+')',1);
857 _s._wD('soundManager._initMovie(): Waiting for ExternalInterface call from Flash..');
858 }
859 };
860
861 this.waitForExternalInterface = function() {
862 if (_s._waitingForEI) {
863 return false;
864 }
865 _s._waitingForEI = true;
866 if (_s._tryInitOnFocus && !_s._isFocused) {
867 _s._wD('soundManager: Special case: Flash may not have started due to non-focused tab (Safari is lame), and/or focus cannot be detected. Waiting for focus-related event..');
868 return false;
869 }
870 if (!_s._didInit) {
871 _s._wD('soundManager: Getting impatient, still waiting for Flash.. ;)');
872 }
873 setTimeout(function() {
874 if (!_s._didInit) {
875 _s._wD('soundManager: No Flash response within reasonable time after document load.\nPossible causes: Flash version under 8, no support, or Flash security denying JS-Flash communication.',2);
876 if (!_s._overHTTP) {
877 _s._wD('soundManager: Loading this page from local/network file system (not over HTTP?) Flash security likely restricting JS-Flash access. Consider adding current URL to "trusted locations" in the Flash player security settings manager at '+flashCPLink+', or simply serve this content over HTTP.',2);
878 }
879 _s._debugTS('flashtojs',false,': Timed out'+(_s._overHTTP)?' (Check flash security)':' (No plugin/missing SWF?)');
880 }
881 // if still not initialized and no other options, give up
882 if (!_s._didInit && _s._okToDisable) {
883 _s._failSafely();
884 }
885 },750);
886 };
887
888 this.handleFocus = function() {
889 if (_s._isFocused || !_s._tryInitOnFocus) {
890 return true;
891 }
892 _s._okToDisable = true;
893 _s._isFocused = true;
894 _s._wD('soundManager.handleFocus()');
895 if (_s._tryInitOnFocus) {
896 // giant Safari 3.1 hack - assume window in focus if mouse is moving, since document.hasFocus() not currently implemented.
897 window.removeEventListener('mousemove',_s.handleFocus,false);
898 }
899 // allow init to restart
900 _s._waitingForEI = false;
901 setTimeout(_s.waitForExternalInterface,500);
902 // detach event
903 if (window.removeEventListener) {
904 window.removeEventListener('focus',_s.handleFocus,false);
905 } else if (window.detachEvent) {
906 window.detachEvent('onfocus',_s.handleFocus);
907 }
908 };
909
910 this.initComplete = function() {
911 if (_s._didInit) {
912 return false;
913 }
914 _s._didInit = true;
915 _s._wD('-- SoundManager 2 '+(_s._disabled?'failed to load':'loaded')+' ('+(_s._disabled?'security/load error':'OK')+') --',1);
916 if (_s._disabled) {
917 _s._wD('soundManager.initComplete(): calling soundManager.onerror()',1);
918 _s._debugTS('onload',false);
919 _s.onerror.apply(window);
920 return false;
921 } else {
922 _s._debugTS('onload',true);
923 }
924 if (_s.waitForWindowLoad && !_s._windowLoaded) {
925 _s._wD('soundManager: Waiting for window.onload()');
926 if (window.addEventListener) {
927 window.addEventListener('load',_s.initUserOnload,false);
928 } else if (window.attachEvent) {
929 window.attachEvent('onload',_s.initUserOnload);
930 }
931 return false;
932 } else {
933 if (_s.waitForWindowLoad && _s._windowLoaded) {
934 _s._wD('soundManager: Document already loaded');
935 }
936 _s.initUserOnload();
937 }
938 };
939
940 this.initUserOnload = function() {
941 _s._wD('soundManager.initComplete(): calling soundManager.onload()',1);
942 // call user-defined "onload", scoped to window
943 _s.onload.apply(window);
944 _s._wD('soundManager.onload() complete',1);
945 };
946
947 this.init = function() {
948 _s._wD('-- soundManager.init() --');
949 // called after onload()
950 _s._initMovie();
951 if (_s._didInit) {
952 _s._wD('soundManager.init(): Already called?');
953 return false;
954 }
955 // event cleanup
956 if (window.removeEventListener) {
957 window.removeEventListener('load',_s.beginDelayedInit,false);
958 } else if (window.detachEvent) {
959 window.detachEvent('onload',_s.beginDelayedInit);
960 }
961 try {
962 _s._wD('Attempting to call Flash from JS..');
963 _s.o._externalInterfaceTest(false); // attempt to talk to Flash
964 // _s._wD('Flash ExternalInterface call (JS-Flash) OK',1);
965 if (!_s.allowPolling) {
966 _s._wD('Polling (whileloading/whileplaying support) is disabled.',1);
967 }
968 _s.setPolling(true);
969 if (!_s.debugMode) {
970 _s.o._disableDebug();
971 }
972 _s.enabled = true;
973 _s._debugTS('jstoflash',true);
974 } catch(e) {
975 _s._debugTS('jstoflash',false);
976 _s._failSafely();
977 _s.initComplete();
978 return false;
979 }
980 _s.initComplete();
981 };
982
983 this.beginDelayedInit = function() {
984 _s._wD('soundManager.beginDelayedInit(): Document loaded');
985 _s._windowLoaded = true;
986 setTimeout(_s.waitForExternalInterface,500);
987 setTimeout(_s.beginInit,20);
988 };
989
990 this.beginInit = function() {
991 if (_s._initPending) {
992 return false;
993 }
994 _s.createMovie(); // ensure creation if not already done
995 _s._initMovie();
996 _s._initPending = true;
997 return true;
998 };
999
1000 this.domContentLoaded = function() {
1001 _s._wD('soundManager.domContentLoaded()');
1002 if (document.removeEventListener) {
1003 document.removeEventListener('DOMContentLoaded',_s.domContentLoaded,false);
1004 }
1005 _s.go();
1006 };
1007
1008 this._externalInterfaceOK = function() {
1009 // callback from flash for confirming that movie loaded, EI is working etc.
1010 if (_s.swfLoaded) {
1011 return false;
1012 }
1013 _s._wD('soundManager._externalInterfaceOK()');
1014 _s._debugTS('swf',true);
1015 _s._debugTS('flashtojs',true);
1016 _s.swfLoaded = true;
1017 _s._tryInitOnFocus = false;
1018 if (_s.isIE) {
1019 // IE needs a timeout OR delay until window.onload - may need TODO: investigating
1020 setTimeout(_s.init,100);
1021 } else {
1022 _s.init();
1023 }
1024 };
1025
1026 this._setSandboxType = function(sandboxType) {
1027 var sb = _s.sandbox;
1028 sb.type = sandboxType;
1029 sb.description = sb.types[(typeof sb.types[sandboxType] != 'undefined'?sandboxType:'unknown')];
1030 _s._wD('Flash security sandbox type: '+sb.type);
1031 if (sb.type == 'localWithFile') {
1032 sb.noRemote = true;
1033 sb.noLocal = false;
1034 _s._wD('Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html',2);
1035 } else if (sb.type == 'localWithNetwork') {
1036 sb.noRemote = false;
1037 sb.noLocal = true;
1038 } else if (sb.type == 'localTrusted') {
1039 sb.noRemote = false;
1040 sb.noLocal = false;
1041 }
1042 };
1043
1044 this.destruct = function() {
1045 _s._wD('soundManager.destruct()');
1046 _s.disable(true);
1047 };
1048
1049 // SMSound (sound object)
1050
1051 SMSound = function(oOptions) {
1052 var _t = this;
1053 this.sID = oOptions.id;
1054 this.url = oOptions.url;
1055 this.options = _s._mergeObjects(oOptions);
1056 this.instanceOptions = this.options; // per-play-instance-specific options
1057 this._iO = this.instanceOptions; // short alias
1058
1059 // assign property defaults (volume, pan etc.)
1060 this.pan = this.options.pan;
1061 this.volume = this.options.volume;
1062
1063 this._debug = function() {
1064 if (_s.debugMode) {
1065 var stuff = null;
1066 var msg = [];
1067 var sF = null;
1068 var sfBracket = null;
1069 var maxLength = 64; // # of characters of function code to show before truncating
1070 for (stuff in _t.options) {
1071 if (_t.options[stuff] !== null) {
1072 if (_t.options[stuff] instanceof Function) {
1073 // handle functions specially
1074 sF = _t.options[stuff].toString();
1075 sF = sF.replace(/\s\s+/g,' '); // normalize spaces
1076 sfBracket = sF.indexOf('{');
1077 msg[msg.length] = ' '+stuff+': {'+sF.substr(sfBracket+1,(Math.min(Math.max(sF.indexOf('\n')-1,maxLength),maxLength))).replace(/\n/g,'')+'... }';
1078 } else {
1079 msg[msg.length] = ' '+stuff+': '+_t.options[stuff];
1080 }
1081 }
1082 }
1083 _s._wD('SMSound() merged options: {\n'+msg.join(', \n')+'\n}');
1084 }
1085 };
1086
1087 this._debug();
1088
1089 this.id3 = {
1090 /*
1091 Name/value pairs set via Flash when available - see reference for names:
1092 http://livedocs.macromedia.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001567.html
1093 (eg., this.id3.songname or this.id3['songname'])
1094 */
1095 };
1096
1097 this.resetProperties = function(bLoaded) {
1098 _t.bytesLoaded = null;
1099 _t.bytesTotal = null;
1100 _t.position = null;
1101 _t.duration = null;
1102 _t.durationEstimate = null;
1103 _t.loaded = false;
1104 _t.playState = 0;
1105 _t.paused = false;
1106 _t.readyState = 0; // 0 = uninitialised, 1 = loading, 2 = failed/error, 3 = loaded/success
1107 _t.muted = false;
1108 _t.didBeforeFinish = false;
1109 _t.didJustBeforeFinish = false;
1110 _t.instanceOptions = {};
1111 _t.instanceCount = 0;
1112 _t.peakData = {
1113 left: 0,
1114 right: 0
1115 };
1116 _t.waveformData = [];
1117 _t.eqData = [];
1118 };
1119
1120 _t.resetProperties();
1121
1122 // --- public methods ---
1123
1124 this.load = function(oOptions) {
1125 if (typeof oOptions != 'undefined') {
1126 _t._iO = _s._mergeObjects(oOptions);
1127 _t.instanceOptions = _t._iO;
1128 } else {
1129 oOptions = _t.options;
1130 _t._iO = oOptions;
1131 _t.instanceOptions = _t._iO;
1132 }
1133 if (typeof _t._iO.url == 'undefined') {
1134 _t._iO.url = _t.url;
1135 }
1136 _s._wD('soundManager.load(): '+_t._iO.url,1);
1137 if (_t._iO.url == _t.url && _t.readyState !== 0 && _t.readyState != 2) {
1138 _s._wD('soundManager.load(): current URL already assigned.',1);
1139 return false;
1140 }
1141 _t.loaded = false;
1142 _t.readyState = 1;
1143 _t.playState = 0; // (oOptions.autoPlay?1:0); // if autoPlay, assume "playing" is true (no way to detect when it actually starts in Flash unless onPlay is watched?)
1144 try {
1145 if (_s.flashVersion==8) {
1146 _s.o._load(_t.sID,_t._iO.url,_t._iO.stream,_t._iO.autoPlay,(_t._iO.whileloading?1:0));
1147 } else {
1148 _s.o._load(_t.sID,_t._iO.url,_t._iO.stream?true:false,_t._iO.autoPlay?true:false); // ,(_tO.whileloading?true:false)
1149 if (_t._iO.isMovieStar && _t._iO.autoLoad && !_t._iO.autoPlay) {
1150 // special case: MPEG4 content must start playing to load, then pause to prevent playing.
1151 _t.pause();
1152 }
1153 }
1154 } catch(e) {
1155 _s._wD('SMSound.load(): Exception: JS-Flash communication failed, or JS error.',2);
1156 _s._debugTS('onload',false);
1157 _s.onerror();
1158 _s.disable();
1159 }
1160
1161 };
1162
1163 this.unload = function() {
1164 // Flash 8/AS2 can't "close" a stream - fake it by loading an empty MP3
1165 // Flash 9/AS3: Close stream, preventing further load
1166 if (_t.readyState !== 0) {
1167 _s._wD('SMSound.unload(): "'+_t.sID+'"');
1168 if (_t.readyState != 2) { // reset if not error
1169 _t.setPosition(0,true); // reset current sound positioning
1170 }
1171 _s.o._unload(_t.sID,_s.nullURL);
1172 // reset load/status flags
1173 _t.resetProperties();
1174 }
1175 };
1176
1177 this.destruct = function() {
1178 // kill sound within Flash
1179 _s._wD('SMSound.destruct(): "'+_t.sID+'"');
1180 _s.o._destroySound(_t.sID);
1181 _s.destroySound(_t.sID,true); // ensure deletion from controller
1182 };
1183
1184 this.play = function(oOptions) {
1185 if (!oOptions) {
1186 oOptions = {};
1187 }
1188 _t._iO = _s._mergeObjects(oOptions,_t._iO);
1189 _t._iO = _s._mergeObjects(_t._iO,_t.options);
1190 _t.instanceOptions = _t._iO;
1191 if (_t.playState == 1) {
1192 var allowMulti = _t._iO.multiShot;
1193 if (!allowMulti) {
1194 _s._wD('SMSound.play(): "'+_t.sID+'" already playing (one-shot)',1);
1195 return false;
1196 } else {
1197 _s._wD('SMSound.play(): "'+_t.sID+'" already playing (multi-shot)',1);
1198 }
1199 }
1200 if (!_t.loaded) {
1201 if (_t.readyState === 0) {
1202 _s._wD('SMSound.play(): Attempting to load "'+_t.sID+'"',1);
1203 // try to get this sound playing ASAP
1204 _t._iO.stream = true;
1205 _t._iO.autoPlay = true;
1206 // TODO: need to investigate when false, double-playing
1207 // if (typeof oOptions.autoPlay=='undefined') _tO.autoPlay = true; // only set autoPlay if unspecified here
1208 _t.load(_t._iO); // try to get this sound playing ASAP
1209 } else if (_t.readyState == 2) {
1210 _s._wD('SMSound.play(): Could not load "'+_t.sID+'" - exiting',2);
1211 return false;
1212 } else {
1213 _s._wD('SMSound.play(): "'+_t.sID+'" is loading - attempting to play..',1);
1214 }
1215 } else {
1216 _s._wD('SMSound.play(): "'+_t.sID+'"');
1217 }
1218 if (_t.paused) {
1219 _t.resume();
1220 } else {
1221 _t.playState = 1;
1222 if (!_t.instanceCount || _s.flashVersion == 9) {
1223 _t.instanceCount++;
1224 }
1225 _t.position = (typeof _t._iO.position != 'undefined' && !isNaN(_t._iO.position)?_t._iO.position:0);
1226 if (_t._iO.onplay) {
1227 _t._iO.onplay.apply(_t);
1228 }
1229 _t.setVolume(_t._iO.volume,true); // restrict volume to instance options only
1230 _t.setPan(_t._iO.pan,true);
1231 _s.o._start(_t.sID,_t._iO.loop||1,(_s.flashVersion==9?_t.position:_t.position/1000));
1232 }
1233 };
1234
1235 this.start = this.play; // just for convenience
1236
1237 this.stop = function(bAll) {
1238 if (_t.playState == 1) {
1239 _t.playState = 0;
1240 _t.paused = false;
1241 // if (_s.defaultOptions.onstop) _s.defaultOptions.onstop.apply(_s);
1242 if (_t._iO.onstop) {
1243 _t._iO.onstop.apply(_t);
1244 }
1245 _s.o._stop(_t.sID,bAll);
1246 _t.instanceCount = 0;
1247 _t._iO = {};
1248 // _t.instanceOptions = _t._iO;
1249 }
1250 };
1251
1252 this.setPosition = function(nMsecOffset,bNoDebug) {
1253 if (typeof nMsecOffset == 'undefined') {
1254 nMsecOffset = 0;
1255 }
1256 var offset = Math.min(_t.duration,Math.max(nMsecOffset,0)); // position >= 0 and <= current available (loaded) duration
1257 _t._iO.position = offset;
1258 if (!bNoDebug) {
1259 _s._wD('SMSound.setPosition('+nMsecOffset+')'+(nMsecOffset != offset?', corrected value: '+offset:''));
1260 }
1261 _s.o._setPosition(_t.sID,(_s.flashVersion==9?_t._iO.position:_t._iO.position/1000),(_t.paused||!_t.playState)); // if paused or not playing, will not resume (by playing)
1262 };
1263
1264 this.pause = function() {
1265 if (_t.paused || _t.playState === 0) {
1266 return false;
1267 }
1268 _s._wD('SMSound.pause()');
1269 _t.paused = true;
1270 _s.o._pause(_t.sID);
1271 if (_t._iO.onpause) {
1272 _t._iO.onpause.apply(_t);
1273 }
1274 };
1275
1276 this.resume = function() {
1277 if (!_t.paused || _t.playState === 0) {
1278 return false;
1279 }
1280 _s._wD('SMSound.resume()');
1281 _t.paused = false;
1282 _s.o._pause(_t.sID); // flash method is toggle-based (pause/resume)
1283 if (_t._iO.onresume) {
1284 _t._iO.onresume.apply(_t);
1285 }
1286 };
1287
1288 this.togglePause = function() {
1289 _s._wD('SMSound.togglePause()');
1290 if (!_t.playState) {
1291 _t.play({position:(_s.flashVersion==9?_t.position:_t.position/1000)});
1292 return false;
1293 }
1294 if (_t.paused) {
1295 _t.resume();
1296 } else {
1297 _t.pause();
1298 }
1299 };
1300
1301 this.setPan = function(nPan,bInstanceOnly) {
1302 if (typeof nPan == 'undefined') {
1303 nPan = 0;
1304 }
1305 if (typeof bInstanceOnly == 'undefined') {
1306 bInstanceOnly = false;
1307 }
1308 _s.o._setPan(_t.sID,nPan);
1309 _t._iO.pan = nPan;
1310 if (!bInstanceOnly) {
1311 _t.pan = nPan;
1312 }
1313 };
1314
1315 this.setVolume = function(nVol,bInstanceOnly) {
1316 if (typeof nVol == 'undefined') {
1317 nVol = 100;
1318 }
1319 if (typeof bInstanceOnly == 'undefined') {
1320 bInstanceOnly = false;
1321 }
1322 _s.o._setVolume(_t.sID,(_s.muted&&!_t.muted)||_t.muted?0:nVol);
1323 _t._iO.volume = nVol;
1324 if (!bInstanceOnly) {
1325 _t.volume = nVol;
1326 }
1327 };
1328
1329 this.mute = function() {
1330 _t.muted = true;
1331 _s.o._setVolume(_t.sID,0);
1332 };
1333
1334 this.unmute = function() {
1335 _t.muted = false;
1336 var hasIO = typeof _t._iO.volume != 'undefined';
1337 _s.o._setVolume(_t.sID,hasIO?_t._iO.volume:_t.options.volume,hasIO?false:true);
1338 };
1339
1340 // --- "private" methods called by Flash ---
1341
1342 this._whileloading = function(nBytesLoaded,nBytesTotal,nDuration) {
1343 if (!_t._iO.isMovieStar) {
1344 _t.bytesLoaded = nBytesLoaded;
1345 _t.bytesTotal = nBytesTotal;
1346 _t.duration = Math.floor(nDuration);
1347 _t.durationEstimate = parseInt((_t.bytesTotal/_t.bytesLoaded)*_t.duration,10); // estimate total time (will only be accurate with CBR MP3s.)
1348 if (_t.readyState != 3 && _t._iO.whileloading) {
1349 _t._iO.whileloading.apply(_t);
1350 }
1351 } else {
1352 _t.bytesLoaded = nBytesLoaded;
1353 _t.bytesTotal = nBytesTotal;
1354 _t.duration = Math.floor(nDuration);
1355 _t.durationEstimate = _t.duration;
1356 if (_t.readyState != 3 && _t._iO.whileloading) {
1357 _t._iO.whileloading.apply(_t);
1358 }
1359 }
1360 };
1361
1362 this._onid3 = function(oID3PropNames,oID3Data) {
1363 // oID3PropNames: string array (names)
1364 // ID3Data: string array (data)
1365 _s._wD('SMSound._onid3(): "'+this.sID+'" ID3 data received.');
1366 var oData = [];
1367 for (var i=0,j=oID3PropNames.length; i<j; i++) {
1368 oData[oID3PropNames[i]] = oID3Data[i];
1369 // _s._wD(oID3PropNames[i]+': '+oID3Data[i]);
1370 }
1371 _t.id3 = _s._mergeObjects(_t.id3,oData);
1372 if (_t._iO.onid3) {
1373 _t._iO.onid3.apply(_t);
1374 }
1375 };
1376
1377 this._whileplaying = function(nPosition,oPeakData,oWaveformData,oEQData) {
1378 if (isNaN(nPosition) || nPosition === null) {
1379 return false; // Flash may return NaN at times
1380 }
1381 _t.position = nPosition;
1382 if (_t._iO.usePeakData && typeof oPeakData != 'undefined' && oPeakData) {
1383 _t.peakData = {
1384 left: oPeakData.leftPeak,
1385 right: oPeakData.rightPeak
1386 };
1387 }
1388 if (_t._iO.useWaveformData && typeof oWaveformData != 'undefined' && oWaveformData) {
1389 _t.waveformData = oWaveformData;
1390 /*
1391 _t.spectrumData = {
1392 left: oSpectrumData.left.split(','),
1393 right: oSpectrumData.right.split(',')
1394 }
1395 */
1396 }
1397 if (_t._iO.useEQData && typeof oEQData != 'undefined' && oEQData) {
1398 _t.eqData = oEQData;
1399 }
1400 if (_t.playState == 1) {
1401 if (_t._iO.whileplaying) {
1402 _t._iO.whileplaying.apply(_t); // flash may call after actual finish
1403 }
1404 if (_t.loaded && _t._iO.onbeforefinish && _t._iO.onbeforefinishtime && !_t.didBeforeFinish && _t.duration-_t.position <= _t._iO.onbeforefinishtime) {
1405 _s._wD('duration-position &lt;= onbeforefinishtime: '+_t.duration+' - '+_t.position+' &lt= '+_t._iO.onbeforefinishtime+' ('+(_t.duration-_t.position)+')');
1406 _t._onbeforefinish();
1407 }
1408 }
1409 };
1410
1411 this._onload = function(bSuccess) {
1412 bSuccess = (bSuccess==1?true:false);
1413 _s._wD('SMSound._onload(): "'+_t.sID+'"'+(bSuccess?' loaded.':' failed to load? - '+_t.url));
1414 if (!bSuccess) {
1415 if (_s.sandbox.noRemote === true) {
1416 _s._wD('SMSound._onload(): Reminder: Flash security is denying network/internet access',1);
1417 }
1418 if (_s.sandbox.noLocal === true) {
1419 _s._wD('SMSound._onload(): Reminder: Flash security is denying local access',1);
1420 }
1421 }
1422 _t.loaded = bSuccess;
1423 _t.readyState = bSuccess?3:2;
1424 if (_t._iO.onload) {
1425 _t._iO.onload.apply(_t);
1426 }
1427 };
1428
1429 this._onbeforefinish = function() {
1430 if (!_t.didBeforeFinish) {
1431 _t.didBeforeFinish = true;
1432 if (_t._iO.onbeforefinish) {
1433 _s._wD('SMSound._onbeforefinish(): "'+_t.sID+'"');
1434 _t._iO.onbeforefinish.apply(_t);
1435 }
1436 }
1437 };
1438
1439 this._onjustbeforefinish = function(msOffset) {
1440 // msOffset: "end of sound" delay actual value (eg. 200 msec, value at event fire time was 187)
1441 if (!_t.didJustBeforeFinish) {
1442 _t.didJustBeforeFinish = true;
1443 if (_t._iO.onjustbeforefinish) {
1444 _s._wD('SMSound._onjustbeforefinish(): "'+_t.sID+'"');
1445 _t._iO.onjustbeforefinish.apply(_t);
1446 }
1447 }
1448 };
1449
1450 this._onfinish = function() {
1451 // sound has finished playing
1452
1453 // TODO: calling user-defined onfinish() should happen after setPosition(0)
1454 // OR: onfinish() and then setPosition(0) is bad.
1455
1456 if (_t._iO.onbeforefinishcomplete) {
1457 _t._iO.onbeforefinishcomplete.apply(_t);
1458 }
1459 // reset some state items
1460 _t.didBeforeFinish = false;
1461 _t.didJustBeforeFinish = false;
1462 if (_t.instanceCount) {
1463 _t.instanceCount--;
1464 if (!_t.instanceCount) {
1465 // reset instance options
1466 // _t.setPosition(0);
1467 _t.playState = 0;
1468 _t.paused = false;
1469 _t.instanceCount = 0;
1470 _t.instanceOptions = {};
1471 if (_t._iO.onfinish) {
1472 _s._wD('SMSound._onfinish(): "'+_t.sID+'"');
1473 _t._iO.onfinish.apply(_t);
1474 }
1475 }
1476 } else {
1477 // _t.setPosition(0);
1478 }
1479 };
1480
1481 this._onmetadata = function(oMetaData) {
1482 // movieStar mode only
1483 _s._wD('SMSound.onmetadata()');
1484 // Contains a subset of metadata. Note that files may have their own unique metadata.
1485 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000267.html
1486 if (!oMetaData.width && !oMetaData.height) {
1487 _s._wD('No width/height given, assuming defaults');
1488 oMetaData.width = 320;
1489 oMetaData.height = 240;
1490 }
1491 _t.metadata = oMetaData; // potentially-large object from flash
1492 _t.width = oMetaData.width;
1493 _t.height = oMetaData.height;
1494 if (_t._iO.onmetadata) {
1495 _s._wD('SMSound._onmetadata(): "'+_t.sID+'"');
1496 _t._iO.onmetadata.apply(_t);
1497 }
1498 _s._wD('SMSound.onmetadata() complete');
1499 };
1500
1501 }; // SMSound()
1502
1503 // register a few event handlers
1504 if (window.addEventListener) {
1505 window.addEventListener('focus',_s.handleFocus,false);
1506 window.addEventListener('load',_s.beginDelayedInit,false);
1507 window.addEventListener('unload',_s.destruct,false);
1508 if (_s._tryInitOnFocus) {
1509 window.addEventListener('mousemove',_s.handleFocus,false); // massive Safari focus hack
1510 }
1511 } else if (window.attachEvent) {
1512 window.attachEvent('onfocus',_s.handleFocus);
1513 window.attachEvent('onload',_s.beginDelayedInit);
1514 window.attachEvent('unload',_s.destruct);
1515 } else {
1516 // no add/attachevent support - safe to assume no JS -> Flash either.
1517 _s._debugTS('onload',false);
1518 soundManager.onerror();
1519 soundManager.disable();
1520 }
1521
1522 if (document.addEventListener) {
1523 document.addEventListener('DOMContentLoaded',_s.domContentLoaded,false);
1524 }
1525
1526 } // SoundManager()
1527
1528 soundManager = new SoundManager();
1529