(function(){ 'use strict'; var HowlerGlobal=function(){ this.init(); }; HowlerGlobal.prototype={ init: function(){ var self=this || Howler; self._counter=1000; self._html5AudioPool=[]; self.html5PoolSize=10; self._codecs={}; self._howls=[]; self._muted=false; self._volume=1; self._canPlayEvent='canplaythrough'; self._navigator=(typeof window !== 'undefined' && window.navigator) ? window.navigator : null; self.masterGain=null; self.noAudio=false; self.usingWebAudio=true; self.autoSuspend=true; self.ctx=null; self.autoUnlock=true; self._setup(); return self; }, volume: function(vol){ var self=this || Howler; vol=parseFloat(vol); if (!self.ctx){ setupAudioContext(); } if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1){ self._volume=vol; if (self._muted){ return self; } if (self.usingWebAudio){ self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime); } for (var i=0; i= 0; i--){ self._howls[i].unload(); } if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined'){ self.ctx.close(); self.ctx=null; setupAudioContext(); } return self; }, codecs: function(ext){ return (this || Howler)._codecs[ext.replace(/^x-/, '')]; }, _setup: function(){ var test; var self=this || Howler; self.state=self.ctx ? self.ctx.state || 'suspended' : 'suspended'; self._autoSuspend(); if (!self.usingWebAudio){ if (typeof Audio !== 'undefined'){ try { test=new Audio(); if (typeof test.oncanplaythrough === 'undefined'){ self._canPlayEvent='canplay'; } } catch (e){ self.noAudio=true; } } else { self.noAudio=true; } } try { test=new Audio(); if (test.muted){ self.noAudio=true; } } catch (e){} if (!self.noAudio){ self._setupCodecs(); } return self; }, _setupCodecs: function(){ var self=this || Howler; var audioTest=null; try { audioTest=(typeof Audio !== 'undefined') ? new Audio() : null; } catch (err){ return self; } if (!audioTest || typeof audioTest.canPlayType !== 'function'){ return self; } var mpegTest=audioTest.canPlayType('audio/mpeg;').replace(/^no$/, ''); var checkOpera=self._navigator && self._navigator.userAgent.match(/OPR\/([0-6].)/g); var isOldOpera=(checkOpera && parseInt(checkOpera[0].split('/')[1], 10)<33); self._codecs={ mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))), mpeg: !!mpegTest, opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''), ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''), oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''), wav: !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''), aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''), caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''), m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''), webm: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''), dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ''), flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '') }; return self; }, _unlockAudio: function(){ var self=this || Howler; if (self._audioUnlocked || !self.ctx){ return; } self._audioUnlocked=false; self.autoUnlock=false; if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100){ self._mobileUnloaded=true; self.unload(); } self._scratchBuffer=self.ctx.createBuffer(1, 1, 22050); var unlock=function(e){ while (self._html5AudioPool.length0 ? sound._seek : self._sprite[sprite][0]/1000); var duration=Math.max(0, ((self._sprite[sprite][0]+self._sprite[sprite][1])/1000)-seek); var timeout=(duration*1000)/Math.abs(sound._rate); var start=self._sprite[sprite][0]/1000; var stop=(self._sprite[sprite][0]+self._sprite[sprite][1])/1000; sound._sprite=sprite; sound._ended=false; var setParams=function(){ sound._paused=false; sound._seek=seek; sound._start=start; sound._stop=stop; sound._loop=!!(sound._loop || self._sprite[sprite][2]); }; if (seek >= stop){ self._ended(sound); return; } var node=sound._node; if (self._webAudio){ var playWebAudio=function(){ self._playLock=false; setParams(); self._refreshBuffer(sound); var vol=(sound._muted || self._muted) ? 0 : sound._volume; node.gain.setValueAtTime(vol, Howler.ctx.currentTime); sound._playStart=Howler.ctx.currentTime; if (typeof node.bufferSource.start === 'undefined'){ sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration); } else { sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration); } if (timeout !== Infinity){ self._endTimers[sound._id]=setTimeout(self._ended.bind(self, sound), timeout); } if (!internal){ setTimeout(function(){ self._emit('play', sound._id); self._loadQueue(); }, 0); } }; if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted'){ playWebAudio(); } else { self._playLock=true; self.once('resume', playWebAudio); self._clearTimer(sound._id); } } else { var playHtml5=function(){ node.currentTime=seek; node.muted=sound._muted || self._muted || Howler._muted || node.muted; node.volume=sound._volume*Howler.volume(); node.playbackRate=sound._rate; try { var play=node.play(); if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')){ self._playLock=true; setParams(); play .then(function(){ self._playLock=false; node._unlocked=true; if (!internal){ self._emit('play', sound._id); self._loadQueue(); } }) .catch(function(){ self._playLock=false; self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' + 'on mobile devices and Chrome where playback was not within a user interaction.'); sound._ended=true; sound._paused=true; }); } else if (!internal){ self._playLock=false; setParams(); self._emit('play', sound._id); self._loadQueue(); } node.playbackRate=sound._rate; if (node.paused){ self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue '+'on mobile devices and Chrome where playback was not within a user interaction.'); return; } if (sprite !== '__default' || sound._loop){ self._endTimers[sound._id]=setTimeout(self._ended.bind(self, sound), timeout); } else { self._endTimers[sound._id]=function(){ self._ended(sound); node.removeEventListener('ended', self._endTimers[sound._id], false); }; node.addEventListener('ended', self._endTimers[sound._id], false); } } catch (err){ self._emit('playerror', sound._id, err); } }; if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA'){ node.src=self._src; node.load(); } var loadedNoReadyState=(window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS); if (node.readyState >= 3 || loadedNoReadyState){ playHtml5(); } else { self._playLock=true; var listener=function(){ playHtml5(); node.removeEventListener(Howler._canPlayEvent, listener, false); }; node.addEventListener(Howler._canPlayEvent, listener, false); self._clearTimer(sound._id); } } return sound._id; }, pause: function(id){ var self=this; if (self._state !== 'loaded' || self._playLock){ self._queue.push({ event: 'pause', action: function(){ self.pause(id); } }); return self; } var ids=self._getSoundIds(id); for (var i=0; i= 0){ id=parseInt(args[0], 10); } else { vol=parseFloat(args[0]); } } else if (args.length >= 2){ vol=parseFloat(args[0]); id=parseInt(args[1], 10); } var sound; if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1){ if (self._state !== 'loaded' || self._playLock){ self._queue.push({ event: 'volume', action: function(){ self.volume.apply(self, args); } }); return self; } if (typeof id === 'undefined'){ self._volume=vol; } id=self._getSoundIds(id); for (var i=0; i0) ? len/steps : len); var lastTick=Date.now(); sound._fadeTo=to; sound._interval=setInterval(function(){ var tick=(Date.now()-lastTick)/len; lastTick=Date.now(); vol += diff*tick; vol=Math.round(vol*100)/100; if (diff<0){ vol=Math.max(to, vol); } else { vol=Math.min(to, vol); } if (self._webAudio){ sound._volume=vol; } else { self.volume(vol, sound._id, true); } if (isGroup){ self._volume=vol; } if ((tofrom && vol >= to)){ clearInterval(sound._interval); sound._interval=null; sound._fadeTo=null; self.volume(to, sound._id); self._emit('fade', sound._id); } }, stepLen); }, _stopFade: function(id){ var self=this; var sound=self._soundById(id); if (sound && sound._interval){ if (self._webAudio){ sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime); } clearInterval(sound._interval); sound._interval=null; self.volume(sound._fadeTo, id); sound._fadeTo=null; self._emit('fade', id); } return self; }, loop: function(){ var self=this; var args=arguments; var loop, id, sound; if (args.length === 0){ return self._loop; } else if (args.length === 1){ if (typeof args[0] === 'boolean'){ loop=args[0]; self._loop=loop; } else { sound=self._soundById(parseInt(args[0], 10)); return sound ? sound._loop : false; } } else if (args.length === 2){ loop=args[0]; id=parseInt(args[1], 10); } var ids=self._getSoundIds(id); for (var i=0; i= 0){ id=parseInt(args[0], 10); } else { rate=parseFloat(args[0]); } } else if (args.length === 2){ rate=parseFloat(args[0]); id=parseInt(args[1], 10); } var sound; if (typeof rate === 'number'){ if (self._state !== 'loaded' || self._playLock){ self._queue.push({ event: 'rate', action: function(){ self.rate.apply(self, args); } }); return self; } if (typeof id === 'undefined'){ self._rate=rate; } id=self._getSoundIds(id); for (var i=0; i= 0){ id=parseInt(args[0], 10); } else if (self._sounds.length){ id=self._sounds[0]._id; seek=parseFloat(args[0]); } } else if (args.length === 2){ seek=parseFloat(args[0]); id=parseInt(args[1], 10); } if (typeof id === 'undefined'){ return self; } if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)){ self._queue.push({ event: 'seek', action: function(){ self.seek.apply(self, args); } }); return self; } var sound=self._soundById(id); if (sound){ if (typeof seek === 'number' && seek >= 0){ var playing=self.playing(id); if (playing){ self.pause(id, true); } sound._seek=seek; sound._ended=false; self._clearTimer(id); if (!self._webAudio && sound._node && !isNaN(sound._node.duration)){ sound._node.currentTime=seek; } var seekAndEmit=function(){ self._emit('seek', id); if (playing){ self.play(id, true); } }; if (playing && !self._webAudio){ var emitSeek=function(){ if (!self._playLock){ seekAndEmit(); } else { setTimeout(emitSeek, 0); } }; setTimeout(emitSeek, 0); } else { seekAndEmit(); } } else { if (self._webAudio){ var realTime=self.playing(id) ? Howler.ctx.currentTime-sound._playStart : 0; var rateSeek=sound._rateSeek ? sound._rateSeek-sound._seek : 0; return sound._seek+(rateSeek+realTime*Math.abs(sound._rate)); } else { return sound._node.currentTime; } } } return self; }, playing: function(id){ var self=this; if (typeof id === 'number'){ var sound=self._soundById(id); return sound ? !sound._paused : false; } for (var i=0; i= 0){ Howler._howls.splice(index, 1); } var remCache=true; for (i=0; i= 0){ remCache=false; break; } } if (cache && remCache){ delete cache[self._src]; } Howler.noAudio=false; self._state='unloaded'; self._sounds=[]; self=null; return null; }, on: function(event, fn, id, once){ var self=this; var events=self['_on'+event]; if (typeof fn === 'function'){ events.push(once ? { id: id, fn: fn, once: once } : { id: id, fn: fn }); } return self; }, off: function(event, fn, id){ var self=this; var events=self['_on'+event]; var i=0; if (typeof fn === 'number'){ id=fn; fn=null; } if (fn || id){ for (i=0; i= 0; i--){ if (!events[i].id || events[i].id === id || event === 'load'){ setTimeout(function(fn){ fn.call(this, id, msg); }.bind(self, events[i].fn), 0); if (events[i].once){ self.off(event, events[i].fn, events[i].id); } } } self._loadQueue(event); return self; }, _loadQueue: function(event){ var self=this; if (self._queue.length>0){ var task=self._queue[0]; if (task.event === event){ self._queue.shift(); self._loadQueue(); } if (!event){ task.action(); } } return self; }, _ended: function(sound){ var self=this; var sprite=sound._sprite; if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime= 0; i--){ if (cnt <= limit){ return; } if (self._sounds[i]._ended){ if (self._webAudio && self._sounds[i]._node){ self._sounds[i]._node.disconnect(0); } self._sounds.splice(i, 1); cnt--; } } }, _getSoundIds: function(id){ var self=this; if (typeof id === 'undefined'){ var ids=[]; for (var i=0; i= 0; if (Howler._scratchBuffer && node.bufferSource){ node.bufferSource.onended=null; node.bufferSource.disconnect(0); if (isIOS){ try { node.bufferSource.buffer=Howler._scratchBuffer; } catch (e){} } } node.bufferSource=null; return self; }, _clearSound: function(node){ var checkIE=/MSIE |Trident\//.test(Howler._navigator && Howler._navigator.userAgent); if (!checkIE){ node.src='data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA'; } } }; var Sound=function(howl){ this._parent=howl; this.init(); }; Sound.prototype={ init: function(){ var self=this; var parent=self._parent; self._muted=parent._muted; self._loop=parent._loop; self._volume=parent._volume; self._rate=parent._rate; self._seek=0; self._paused=true; self._ended=true; self._sprite='__default'; self._id=++Howler._counter; parent._sounds.push(self); self.create(); return self; }, create: function(){ var self=this; var parent=self._parent; var volume=(Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume; if (parent._webAudio){ self._node=(typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain(); self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime); self._node.paused=true; self._node.connect(Howler.masterGain); } else if (!Howler.noAudio){ self._node=Howler._obtainHtml5Audio(); self._errorFn=self._errorListener.bind(self); self._node.addEventListener('error', self._errorFn, false); self._loadFn=self._loadListener.bind(self); self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false); self._endFn=self._endListener.bind(self); self._node.addEventListener('ended', self._endFn, false); self._node.src=parent._src; self._node.preload=parent._preload === true ? 'auto' : parent._preload; self._node.volume=volume*Howler.volume(); self._node.load(); } return self; }, reset: function(){ var self=this; var parent=self._parent; self._muted=parent._muted; self._loop=parent._loop; self._volume=parent._volume; self._rate=parent._rate; self._seek=0; self._rateSeek=0; self._paused=true; self._ended=true; self._sprite='__default'; self._id=++Howler._counter; return self; }, _errorListener: function(){ var self=this; self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0); self._node.removeEventListener('error', self._errorFn, false); }, _loadListener: function(){ var self=this; var parent=self._parent; parent._duration=Math.ceil(self._node.duration*10)/10; if (Object.keys(parent._sprite).length === 0){ parent._sprite={ __default: [0, parent._duration*1000] }; } if (parent._state !== 'loaded'){ parent._state='loaded'; parent._emit('load'); parent._loadQueue(); } self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false); }, _endListener: function(){ var self=this; var parent=self._parent; if (parent._duration === Infinity){ parent._duration=Math.ceil(self._node.duration*10)/10; if (parent._sprite.__default[1] === Infinity){ parent._sprite.__default[1]=parent._duration*1000; } parent._ended(self); } self._node.removeEventListener('ended', self._endFn, false); } }; var cache={}; var loadBuffer=function(self){ var url=self._src; if (cache[url]){ self._duration=cache[url].duration; loadSound(self); return; } if (/^data:[^;]+;base64,/.test(url)){ var data=atob(url.split(',')[1]); var dataView=new Uint8Array(data.length); for (var i=0; i0){ cache[self._src]=buffer; loadSound(self, buffer); } else { error(); } }; if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1){ Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error); } else { Howler.ctx.decodeAudioData(arraybuffer, success, error); } } var loadSound=function(self, buffer){ if (buffer && !self._duration){ self._duration=buffer.duration; } if (Object.keys(self._sprite).length === 0){ self._sprite={ __default: [0, self._duration*1000] }; } if (self._state !== 'loaded'){ self._state='loaded'; self._emit('load'); self._loadQueue(); } }; var setupAudioContext=function(){ if (!Howler.usingWebAudio){ return; } try { if (typeof AudioContext !== 'undefined'){ Howler.ctx=new AudioContext(); } else if (typeof webkitAudioContext !== 'undefined'){ Howler.ctx=new webkitAudioContext(); } else { Howler.usingWebAudio=false; } } catch (e){ Howler.usingWebAudio=false; } if (!Howler.ctx){ Howler.usingWebAudio=false; } var iOS=(/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform)); var appVersion=Howler._navigator && Howler._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/); var version=appVersion ? parseInt(appVersion[1], 10) : null; if (iOS && version && version<9){ var safari=/safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase()); if (Howler._navigator && !safari){ Howler.usingWebAudio=false; } } if (Howler.usingWebAudio){ Howler.masterGain=(typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain(); Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime); Howler.masterGain.connect(Howler.ctx.destination); } Howler._setup(); }; if (typeof define === 'function' && define.amd){ define([], function(){ return { Howler: Howler, Howl: Howl }; }); } if (typeof exports !== 'undefined'){ exports.Howler=Howler; exports.Howl=Howl; } if (typeof global !== 'undefined'){ global.HowlerGlobal=HowlerGlobal; global.Howler=Howler; global.Howl=Howl; global.Sound=Sound; } else if (typeof window !== 'undefined'){ window.HowlerGlobal=HowlerGlobal; window.Howler=Howler; window.Howl=Howl; window.Sound=Sound; } })(); (function(){ 'use strict'; HowlerGlobal.prototype._pos=[0, 0, 0]; HowlerGlobal.prototype._orientation=[0, 0, -1, 0, 1, 0]; HowlerGlobal.prototype.stereo=function(pan){ var self=this; if (!self.ctx || !self.ctx.listener){ return self; } for (var i=self._howls.length-1; i >= 0; i--){ self._howls[i].stereo(pan); } return self; }; HowlerGlobal.prototype.pos=function(x, y, z){ var self=this; if (!self.ctx || !self.ctx.listener){ return self; } y=(typeof y !== 'number') ? self._pos[1] : y; z=(typeof z !== 'number') ? self._pos[2] : z; if (typeof x === 'number'){ self._pos=[x, y, z]; if (typeof self.ctx.listener.positionX !== 'undefined'){ self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1); self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1); self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1); } else { self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]); } } else { return self._pos; } return self; }; HowlerGlobal.prototype.orientation=function(x, y, z, xUp, yUp, zUp){ var self=this; if (!self.ctx || !self.ctx.listener){ return self; } var or=self._orientation; y=(typeof y !== 'number') ? or[1] : y; z=(typeof z !== 'number') ? or[2] : z; xUp=(typeof xUp !== 'number') ? or[3] : xUp; yUp=(typeof yUp !== 'number') ? or[4] : yUp; zUp=(typeof zUp !== 'number') ? or[5] : zUp; if (typeof x === 'number'){ self._orientation=[x, y, z, xUp, yUp, zUp]; if (typeof self.ctx.listener.forwardX !== 'undefined'){ self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1); self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1); self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1); self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1); self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1); self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1); } else { self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp); } } else { return or; } return self; }; Howl.prototype.init=(function(_super){ return function(o){ var self=this; self._orientation=o.orientation || [1, 0, 0]; self._stereo=o.stereo || null; self._pos=o.pos || null; self._pannerAttr={ coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360, coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360, coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0, distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse', maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000, panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF', refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1, rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1 }; self._onstereo=o.onstereo ? [{ fn: o.onstereo }] : []; self._onpos=o.onpos ? [{ fn: o.onpos }] : []; self._onorientation=o.onorientation ? [{ fn: o.onorientation }] : []; return _super.call(this, o); }; })(Howl.prototype.init); Howl.prototype.stereo=function(pan, id){ var self=this; if (!self._webAudio){ return self; } if (self._state !== 'loaded'){ self._queue.push({ event: 'stereo', action: function(){ self.stereo(pan, id); } }); return self; } var pannerType=(typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo'; if (typeof id === 'undefined'){ if (typeof pan === 'number'){ self._stereo=pan; self._pos=[pan, 0, 0]; } else { return self._stereo; } } var ids=self._getSoundIds(id); for (var i=0; i