File: jzik.js - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

001:         /*
002:                 jZik javascript sampler, by r043v/dph/m2m -- noferov@gmail.com
003:                 under creative commons 3.0 by-nc-sa license -- http://creativecommons.org/licenses/by-nc-sa/3.0/
004:                
005:                 this plugin is dedicated to read audio sprites using html5 audio api
006:                 it take only one source sound file, copy it to create some channels and play inside small part of the long source file
007:                 support delay play and repeat, volume or play rate option, and callback on play, stop and repeat event
008:         */
009: 
010:         function jzik(sources,samples,channels,onInit)
011:         {       var zik = new Object({audio:document.createElement('audio'),source:""});
012:                 if(!zik.audio.canPlayType) return false;
013:                 if(sources.ogg !== undefined) if(!!(zik.audio.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''))) zik.source="ogg";
014:                 if(zik.source == "") if(sources.mp3 !== undefined) if(!!(zik.audio.canPlayType('audio/mpeg;').replace(/no/, ''))) zik.source="mp3";
015:                 if(zik.source == "") if(sources.wav !== undefined) if(!!(zik.audio.canPlayType('audio/wav; codecs="1"').replace(/no/, ''))) zik.source="wav";
016:                 if(zik.source == "") if(sources.aac !== undefined) if(!!(zik.audio.canPlayType('audio/mp4; codecs="mp4a.40.2"').replace(/no/, ''))) zik.source="aac";
017:                 if(zik.source == "") return false;
018: 
019:                 for(n in samples){ var spl = samples[n]; if(spl.end === undefined){ if(spl.size === undefined) return false; spl.end = spl.start + spl.size; } };
020: 
021:                 zik.channelsNb = channels;
022:                 zik.samples = samples;
023:                 zik.channels = [];
024:                 zik.activePlay = [];
025:                 zik.checkTimer = false;
026:                
027:                 zik.audio.src = sources[zik.source]; zik.audio.autobuffer=true; zik.audio.preload='auto'; zik.audio.loop=false; document.body.appendChild(zik.audio);
028:                 zik.callInit = function(){ if(jzikIsFunction(onInit)) onInit.call(zik); };
029:                 zik.channelsLoaded = 1;
030:                
031:                 zik.cloneSampleLoaded = function()
032:                 {       if(this.jzloaded || this.readyState < 4) return; this.jzloaded = true; //this.removeEventListener('canplaythrough',zik.cloneSampleLoaded,false);
033:                         if(++zik.channelsLoaded >= zik.channelsNb) zik.callInit();
034:                 };
035:                
036:                 zik.masterSampleLoaded = function()
037:                 {       if(this.jzloaded || this.readyState < 4) return; this.jzloaded = true; //this.removeEventListener('canplaythrough',zik.masterSampleLoaded,false);
038:                         zik.channels[0] = new Object({isplay:false,isfree:true,audio:zik.audio});
039:                         if(zik.channelsNb == 1) zik.callInit();
040:                           else
041:                         for(var n=1; n < zik.channelsNb; n++)
042:                         {       zik.channels[n] = new Object({isplay:false,isfree:true,audio:zik.audio.cloneNode(true)});
043:                                 var a = zik.channels[n].audio; a.jzloaded = false;
044:                                 a.addEventListener('canplaythrough',zik.cloneSampleLoaded,false);
045:                                 if(window.opera !== undefined) zik.channels[n].audio.load(); // manual load for call event in opera.
046:                         }
047:                 };
048:                
049:                 zik.audio.jzloaded = false;
050:                 zik.audio.addEventListener('canplaythrough',zik.masterSampleLoaded,false);
051:                 zik.play = jzikplay; zik.check = function(){ jzikcheck.call(zik); };
052:                 zik.audio.load(); return zik;
053:         };
054: 
055:         function jzikcheck()
056:         {       var zik = this;
057:                 for(n in zik.activePlay)
058:                 {       var chn = zik.channels[zik.activePlay[n]]; var opt = chn.opt;
059:                         if(chn.isfree || !chn.isplay) continue;
060:                         if(chn.startTime != 0)
061:                         {       var ctime = new Date(); ctime = ctime.getTime();
062:                                 if(chn.startTime <= ctime) { chn.startTime=0; chn.audio.play(); if(jzikIsFunction(opt.onPlay)) opt.onPlay.call(chn); }
063:                         } else {
064:                                 if(chn.audio.currentTime >= chn.stopOffset)
065:                                 {       chn.audio.pause();
066:                                         if(opt.repeat > 0) opt.repeat--;
067:                                         if(opt.repeat != 0)
068:                                         {       chn.audio.currentTime = chn.startOffset; chn.audio.play();
069:                                                 if(jzikIsFunction(opt.onRepeat)) opt.onRepeat.call(chn);
070:                                         } else {
071:                                                 if(jzikIsFunction(opt.onEnd)) opt.onEnd.call(chn);
072:                                                 chn.isplay = false; zik.activePlay.splice(n,1); chn.isfree = true;
073:                                         }
074:                                 }
075:                         }
076:                 }
077:                 if(zik.activePlay.length <= 0) { clearInterval(zik.checkTimer); zik.checkTimer = false; }
078:         };
079:        
080:         function jzikplay(sample, opts)
081:         {       var zik = this;
082:                 var opt = { repeat:0,speed:1,volume:1,delay:0,updateTime:20,onPlay:false,onEnd:false,onRepeat:false }; for(i in opts) opt[i] = opts[i];
083:                 var spl = zik.samples[sample]; if(spl === undefined) return false;
084:                 var nchn = 0; while(nchn < zik.channelsNb && (false === zik.channels[nchn].isfree)) nchn++; if(nchn >= zik.channelsNb) return false;
085:                 var chn = zik.channels[nchn];
086:                 chn.isfree = false;
087:                 chn.opt = opt;
088:                 chn.audio.volume = opt.volume;
089:                 chn.audio.loop = false;
090:                 chn.audio.playbackRate = opt.speed;
091:                 chn.startOffset = spl.start; chn.stopOffset = spl.end; if(chn.stopOffset > chn.audio.duration) chn.stopOffset = chn.audio.duration;
092:                 chn.audio.currentTime = spl.start;
093:                 if(opt.delay)
094:                 {       chn.audio.pause(); // firefox autoplay fix
095:                         var ctime = new Date(); ctime = ctime.getTime();
096:                         chn.startTime = ctime+chn.delay;
097:                 } else { chn.startTime = 0; chn.audio.play(); if(jzikIsFunction(opt.onPlay)) opt.onPlay.call(chn); }
098:                 chn.isplay = true; zik.activePlay.push(nchn);
099:                 if(zik.checkTimer === false) zik.checkTimer = setInterval(zik.check,opt.updateTime);
100:                 return true;
101:         };
102:        
103:         function jzikIsFunction(f){ var getType = {}; return f && getType.toString.call(f) == '[object Function]'; }