1 /**
  2  * This file is part of the Web Enabled Audio and Sound Enhancement Library (aka the Weasel audio library) Copyright 2011 - 2013 Warren Willmey. It is covered by the GNU General Public License version 3 as published by the Free Software Foundation, you should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
  3  */
  4 
  5 if( undefined == window.weasel ) window.weasel = {};
  6 if( undefined == weasel.Helper ) weasel.Helper = {};
  7 
  8 // ---------------------------------------------------------------------------
  9 /** Handle the change interpolation for the Easy Menu.
 10  * 
 11  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
 12  * to the Easy Menu.
 13  * @param {int} iInterpolationType = The interpolation type to use.
 14  * 
 15  * @private
 16  */
 17 weasel.Helper._MenuChangeInterpolation = function( oBrowserAudio, iInterpolationType )
 18 {
 19 	if( oBrowserAudio != undefined && iInterpolationType != undefined )
 20 	{
 21 		oBrowserAudio.setInterpolation( iInterpolationType );
 22 	}
 23 };
 24 
 25 // ---------------------------------------------------------------------------
 26 /** Handle the display update for changes in interpolation for the Easy Menu.
 27  * 
 28  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
 29  * to the Easy Menu.
 30  * @param {HTMLSelectElement} oElement = The select HTML Element containing all the Interpolation types in the Easy Menu.
 31  * 
 32  * @private
 33  */
 34 weasel.Helper._MenuUpdateInterpolation = function( oBrowserAudio, oElement )
 35 {
 36 	if( oBrowserAudio != undefined && oElement != undefined )
 37 	{
 38 		var oModule = oBrowserAudio.getModule();
 39 
 40 		if( oModule )
 41 		{
 42 			oElement.selectedIndex = oModule.getChannel( 0 ).getChannelInterpolation();
 43 		}
 44 	}
 45 };
 46 
 47 
 48 // ---------------------------------------------------------------------------
 49 /** Handle the change mixer for the Easy Menu.
 50  * 
 51  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
 52  * to the Easy Menu.
 53  * @param {int} iMixerType = The mixer type to use.
 54  * 
 55  * @private
 56  */
 57 weasel.Helper._MenuChangeMixer = function( oBrowserAudio, iMixerType )
 58 {
 59 	if( oBrowserAudio != undefined && iMixerType != undefined )
 60 	{
 61 		oBrowserAudio.getAudioBuffer().setMixerType( iMixerType );
 62 	}
 63 };
 64 
 65 // ---------------------------------------------------------------------------
 66 /** Handle the display update for changes in Mixer for the Easy Menu.
 67  * 
 68  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
 69  * to the Easy Menu.
 70  * @param {HTMLSelectElement} oElement = The select HTML Element containing all the Mixer types in the Easy Menu.
 71  * 
 72  * @private
 73  */
 74 weasel.Helper._MenuUpdateMixer = function( oBrowserAudio, oElement )
 75 {
 76 	if( oBrowserAudio != undefined && oElement != undefined )
 77 	{
 78 		oElement.selectedIndex = oBrowserAudio.getAudioBuffer().getMixerType();
 79 	}
 80 };
 81 
 82 
 83 // ---------------------------------------------------------------------------
 84 /** Handle the change of replay frequency for the Easy Menu.
 85  * 
 86  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
 87  * to the Easy Menu.
 88  * @param {int} iReplayFrequency = The new replay frequency to use.
 89  * 
 90  * @private
 91  */
 92 weasel.Helper._MenuChangeReplayFrequency = function( oBrowserAudio, iReplayFrequency )
 93 {
 94 	if( oBrowserAudio != undefined && iReplayFrequency != undefined )
 95 	{
 96 		oBrowserAudio.changeReplayFrequency( iReplayFrequency );
 97 	}
 98 };
 99 
100 // ---------------------------------------------------------------------------
101 /** Handle the display update for changes in replay frequency for the Easy Menu.
102  * 
103  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
104  * to the Easy Menu.
105  * @param {HTMLSelectElement} oElement = The select HTML Element containing all the replay frequencies in the Easy Menu.
106  * 
107  * @private
108  */
109 weasel.Helper._MenuUpdateReplayFrequency = function( oBrowserAudio, oElement )
110 {
111 	if( oBrowserAudio != undefined && oElement != undefined )
112 	{
113 		var iReplayFrequency = oBrowserAudio.getPlaybackFrequency();
114 
115 		for( var iChild = oElement.children.length; --iChild >= 0; )
116 		{
117 			if( oElement.children[ iChild ].value == iReplayFrequency )
118 			{
119 				oElement.selectedIndex = oElement.children[ iChild ].index;
120 				break;
121 			}
122 		}
123 	}
124 };
125 
126 // ---------------------------------------------------------------------------
127 /** Handle the change of volume for the Easy Menu.
128  * 
129  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
130  * to the Easy Menu.
131  * @param {Element} oStatus = The status HTML Element used to display the current volume in the Easy Menu.
132  * @param {float} fVolume = The new volume to use.
133  * 
134  * @private
135  */
136 weasel.Helper._MenuChangeVolume = function( oBrowserAudio, oStatus, fVolume )
137 {
138 	if( oBrowserAudio != undefined && oStatus != undefined && fVolume != undefined )
139 	{
140 		var oModule = oBrowserAudio.getModule();
141 
142 		if( oModule )
143 		{
144 			oModule.setMasterVolume( fVolume );
145 			oStatus.textContent = ((oModule.getMasterVolume() * 100) |0) + '%';
146 		}
147 	}
148 };
149 
150 // ---------------------------------------------------------------------------
151 /** Handle the display update of volume for the Easy Menu.
152  * 
153  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
154  * to the Easy Menu.
155  * @param {Element} oStatus = The status HTML Element used to display the current volume in the Easy Menu.
156  * @param {HTMLDivElement} oScrollBar = The div Element set to display a scrollbar for volume adjustment.
157  * 
158  * @private
159  */
160 weasel.Helper._MenuUpdateMasterVolume = function( oBrowserAudio, oStatus, oScrollBar )
161 {
162 
163 	if( oBrowserAudio != undefined && oStatus != undefined && oScrollBar != undefined )
164 	{
165 		var oModule = oBrowserAudio.getModule();
166 		
167 		if( oModule )
168 		{
169 			var fVolume = oModule.getMasterVolume();
170 			oStatus.textContent = ((fVolume * 100) |0) + '%';
171 			oScrollBar.scrollLeft = (fVolume * 500) |0;
172 		}
173 	}
174 };
175 
176 // ---------------------------------------------------------------------------
177 /** Handle the change of Pre-buffering for the Easy Menu.
178  * 
179  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
180  * to the Easy Menu.
181  * @param {Element} oStatus = The status HTML Element used to display the current pre-buffering value in the Easy Menu.
182  * @param {int} iPreBufferMS = The new pre-buffer size to use in milliseconds.
183  * 
184  * @private
185  */
186 weasel.Helper._MenuChangePreBuffer = function( oBrowserAudio, oStatus, iPreBufferMS )
187 {
188 	if( oBrowserAudio != undefined && oStatus != undefined && iPreBufferMS != undefined )
189 	{
190 		if( iPreBufferMS < oBrowserAudio.getIntervalRate() )
191 		{
192 			iPreBufferMS = oBrowserAudio.getIntervalRate();
193 		}
194 
195 		oBrowserAudio.setPreBufferingInMS( iPreBufferMS );
196 		oStatus.textContent = (oBrowserAudio.getPreBufferingInMS()|0) + 'ms';
197 	}
198 };
199 
200 // ---------------------------------------------------------------------------
201 /** Handle the display update of pre-buffering for the Easy Menu.
202  * 
203  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
204  * to the Easy Menu.
205  * @param {Element} oStatus = The status HTML Element used to display the current pre-buffering in the Easy Menu.
206  * @param {Element} oIntervalRate = The interval rate HTML Element used to display the current interval rate in the Easy Menu.
207  * @param {HTMLDivElement} oScrollBar = The div Element set to display a scrollbar for pre-buffering adjustment.
208  * 
209  * @private
210  */
211 weasel.Helper._MenuUpdatePreBuffer = function( oBrowserAudio, oStatus, oIntervalRate, oLatencyScrollBar )
212 {
213 	if( oBrowserAudio != undefined && oIntervalRate != undefined && oStatus != undefined && oLatencyScrollBar != undefined )
214 	{
215 		var iPreBufferingInMS = oBrowserAudio.getPreBufferingInMS()|0;
216 		oIntervalRate.textContent = (oBrowserAudio.getIntervalRate() |0) + 'ms';
217 		oStatus.textContent = iPreBufferingInMS + 'ms';
218 		oLatencyScrollBar.scrollLeft = iPreBufferingInMS;
219 	}
220 };
221 
222 // ---------------------------------------------------------------------------
223 /** Handle the change of latency for speed for the Easy Menu.
224  * 
225  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
226  * to the Easy Menu.
227  * @param {bool} bTradeLatencyForSpeed = True = latency false = speed.
228  * 
229  * @private
230  */
231 weasel.Helper._MenuChangeLatency = function( oBrowserAudio, bTradeLatencyForSpeed )
232 {
233 	if( oBrowserAudio != undefined && bTradeLatencyForSpeed != undefined )
234 	{
235 		oBrowserAudio.tradeLowerLatencyForSpeed( bTradeLatencyForSpeed );
236 	}
237 };
238 
239 // ---------------------------------------------------------------------------
240 /** Handle the change of fidelity for HTML5 Audio for the Easy Menu.
241  * 
242  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
243  * to the Easy Menu.
244  * @param {bool} bHTML5LowFidelityMode = True = low fidelity, false = high fidelity.
245  * 
246  * @private
247  */
248 weasel.Helper._MenuChangeHTML5Fidelity = function( oBrowserAudio, bHTML5LowFidelityMode )
249 {
250 	if( oBrowserAudio != undefined && bHTML5LowFidelityMode != undefined )
251 	{
252 		oBrowserAudio.setHTML5LowFidelityMode( bHTML5LowFidelityMode );
253 	}
254 };
255 
256 //---------------------------------------------------------------------------
257 /** Add the Easy Menu Style Sheet to the provided header element.
258  * 
259  * @param {Element} oHeaderTag = The page header element to add the Easy Menu style sheet to.
260  * 
261  * @private
262  */
263 weasel.Helper._addEasyMenuCSSToPage = function( oHeaderTag )
264 {
265 	if( !oHeaderTag || !oHeaderTag.appendChild || !(oHeaderTag instanceof Element) )
266 	{
267 		return false;
268 	}
269 
270 	var oStyleElement = document.createElement( 'style' );
271 	oStyleElement.type = 'text/css';
272 	oStyleElement.id = 'weaselMenuCSS';
273 	oStyleElement.innerHTML = [ 'ul.weaselMenu {'
274 , '	padding: 0px;'
275 , '	margin: 0px;'
276 , '}'
277 
278 , 'ul.weaselMenu li {'
279 , '	list-style: none;'
280 , '	border: 2px solid;'
281 , '	position: absolute;'
282 , '	text-align:center;'
283 , '	color: black;'
284 , '	background: #adf;'
285 , '	border: 2px solid #3bd;'
286 , '	padding: 10px;'
287 , '	border-radius: 15px 15px; -moz-border-radius: 15px; -webkit-border-radius: 15px;' 
288 , '	box-shadow: 15px 15px 15px rgba(0, 0, 0, 0.2); -webkit-box-shadow: 15px 15px rgba(0, 0, 0, 0.2); -moz-box-shadow: 15px 15px rgba(0, 0, 0, 0.2);'
289 , '	font-family: Calibri, Tahoma, Geneva, sans-serif;'
290 , '	font-size: small;'
291 , '	position: relative;'
292 , '	z-index: 999;'
293 , '}'
294 
295 , 'ul.weaselMenu ul {'
296 , '	display: none;'
297 , '	padding: 0px;'
298 , '	position: absolute;'
299 , '	left: 100%;'
300 , '	top: -2px;'
301 , '}'
302 
303 , 'ul.weaselMenu ul ul {'
304 , '	padding: 0px;'
305 , '	position: absolute;'
306 , '	left: 100%;'
307 , '	top: -2px;'
308 , '}'
309 , 'ul.weaselMenu ul li {'
310 , '	list-style: none;'
311 , '	position: relative;'
312 , '}'
313 
314 , 'ul.weaselMenu li:hover > ul {'
315 , '	display: block;'
316 , '}'
317 
318 
319 , 'ul.weaselMenu li:hover {'
320 , '	background: #bef;'
321 , '	color:red;'
322 , '}'
323 
324 , 'div.weaselScrollBar{'
325 , '	font-family: monospace;'
326 , '	font-size: 20px;'
327 , '	width:200px;'
328 , '	height:1px;'
329 , '	padding-top:20px;'
330 , '	overflow-y: hidden;'
331 , '	overflow-x:scroll ;'
332 , '}'
333 
334 , 'span.weaselInline {'
335 , '	display: inline-block;'
336 , '}' ].join( "\r\n" );
337 
338 	oHeaderTag.appendChild( oStyleElement );
339 
340 	return true;
341 };
342 
343 // ---------------------------------------------------------------------------
344 /** Append the Interpolation menu to the sub menu.
345  * 
346  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the Interpolation menu to.
347  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
348  * to the Easy Menu.
349  * 
350  * @private
351  */
352 weasel.Helper._subMenuInterpolation = function( oSubMenus, oBrowserAudio )
353 {
354 	var oMenuItem = document.createElement( 'li' );
355 	var oNested = document.createElement( 'ul' );
356 	var oList = document.createElement( 'li' );
357 	var oSelect = document.createElement( 'select' );
358 	oSelect.id = 'weaselMenuInterpolation';
359 	/** Anonymous event handler.
360 	 * @param {Event} e = The event which has been raised.
361 	 * @private
362 	 * @ignore
363 	 */
364 	oSelect.onclick = function( e ){ weasel.Helper._MenuChangeInterpolation( oBrowserAudio, parseInt( this.value ) ); };
365 	/** Anonymous event handler.
366 	 * @param {Event} e = The event which has been raised.
367 	 * @private
368 	 * @ignore
369 	 */
370 	oMenuItem.onmouseover = function( e ){ weasel.Helper._MenuUpdateInterpolation( oBrowserAudio, oSelect ); };
371 
372 	var oSupportedInterpolationTypes = weasel.Channel.prototype.getSupportedInterpolationTypes();
373 	var iSize = 0;
374 
375 	for( var sPropertyName in oSupportedInterpolationTypes )
376 	{
377 		if( oSupportedInterpolationTypes.hasOwnProperty( sPropertyName ) )
378 		{
379 			var sDisplayName = sPropertyName.replace(/_/gi,' ').replace(/\$/gi, '-' );
380 			var oOption = document.createElement( 'option' );
381 			oOption.text = sDisplayName;
382 			oOption.value = oSupportedInterpolationTypes[ sPropertyName ];
383 
384 			oSelect.appendChild( oOption );
385 			iSize++;
386 		}
387 	}
388 	oSelect.size = iSize;
389 
390 	oList.appendChild( oSelect );
391 	oNested.appendChild( oList );
392 	oMenuItem.textContent = 'Interpolation';
393 	oMenuItem.appendChild( oNested );
394 	oSubMenus.appendChild( oMenuItem );
395 };
396 
397 // ---------------------------------------------------------------------------
398 /** Append the Master Volume menu to the sub menu.
399  * 
400  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the Master Volume menu to.
401  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
402  * to the Easy Menu.
403  * 
404  * @private
405  */
406 weasel.Helper._subMenuMasterVolume = function ( oSubMenus, oBrowserAudio )
407 {
408 	var oMenuItem = document.createElement( 'li' );
409 	var oNested = document.createElement( 'ul' );
410 	var oList = document.createElement( 'li' );
411 	var oStatus = document.createElement( 'div' );
412 	oStatus.id = 'weaselMasterVolume';
413 	oStatus.textContent = '100%';
414 	
415 	var oVolumeScrollBar = document.createElement( 'div' );
416 	oVolumeScrollBar.className = 'weaselScrollBar';
417 	oVolumeScrollBar.id = 'weaselMenuVolumeScrollBar';
418 	oVolumeScrollBar.title = 'Master volume.';
419 	oVolumeScrollBar.innerHTML = new Array( 10 +1 ).join( '0123456789' );
420 	/** Anonymous event handler.
421 	 * @param {Event} e = The event which has been raised.
422 	 * @private
423 	 * @ignore
424 	 */
425 	oVolumeScrollBar.onscroll = function(e){ weasel.Helper._MenuChangeVolume( oBrowserAudio, oStatus, parseInt( this.scrollLeft ) / 500 ); };
426 	
427 	oList.appendChild( oStatus );
428 	oList.appendChild( oVolumeScrollBar );
429 	
430 	oNested.appendChild( oList );
431 	/** Anonymous event handler.
432 	 * @param {Event} e = The event which has been raised.
433 	 * @private
434 	 * @ignore
435 	 */
436 	oMenuItem.onmouseover = function( e ){ weasel.Helper._MenuUpdateMasterVolume( oBrowserAudio, oStatus, oVolumeScrollBar ); };
437 	oMenuItem.textContent = 'Master Volume';
438 	oMenuItem.appendChild( oNested );
439 	oSubMenus.appendChild( oMenuItem );
440 };
441 
442 // ---------------------------------------------------------------------------
443 /** Append the Mixer menu to the sub menu.
444  * 
445  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the Mixer menu to.
446  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
447  * to the Easy Menu.
448  * 
449  * @private
450  */
451 weasel.Helper._subMenuMixer = function( oSubMenus, oBrowserAudio )
452 {
453 	var oMenuItem = document.createElement( 'li' );
454 	var oNested = document.createElement( 'ul' );
455 	var oList = document.createElement( 'li' );
456 	var oSelect = document.createElement( 'select' );
457 	oSelect.id = 'weaselMenuMixer';
458 	/** Anonymous event handler.
459 	 * @param {Event} e = The event which has been raised.
460 	 * @private
461 	 * @ignore
462 	 */
463 	oSelect.onclick = function( e ){ weasel.Helper._MenuChangeMixer( oBrowserAudio, parseInt( this.value ) ); };
464 	/** Anonymous event handler.
465 	 * @param {Event} e = The event which has been raised.
466 	 * @private
467 	 * @ignore
468 	 */
469 	oMenuItem.onmouseover = function( e ){ weasel.Helper._MenuUpdateMixer( oBrowserAudio, oSelect ); };
470 
471 	var oSupportedMixerTypes = weasel.AudioBuffer.prototype.getSupportedMixerTypes();
472 	var iSize = 0;
473 
474 	for( var sPropertyName in oSupportedMixerTypes )
475 	{
476 		if( oSupportedMixerTypes.hasOwnProperty( sPropertyName ) )
477 		{
478 			var sDisplayName = sPropertyName.replace(/_/gi,' ').replace(/\$/gi, '-' );
479 			var oOption = document.createElement( 'option' );
480 			oOption.text = sDisplayName;
481 			oOption.value = oSupportedMixerTypes[ sPropertyName ];
482 
483 			oSelect.appendChild( oOption );
484 			iSize++;
485 		}
486 	}
487 	oSelect.size = iSize;
488 
489 	oList.appendChild( oSelect );
490 	oNested.appendChild( oList );
491 	oMenuItem.textContent = 'Mixer';
492 	oMenuItem.appendChild( oNested );
493 	oSubMenus.appendChild( oMenuItem );
494 };
495 
496 
497 // ---------------------------------------------------------------------------
498 /** Append the Replay Frequency menu to the sub menu.
499  * 
500  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the  Replay Frequency menu to.
501  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
502  * to the Easy Menu.
503  * 
504  * @private
505  */
506 weasel.Helper._subMenuReplayFrequency = function( oSubMenus, oBrowserAudio )
507 {
508 	var oMenuItem = document.createElement( 'li' );
509 	var oNested = document.createElement( 'ul' );
510 	var oList = document.createElement( 'li' );
511 	var oSelect = document.createElement( 'select' );
512 	oSelect.size = 9;
513 	oSelect.id = 'weaselMenuReplayFrequency';
514 	/** Anonymous event handler.
515 	 * @param {Event} e = The event which has been raised.
516 	 * @private
517 	 * @ignore
518 	 */
519 	oSelect.onclick = function( e ){weasel.Helper._MenuChangeReplayFrequency( oBrowserAudio, parseInt( this.value ) ); };
520 	/** Anonymous event handler.
521 	 * @param {Event} e = The event which has been raised.
522 	 * @private
523 	 * @ignore
524 	 */
525 	oMenuItem.onmouseover = function( e ){ weasel.Helper._MenuUpdateReplayFrequency( oBrowserAudio, oSelect ); };
526 
527 	var oFrequencies = {  11025 : '11Khz'
528 						, 16000 : '16Khz'
529 						, 22050 : '22Khz'
530 						, 24000 : '24Khz'
531 						, 32000 : '32Khz'
532 						, 44100 : '44.1Khz (CD quality)'
533 						, 48000 : '48Khz (DAT - Digital Audio Tape)'
534 						, 96000 : '96Khz'
535 						, 192000: '192Khz' };
536 
537 	for( var sPropertyName in oFrequencies )
538 	{
539 		if( oFrequencies.hasOwnProperty( sPropertyName ) )
540 		{
541 			var oOption = document.createElement( 'option' );
542 			oOption.value = parseInt( sPropertyName );
543 			oOption.text = oFrequencies[ sPropertyName ];
544 
545 			oSelect.appendChild( oOption );
546 		}
547 	}
548 	oList.appendChild( oSelect );
549 
550 	if( weasel.BrowserAudio.prototype.AudioType.Mozilla == oBrowserAudio.getAudioType() )
551 	{
552 		var oCheckboxLatency = document.createElement( 'input' );
553 		oCheckboxLatency.type = 'checkbox';
554 		oCheckboxLatency.checked = !oBrowserAudio.getTradeLowerLatencyForSpeed();
555 		oCheckboxLatency.id = 'weaselMenuTradeLatencyForSpeed';
556 		oCheckboxLatency.title = 'On some audio subsystems (Firefox) use a audio buffer the size of a single interval in order to reduce the number of write calls to the browser audio api. This has the disadvantage of poor latency response (because the audio buffer always has to be full before passing to the browser, when we might actually need slightly more or slightly less), but is quicker.';
557 		/** Anonymous event handler.
558 		 * @param {Event} e = The event which has been raised.
559 		 * @private
560 		 */
561 		oCheckboxLatency.onclick = function(e){ weasel.Helper._MenuChangeLatency( oBrowserAudio, !this.checked ); };
562 		var oLabelLatency = document.createElement( 'label' );
563 		oLabelLatency.htmlFor = 'weaselMenuTradeLatencyForSpeed';
564 		oLabelLatency.textContent = ':Trade latency for speed.';
565 		
566 		oList.appendChild( oCheckboxLatency );
567 		oList.appendChild( oLabelLatency );
568 	}
569 
570 	if( weasel.BrowserAudio.prototype.AudioType.HTML5Audio == oBrowserAudio.getAudioType() )
571 	{
572 		var oCheckboxFidelity = document.createElement( 'input' );
573 		oCheckboxFidelity.type = 'checkbox';
574 		oCheckboxFidelity.checked = oBrowserAudio.getHTML5LowFidelityMode();
575 		oCheckboxFidelity.id = 'weaselMenuHTML5LowFidelityMode';
576 		oCheckboxFidelity.title = 'HTML5 Audio does not support the playback of audio created by JavaScript, so it is dummied by create a new DataURI every 2 seconds. Unfortunately this is extremely slow and causes the browser to slightly pause. Low fidelity mode generates 4 times less data, causing less or no pause by using mono 8-bit audio instead of 16-bit stereo.';
577 		/** Anonymous event handler.
578 		 * @param {Event} e = The event which has been raised.
579 		 * @private
580 		 */
581 		oCheckboxFidelity.onclick = function( e ){ weasel.Helper._MenuChangeHTML5Fidelity( oBrowserAudio, this.checked ); };
582 		var oLabelFidelity = document.createElement( 'label' );
583 		oLabelFidelity.htmlFor = 'weaselMenuHTML5LowFidelityMode';
584 		oLabelFidelity.textContent = ':HTML5 low fidelity mode.';
585 		
586 		oList.appendChild( oCheckboxFidelity );
587 		oList.appendChild( oLabelFidelity );
588 	}
589 
590 	oNested.appendChild( oList );
591 	oMenuItem.innerHTML = 'Replay Frequency';
592 	oMenuItem.appendChild( oNested );
593 	oSubMenus.appendChild( oMenuItem );
594 };
595 
596 // ---------------------------------------------------------------------------
597 /** Append the Pre-Buffering menu to the sub menu.
598  * 
599  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the  Pre-Buffering menu to.
600  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is attached 
601  * to the Easy Menu.
602  * 
603  * @private
604  */
605 weasel.Helper._subMenuPreBuffering = function( oSubMenus, oBrowserAudio )
606 {
607 	var oMenuItem = document.createElement( 'li' );
608 	var oNested = document.createElement( 'ul' );
609 	var oList = document.createElement( 'li' );
610 
611 	var oIntervalWrapper = document.createElement( 'div' );
612 	oIntervalWrapper.textContent = 'Set Interval Rate: ';
613 	oIntervalWrapper.title = 'The interval rate at which audio is approximately updated in milliseconds.';
614 
615 	var oIntervalRate = document.createElement( 'span' );
616 	oIntervalRate.id = 'weaselIntervalRate';
617 	oIntervalRate.className = 'weaselInline';
618 	oIntervalRate.textContent = '0ms';
619 
620 	oIntervalWrapper.appendChild( oIntervalRate );
621 
622 
623 	var oPreBufferWrapper = document.createElement( 'div' );
624 	oPreBufferWrapper.textContent = 'Audio Buffer size: ';
625 	oPreBufferWrapper.title = 'The wanted amount of audio pre-buffering in milliseconds, a higher value reduces the chances of audio pops and glitches but increases the latency before you hear the audio.';
626 	var oStatus = document.createElement( 'span' );
627 	oStatus.id = 'weaselPreBuffering';
628 	oStatus.textContent = '0ms';
629 
630 	oPreBufferWrapper.appendChild( oStatus );
631 
632 	var oLatencyScrollBar = document.createElement( 'div' );
633 	oLatencyScrollBar.className = 'weaselScrollBar';
634 	oLatencyScrollBar.id = 'weaselMenuLatencyScrollBar';
635 	oLatencyScrollBar.title = 'The wanted amount of audio pre-buffering in milliseconds, a higher value reduces the chances of audio pops and glitches but increases the latency before you hear the audio.';
636 	oLatencyScrollBar.innerHTML = new Array( 10 +1 ).join( '0123456789' );
637 	
638 	/** Anonymous event handler.
639 	 * 
640 	 *  * @param {Event} e = The event which has been raised.
641 	 * 
642 	 * @private
643 	 * @ignore
644 	 */
645 	oLatencyScrollBar.onscroll = function(e){ weasel.Helper._MenuChangePreBuffer( oBrowserAudio, oStatus, parseInt( this.scrollLeft ) ); };
646 
647 	oList.appendChild( oIntervalWrapper );
648 	oList.appendChild( oPreBufferWrapper );
649 	oList.appendChild( oLatencyScrollBar );
650 	oNested.appendChild( oList );
651 	/** Anonymous event handler.
652 	 * @param {Event} e = The event which has been raised.
653 	 * @private
654 	 * @ignore
655 	 */
656 	oMenuItem.onmouseover = function( e ){ weasel.Helper._MenuUpdatePreBuffer( oBrowserAudio, oStatus, oIntervalRate, oLatencyScrollBar ); };
657 	oMenuItem.textContent = 'Pre-Buffering';
658 	oMenuItem.appendChild( oNested );
659 	oSubMenus.appendChild( oMenuItem );
660 };
661 
662 
663 // ---------------------------------------------------------------------------
664 /** Append the About menu to the sub menu.
665  * 
666  * @param {HTMLUListElement} oSubMenus = The ul HTML Element to append the About menu to.
667  * 
668  * @private
669  */
670 weasel.Helper._subMenuAbout = function( oSubMenus )
671 {
672 	var oMenuItem = document.createElement( 'li' );
673 	var oNested = document.createElement( 'ul' );
674 	var oList = document.createElement( 'li' );
675 	var oAbout = document.createElement( 'div' );
676 	oAbout.id = 'weaselMenuAbout';
677 	oAbout.innerHTML = "W.e.a.s.e.l. audio library.<br />Version " + weasel.LibraryVersionNumber + "<br />by<br />Warren Willmey. <br /><br />WeaselAudioLib.SourceForge.Net<br />License type: GPL Version 3.";
678 
679 	oList.appendChild( oAbout );
680 
681 	oNested.appendChild( oList );
682 
683 	oMenuItem.textContent = 'About';
684 	oMenuItem.appendChild( oNested );
685 	oSubMenus.appendChild( oMenuItem );
686 };
687 
688 // ---------------------------------------------------------------------------
689 /** Add the Easy Audio Menu to the selected element on the page. The Easy Menu
690  * contains the minimum level of audio settings that are considered useful. The 
691  * menu is CSS driven and is of the drop down variety so it not suitable 
692  * for use in the bottom right of screen (top left is preferred).
693  * 
694  * @param {weasel.BrowserAudio} oBrowserAudio = BrowserAudio object that is to 
695  * be attached to the Easy Menu.
696  * @param {Element} oMenuElement = The HTML Element that the Easy Menu will appear 
697  * under.
698  * @param {bool} bAdvancedMenu = Create either the simple or advanced menu (currently un-implemented).
699  */
700 weasel.Helper.addEasyMenu = function( oBrowserAudio, oMenuElement, bAdvancedMenu )
701 {
702 	if( undefined == oMenuElement || undefined == oBrowserAudio || !(oMenuElement instanceof Element) || !(oBrowserAudio instanceof weasel.BrowserAudio)  )
703 	{
704 		return;
705 	}
706 
707 	// Check to see if css classes have already been added, no point adding them twice.
708 	//
709 	if( null == document.getElementById( 'weaselMenuCSS' ) )
710 	{
711 		weasel.Helper._addEasyMenuCSSToPage( document.getElementsByTagName( 'head' )[ 0 ] );
712 	}
713 
714 	if( null != document.getElementById( 'weaselMenu') )
715 	{
716 		// Audio Menu already exists.
717 		//
718 		return;
719 	}
720 
721 
722 	var oMenuFragment = document.createDocumentFragment();
723 	var oUL = document.createElement( 'ul' );
724 	var oLI = document.createElement( 'li' );
725 	oLI.textContent = 'Audio Settings';
726 	var oSubMenus = document.createElement( 'ul' );
727 	weasel.Helper._subMenuInterpolation( oSubMenus, oBrowserAudio );
728 	weasel.Helper._subMenuMasterVolume( oSubMenus, oBrowserAudio );
729 	weasel.Helper._subMenuMixer( oSubMenus, oBrowserAudio );
730 	weasel.Helper._subMenuReplayFrequency( oSubMenus, oBrowserAudio );
731 	weasel.Helper._subMenuPreBuffering( oSubMenus, oBrowserAudio );
732 	weasel.Helper._subMenuAbout( oSubMenus );
733 
734 
735 	oLI.appendChild( oSubMenus );
736 	oUL.className = 'weaselMenu';
737 	oUL.id = 'weaselMenu';
738 	oUL.appendChild( oLI );
739 	oMenuFragment.appendChild( oUL );
740 	oMenuElement.appendChild( oMenuFragment );
741 };
742 
743 
744