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]'; }