diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/music/player.d/main_static.js | 1374 |
1 files changed, 689 insertions, 685 deletions
diff --git a/libs/music/player.d/main_static.js b/libs/music/player.d/main_static.js index f4077bb..fe30cca 100644 --- a/libs/music/player.d/main_static.js +++ b/libs/music/player.d/main_static.js @@ -8,499 +8,500 @@ let NSPlayer=null; let NSUI=null; const sh={ - elem:function(e) - {return document.getElementById(e);}, - newelem:function(e) - {return document.createElement(e);}, - getcookie:function(key) - {return document.cookie.replace(new RegExp('(?:(?:^|.*;\\s*)'+key+'\\s*\\=\\s*([^;]*).*$)|^.*$'),'$1');}, - useFLAC:function() - {return sh.elem('audio').canPlayType('audio/ogg')=='';} + elem:function(e) + {return document.getElementById(e);}, + newelem:function(e) + {return document.createElement(e);}, + getcookie:function(key) + {return document.cookie.replace(new RegExp('(?:(?:^|.*;\\s*)'+key+'\\s*\\=\\s*([^;]*).*$)|^.*$'),'$1');}, + useFLAC:function() + {return sh.elem('audio').canPlayType('audio/ogg')=='';} }; class Ink { - constructor(_vx,_vy,_c) - { - this.x=NSUI.canvas.width/2;this.y=NSUI.canvas.height/2; - this.vx=_vx;this.vy=_vy; - this.color=_c>6?6:_c;this.active=true; - } - update() - { - const canvas=NSUI.canvas; - this.x+=this.vx;this.y+=this.vy; - this.vx*=0.995;this.vy*=0.995; - if(this.x<-10||this.x>canvas.width+10||this.y<-10||this.y>canvas.height+10) - this.active=false; - } - draw(cctx) - { - cctx.drawImage(NSInk.inkimg[this.color],this.x+5*window.devicePixelRatio,this.y+5*window.devicePixelRatio); - } + constructor(_vx,_vy,_c) + { + this.x=NSUI.canvas.width/2;this.y=NSUI.canvas.height/2; + this.vx=_vx;this.vy=_vy; + this.color=_c>6?6:_c;this.active=true; + } + update() + { + const canvas=NSUI.canvas; + this.x+=this.vx;this.y+=this.vy; + this.vx*=0.995;this.vy*=0.995; + if(this.x<-10||this.x>canvas.width+10||this.y<-10||this.y>canvas.height+10) + this.active=false; + } + draw(cctx) + { + cctx.drawImage(NSInk.inkimg[this.color],this.x+5*window.devicePixelRatio,this.y+5*window.devicePixelRatio); + } } NSPlayer={ - plistname:null, - tracks:null, - current:null, - shuffle:0, - repeat:0, - load_playlist:async function(pln,ord) - { - let r=null; - try{ - const resp=await fetch(new Request(`/libs/music/player.d/playlists/${pln}.playlist?${new Date().getTime()}`)); - r=await resp.text(); - }catch(e){return;} - let rarr=r.split('\n'); - let tarr=[]; - const fmt=sh.useFLAC()?'flac':'ogg'; - for(let i=1;i<rarr.length;++i) - { - let t=rarr[i].trim(); - if(!t.length)continue; - let titem={}; - titem.title=t; - titem.ord=i-1; - titem.src=`//filestorage.chrisoft.org/music/${fmt}/${t}.${fmt}`; - tarr.push(titem); - } - return ({plistname:pln,playlist:tarr,plistord:ord}); - }, - play:function(id) - { - if(!this.plistname)return; - window.history.replaceState('','The Stupid Online Player', - `#${encodeURIComponent(this.plistname)}/${encodeURIComponent(this.tracks[id].title)}`); - NSUI.iplaypause.style.backgroundPosition=`${NSUI.bpauserect}`; - this.current=id; - NSUI.lbnowplaying.innerHTML=`Now Playing: ${this.tracks[id].title}`; - if(navigator.mediaSession) - navigator.mediaSession.metadata=new MediaMetadata({title:this.tracks[id].title,album:this.plistname}); - NSUI.set_highlighted(this.plistname,this.tracks[id].title); - NSUI.audio.src=this.tracks[id].src; - NSUI.audio.load(); - NSUI.audio.play(); - }, - next:function() - { - this.current=(this.current+1)%this.tracks.length; - if(this.current==0&&this.shuffle) - NSUI.switch_playlist(this.plistname); - this.play(this.current); - }, - prev:function() - { - this.current=(this.current-1+this.tracks.length)%this.tracks.length; - this.play(this.current); - }, - switch_playlist:function(plistname,plist) - { - this.plistname=plistname; - this.tracks=plist; - }, - sort_playlist:function(shuffle,plist) - { - const tarr=plist?plist:this.tracks; - if(!tarr)return; - if(shuffle) - for(let i=0;i<tarr.length;++i) - tarr[i].sord=Math.random()*tarr.length; - tarr.sort( - (a,b)=>{ - const ra=shuffle?a.sord:a.ord; - const rb=shuffle?b.sord:b.ord; - return ra<rb?-1:1; - } - ); - if(plist)plist=tarr;else this.tracks=tarr; - } + plistname:null, + tracks:null, + current:null, + shuffle:0, + repeat:0, + load_playlist:async function(pln,ord) + { + let r=null; + try{ + const resp=await fetch(new Request(`/libs/music/player.d/playlists/${pln}.playlist?${new Date().getTime()}`)); + r=await resp.text(); + }catch(e){return;} + let rarr=r.split('\n'); + let tarr=[]; + const fmt=sh.useFLAC()?'flac':'ogg'; + for(let i=1;i<rarr.length;++i) + { + let t=rarr[i].trim(); + if(!t.length)continue; + let titem={}; + titem.title=t; + titem.ord=i-1; + titem.src=`//filestorage.chrisoft.org/music/${fmt}/${t}.${fmt}`; + tarr.push(titem); + } + return ({plistname:pln,playlist:tarr,plistord:ord}); + }, + play:function(id) + { + if(!this.plistname)return; + window.history.replaceState('','The Stupid Online Player', + `#${encodeURIComponent(this.plistname)}/${encodeURIComponent(this.tracks[id].title)}`); + NSUI.iplaypause.style.backgroundPosition=`${NSUI.bpauserect}`; + this.current=id; + NSUI.lbnowplaying.innerHTML=`Now Playing: ${this.tracks[id].title}`; + if(navigator.mediaSession) + navigator.mediaSession.metadata=new MediaMetadata({title:this.tracks[id].title,album:this.plistname}); + NSUI.set_highlighted(this.plistname,this.tracks[id].title); + NSUI.audio.src=this.tracks[id].src; + NSUI.audio.load(); + NSUI.audio.play(); + }, + next:function() + { + this.current=(this.current+1)%this.tracks.length; + if(this.current==0&&this.shuffle) + NSUI.switch_playlist(this.plistname); + this.play(this.current); + }, + prev:function() + { + this.current=(this.current-1+this.tracks.length)%this.tracks.length; + this.play(this.current); + }, + switch_playlist:function(plistname,plist) + { + this.plistname=plistname; + this.tracks=plist; + }, + sort_playlist:function(shuffle,plist) + { + const tarr=plist?plist:this.tracks; + if(!tarr)return; + if(shuffle) + for(let i=0;i<tarr.length;++i) + tarr[i].sord=Math.random()*tarr.length; + tarr.sort( + (a,b)=>{ + const ra=shuffle?a.sord:a.ord; + const rb=shuffle?b.sord:b.ord; + return ra<rb?-1:1; + } + ); + if(plist)plist=tarr;else this.tracks=tarr; + } }; NSUI={ - playlist:null, - audio:null, - canvas:null, - iplaypause:null, - irepeat:null, - ishuffle:null, - lbnowplaying:null, - playlists:null, - ulplaylists:null, - swplaylist:null, - selectedplist:null, - vissel:null, - pbnext:null, - pbprev:null, - ctrlcontainer:null, - am3u8:null, - bplayrect:"0 -48px", - bpauserect:"-24px -48px", - brallrect:"-24px -24px", - brnonrect:"-48px -24px", - bronerect:"0 0", - bsoffrect:"-24px 0", - bshonrect:"-48px 0", - plistshown:true, - setup_ui:function() - { - window.devicePixelRatio=window.devicePixelRatio?window.devicePixelRatio:1; - window.onresize=function() - { - if(window.innerWidth<768) - setupevents(); - else unsetevents(); - }; - window.onresize(); - this.playlist=sh.elem('playlist'); - this.swplaylist=sh.elem('plistsw'); - this.audio=sh.elem('audio'); - this.canvas=sh.elem('cvs'); - this.iplaypause=sh.elem('imgplaypause'); - this.irepeat=sh.elem('imgrepeat'); - this.ishuffle=sh.elem('imgshuffle'); - this.lbnowplaying=sh.elem('nowplaying'); - this.ulplaylists=sh.elem('plists'); - this.vissel=sh.elem('visualizationsel'); - this.pbnext=sh.elem('pbnext'); - this.pbprev=sh.elem('pbprev'); - this.ctrlcontainer=sh.elem('ctrlcontainer'); - this.am3u8=sh.elem('am3u8'); - NSUI.canvas.width=NSUI.canvas.clientWidth*window.devicePixelRatio; - NSUI.canvas.height=NSUI.canvas.clientHeight*window.devicePixelRatio; - NSUI.vissel.onchange=function(){ - if(this.value!='none'&&this.oldvalue=='none')requestAnimationFrame(NSVisualization.updateVisualization); - else NSUI.canvas.getContext('2d').clearRect(0,0,NSUI.canvas.width,NSUI.canvas.height); - document.cookie='playervisualization='+this.value; - this.oldvalue=this.value; - }; - document.getElementById('shufflesw').onclick=function(){ - NSUI.shuffle_switch(NSPlayer.shuffle=1-NSPlayer.shuffle); - NSUI.ishuffle.style.backgroundPosition=`${NSPlayer.shuffle?NSUI.bshonrect:NSUI.bsoffrect}`; - document.cookie=`playershuffle=${NSPlayer.shuffle}`; - }; - document.getElementById('repeatsw').onclick=function(){ - NSPlayer.repeat=1-NSPlayer.repeat; - NSUI.audio.loop=NSPlayer.repeat?true:false; - NSUI.irepeat.style.backgroundPosition=`${NSPlayer.repeat?NSUI.bronerect:NSUI.brallrect}`; - document.cookie=`playerrepeat=${NSPlayer.repeat}`; - }; - document.getElementById('plistsw').onclick=NSUI.togglePlist; - document.getElementById('tsliderbase').onclick= - document.getElementById('tsliderbase').onmousemove=function(e) - { - if(e.type=='click'||(e.type=='mousemove'&&e.buttons==1)) - { - const sr=this.getBoundingClientRect(); - const p=(e.clientX-sr.left)/sr.width; - NSUI.audio.currentTime=NSUI.audio.duration*p; - } - }; - const playpausef=function() - { - if(NSUI.audio.src=='') - { - if(NSUI.selectedplist) - { - NSUI.switch_playlist(NSUI.selectedplist); - NSUI.switch_track(0); - } - return; - } - if(NSUI.audio.paused) - { - NSUI.audio.play(); - NSUI.iplaypause.style.backgroundPosition=`${NSUI.bpauserect}`; - } - else - { - NSUI.audio.pause(); - NSUI.iplaypause.style.backgroundPosition=`${NSUI.bplayrect}`; - } - }; - NSUI.iplaypause.onclick=playpausef; - NSUI.pbprev.onclick=function() - { - if(NSUI.audio.currentTime>10)NSUI.audio.currentTime=0; - else NSPlayer.prev(); - }; - NSUI.pbnext.onclick=NSPlayer.next.bind(NSPlayer); - if(navigator.mediaSession) - { - navigator.mediaSession.setActionHandler('previoustrack',NSUI.pbprev.onclick); - navigator.mediaSession.setActionHandler('nexttrack',NSUI.pbnext.onclick); - } - window.onkeydown=function(e) - { - if(e.key==' ') - { - playpausef(); - return false; - } - if(e.key=='c') - if(NSUI.audio.audioTracks.length==2) - { - const t=NSUI.audio.currentTime; - NSUI.audio.audioTracks[0].enabled^=1; - NSUI.audio.audioTracks[1].enabled^=1; - NSUI.audio.currentTime=t; - } - return true; - }; - }, - load_playlists:async function() - { - const moi=this; - let r=null; - try{ - const resp=await fetch(new Request(`/libs/music/player.d/playlists/playlists?${new Date().getTime()}`)); - r=await resp.text(); - }catch(e){return;} - let rarr=r.split('\n'); - let tarr=[]; - let cnt=0; - for(let i=0;i<rarr.length;++i) - if(rarr[i].trim().length)++cnt; - const p=new Promise((a,b)=>{ - for(let i=0;i<rarr.length;++i) - { - let t=rarr[i].trim(); - if(!t.length)continue; - NSPlayer.load_playlist(t,i).then((rp)=>{ - tarr[rp.plistord]=rp; - if(--cnt<=0)a(null); - }); - } - }); - await p; - for(let i=0;i<tarr.length;++i) - { - const e=sh.newelem('li'); - const ea=sh.newelem('a'); - ea.innerHTML=tarr[i].plistname; - ea.classList.add('listitem'); - ea.href='javascript:void(0);'; - ea.pid=i; - ea.onclick=function(e){ - e.preventDefault(); - for(let i=0;i<NSUI.ulplaylists.childNodes.length;++i) - { - const ta=NSUI.ulplaylists.childNodes[i].firstChild; - if(ta.pid==this.pid) - {ta.classList.add('highlighted');ta.classList.add('active');} - else{ta.classList.remove('highlighted');ta.classList.remove('active');} - } - NSUI.present_playlist.bind(NSUI,this.pid)(); - if(NSPlayer.current) - NSUI.set_highlighted(NSPlayer.plistname,NSPlayer.tracks[NSPlayer.current].title); - }; - e.appendChild(ea); - NSUI.ulplaylists.appendChild(e); - } - moi.playlists=tarr; - }, - present_playlist:function(id) - { - while(this.playlist.firstChild) - this.playlist.removeChild(this.playlist.firstChild); - const list=this.playlists[id].playlist; - for(let i=0;i<list.length;++i) - { - const l=sh.newelem('li'); - const a=sh.newelem('a'); - a.innerHTML=list[i].title; - a.href=list[i].src; - a.ord=i; - a.onclick=function(e){e.preventDefault();NSUI.switch_track.bind(NSUI,this.ord)();}; - l.appendChild(a); - this.playlist.appendChild(l); - } - const d=sh.newelem('div');d.style.height=`${NSUI.ctrlcontainer.getBoundingClientRect().height+16}px`; - this.playlist.appendChild(d); - this.selectedplist=this.playlists[id].plistname; - this.am3u8.href=`https://chrisoft.org/libs/music/player.d/cgi-bin/m3u8.cgi?plist=${this.playlists[id].plistname}`; - }, - switch_playlist:function(pl,setactive) - { - let cid=0; - for(;cid<this.playlists.length;++cid) - if(this.playlists[cid].plistname==pl)break; - if(cid>=this.playlists.length)return; - if(setactive) - { - NSUI.ulplaylists.childNodes[cid].firstChild.classList.add('highlighted'); - NSUI.ulplaylists.childNodes[cid].firstChild.classList.add('active'); - } - //VERY stupid design, but it _should_ work. - NSPlayer.switch_playlist(pl,this.playlists[cid].playlist); - NSPlayer.sort_playlist(NSPlayer.shuffle); - this.playlists[cid].playlist=NSPlayer.tracks; - this.present_playlist(cid); - this.selectedplist=pl; - }, - switch_track:function(id) - { - if(NSPlayer.plistname!=this.selectedplist) - this.switch_playlist(this.selectedplist); - NSPlayer.play(id); - }, - set_highlighted:function(pl,t) - { - if(pl!=this.selectedplist)return; - let cid=0; - for(;cid<this.playlists.length;++cid) - if(this.playlists[cid].plistname==pl)break; - const clist=this.playlists[cid].playlist; - for(let i=0;i<clist.length;++i) - if(clist[i].title==t) - this.playlist.childNodes[i].firstChild.classList.add('highlighted'); - else - this.playlist.childNodes[i].firstChild.classList.remove('highlighted'); - }, - shuffle_switch:function(shuffle) - { - for(let i=0;i<this.playlists.length;++i) - { - NSPlayer.sort_playlist(shuffle,this.playlists[i].playlist); - if(i==this.selectedplist)this.present_playlist(i); - } - NSPlayer.sort_playlist(shuffle); - }, - togglePlist:function() - { - NSUI.plistshown=!NSUI.plistshown; - NSUI.swplaylist.innerHTML=`[${NSUI.plistshown?'Hide':'Show'} Playlist]`; - NSUI.playlist.style.opacity=NSUI.plistshown?'1':'0'; - NSUI.playlist.style.pointerEvents=NSUI.plistshown?'auto':'none'; - }, - formatTime:function(t) - { - if(isNaN(t))return '-:--'; - let m=Math.floor(t/60),s=Math.round(t-Math.floor(t/60)*60); - if(s<10)return `${m}:0${s}`; - else if(s==60)return `${m+1}:00`; - else return `${m}:${s}`; - }, - bufferedUpdate:function() - { - let r=0; - for(let i=0;i<NSUI.audio.buffered.length;++i) - r=r<NSUI.audio.buffered.end(i)?NSUI.audio.buffered.end(i):r; - document.getElementById('cbuff').style.width=r/NSUI.audio.duration*100+'%'; - }, - timeUpdate:function() - { - document.getElementById('timenow').innerHTML=NSUI.formatTime(NSUI.audio.currentTime); - document.getElementById('timeleft').innerHTML=`-${NSUI.formatTime(NSUI.audio.duration-NSUI.audio.currentTime)}`; - document.getElementById('ctime').style.width=NSUI.audio.currentTime/NSUI.audio.duration*100+'%'; - NSUI.bufferedUpdate(); - } + playlist:null, + audio:null, + canvas:null, + iplaypause:null, + irepeat:null, + ishuffle:null, + lbnowplaying:null, + playlists:null, + ulplaylists:null, + swplaylist:null, + selectedplist:null, + vissel:null, + pbnext:null, + pbprev:null, + ctrlcontainer:null, + am3u8:null, + bplayrect:"0 -48px", + bpauserect:"-24px -48px", + brallrect:"-24px -24px", + brnonrect:"-48px -24px", + bronerect:"0 0", + bsoffrect:"-24px 0", + bshonrect:"-48px 0", + plistshown:true, + setup_ui:function() + { + window.devicePixelRatio=window.devicePixelRatio?window.devicePixelRatio:1; + window.onresize=function() + { + if(window.innerWidth<768) + setupevents(); + else unsetevents(); + }; + window.onresize(); + this.playlist=sh.elem('playlist'); + this.swplaylist=sh.elem('plistsw'); + this.audio=sh.elem('audio'); + this.canvas=sh.elem('cvs'); + this.iplaypause=sh.elem('imgplaypause'); + this.irepeat=sh.elem('imgrepeat'); + this.ishuffle=sh.elem('imgshuffle'); + this.lbnowplaying=sh.elem('nowplaying'); + this.ulplaylists=sh.elem('plists'); + this.vissel=sh.elem('visualizationsel'); + this.pbnext=sh.elem('pbnext'); + this.pbprev=sh.elem('pbprev'); + this.ctrlcontainer=sh.elem('ctrlcontainer'); + this.am3u8=sh.elem('am3u8'); + NSUI.canvas.width=NSUI.canvas.clientWidth*window.devicePixelRatio; + NSUI.canvas.height=NSUI.canvas.clientHeight*window.devicePixelRatio; + NSUI.vissel.onchange=function(){ + if(this.value!='none'&&this.oldvalue=='none')requestAnimationFrame(NSVisualization.updateVisualization); + else NSUI.canvas.getContext('2d').clearRect(0,0,NSUI.canvas.width,NSUI.canvas.height); + document.cookie='playervisualization='+this.value; + this.oldvalue=this.value; + }; + document.getElementById('shufflesw').onclick=function(){ + NSUI.shuffle_switch(NSPlayer.shuffle=1-NSPlayer.shuffle); + NSUI.ishuffle.style.backgroundPosition=`${NSPlayer.shuffle?NSUI.bshonrect:NSUI.bsoffrect}`; + document.cookie=`playershuffle=${NSPlayer.shuffle}`; + }; + document.getElementById('repeatsw').onclick=function(){ + NSPlayer.repeat=1-NSPlayer.repeat; + NSUI.audio.loop=NSPlayer.repeat?true:false; + NSUI.irepeat.style.backgroundPosition=`${NSPlayer.repeat?NSUI.bronerect:NSUI.brallrect}`; + document.cookie=`playerrepeat=${NSPlayer.repeat}`; + }; + document.getElementById('plistsw').onclick=NSUI.togglePlist; + document.getElementById('tsliderbase').onclick= + document.getElementById('tsliderbase').onmousemove=function(e) + { + if(e.type=='click'||(e.type=='mousemove'&&e.buttons==1)) + { + const sr=this.getBoundingClientRect(); + const p=(e.clientX-sr.left)/sr.width; + NSUI.audio.currentTime=NSUI.audio.duration*p; + } + }; + const playpausef=function() + { + if(NSUI.audio.src=='') + { + if(NSUI.selectedplist) + { + NSUI.switch_playlist(NSUI.selectedplist); + NSUI.switch_track(0); + } + return; + } + if(NSUI.audio.paused) + { + NSUI.audio.play(); + NSUI.iplaypause.style.backgroundPosition=`${NSUI.bpauserect}`; + } + else + { + NSUI.audio.pause(); + NSUI.iplaypause.style.backgroundPosition=`${NSUI.bplayrect}`; + } + }; + NSUI.iplaypause.onclick=playpausef; + NSUI.pbprev.onclick=function() + { + if(NSUI.audio.currentTime>10)NSUI.audio.currentTime=0; + else NSPlayer.prev(); + }; + NSUI.pbnext.onclick=NSPlayer.next.bind(NSPlayer); + if(navigator.mediaSession) + { + navigator.mediaSession.setActionHandler('previoustrack',NSUI.pbprev.onclick); + navigator.mediaSession.setActionHandler('nexttrack',NSUI.pbnext.onclick); + } + window.onkeydown=function(e) + { + if(e.key==' ') + { + playpausef(); + return false; + } + if(e.key=='c') + if(NSUI.audio.audioTracks.length==2) + { + const t=NSUI.audio.currentTime; + NSUI.audio.audioTracks[0].enabled^=1; + NSUI.audio.audioTracks[1].enabled^=1; + NSUI.audio.currentTime=t; + } + return true; + }; + }, + load_playlists:async function() + { + const moi=this; + let r=null; + try{ + const resp=await fetch(new Request(`/libs/music/player.d/playlists/playlists?${new Date().getTime()}`)); + r=await resp.text(); + }catch(e){return;} + let rarr=r.split('\n'); + let tarr=[]; + let cnt=0; + for(let i=0;i<rarr.length;++i) + if(rarr[i].trim().length)++cnt; + const p=new Promise((a,b)=>{ + for(let i=0;i<rarr.length;++i) + { + let t=rarr[i].trim(); + if(!t.length)continue; + NSPlayer.load_playlist(t,i).then((rp)=>{ + tarr[rp.plistord]=rp; + if(--cnt<=0)a(null); + }); + } + }); + await p; + for(let i=0;i<tarr.length;++i) + { + const e=sh.newelem('li'); + const ea=sh.newelem('a'); + ea.innerHTML=tarr[i].plistname; + ea.classList.add('listitem'); + ea.href='javascript:void(0);'; + ea.pid=i; + ea.onclick=function(e){ + e.preventDefault(); + for(let i=0;i<NSUI.ulplaylists.childNodes.length;++i) + { + const ta=NSUI.ulplaylists.childNodes[i].firstChild; + if(ta.pid==this.pid) + {ta.classList.add('highlighted');ta.classList.add('active');} + else{ta.classList.remove('highlighted');ta.classList.remove('active');} + } + NSUI.present_playlist.bind(NSUI,this.pid)(); + if(NSPlayer.current) + NSUI.set_highlighted(NSPlayer.plistname,NSPlayer.tracks[NSPlayer.current].title); + }; + e.appendChild(ea); + NSUI.ulplaylists.appendChild(e); + } + moi.playlists=tarr; + }, + present_playlist:function(id) + { + while(this.playlist.firstChild) + this.playlist.removeChild(this.playlist.firstChild); + const list=this.playlists[id].playlist; + for(let i=0;i<list.length;++i) + { + const l=sh.newelem('li'); + const a=sh.newelem('a'); + a.innerHTML=list[i].title; + a.href=list[i].src; + a.ord=i; + a.onclick=function(e){e.preventDefault();NSUI.switch_track.bind(NSUI,this.ord)();}; + l.appendChild(a); + this.playlist.appendChild(l); + } + const d=sh.newelem('div');d.style.height=`${NSUI.ctrlcontainer.getBoundingClientRect().height+16}px`; + this.playlist.appendChild(d); + this.selectedplist=this.playlists[id].plistname; + this.am3u8.href=`https://chrisoft.org/libs/music/player.d/cgi-bin/m3u8.cgi?plist=${this.playlists[id].plistname}`; + }, + switch_playlist:function(pl,setactive) + { + let cid=0; + for(;cid<this.playlists.length;++cid) + if(this.playlists[cid].plistname==pl)break; + if(cid>=this.playlists.length)return; + if(setactive) + { + NSUI.ulplaylists.childNodes[cid].firstChild.classList.add('highlighted'); + NSUI.ulplaylists.childNodes[cid].firstChild.classList.add('active'); + } + //VERY stupid design, but it _should_ work. + NSPlayer.switch_playlist(pl,this.playlists[cid].playlist); + NSPlayer.sort_playlist(NSPlayer.shuffle); + this.playlists[cid].playlist=NSPlayer.tracks; + this.present_playlist(cid); + this.selectedplist=pl; + }, + switch_track:function(id) + { + if(NSPlayer.plistname!=this.selectedplist) + this.switch_playlist(this.selectedplist); + NSPlayer.play(id); + }, + set_highlighted:function(pl,t) + { + if(pl!=this.selectedplist)return; + let cid=0; + for(;cid<this.playlists.length;++cid) + if(this.playlists[cid].plistname==pl)break; + const clist=this.playlists[cid].playlist; + for(let i=0;i<clist.length;++i) + if(clist[i].title==t) + this.playlist.childNodes[i].firstChild.classList.add('highlighted'); + else + this.playlist.childNodes[i].firstChild.classList.remove('highlighted'); + }, + shuffle_switch:function(shuffle) + { + for(let i=0;i<this.playlists.length;++i) + { + NSPlayer.sort_playlist(shuffle,this.playlists[i].playlist); + if(i==this.selectedplist)this.present_playlist(i); + } + NSPlayer.sort_playlist(shuffle); + }, + togglePlist:function() + { + NSUI.plistshown=!NSUI.plistshown; + NSUI.swplaylist.innerHTML=`[${NSUI.plistshown?'Hide':'Show'} Playlist]`; + NSUI.playlist.style.opacity=NSUI.plistshown?'1':'0'; + NSUI.playlist.style.pointerEvents=NSUI.plistshown?'auto':'none'; + }, + formatTime:function(t) + { + if(isNaN(t))return '-:--'; + let m=Math.floor(t/60),s=Math.round(t-Math.floor(t/60)*60); + if(s<10)return `${m}:0${s}`; + else if(s==60)return `${m+1}:00`; + else return `${m}:${s}`; + }, + bufferedUpdate:function() + { + let r=0; + for(let i=0;i<NSUI.audio.buffered.length;++i) + r=r<NSUI.audio.buffered.end(i)?NSUI.audio.buffered.end(i):r; + document.getElementById('cbuff').style.width=r/NSUI.audio.duration*100+'%'; + }, + timeUpdate:function() + { + document.getElementById('timenow').innerHTML=NSUI.formatTime(NSUI.audio.currentTime); + document.getElementById('timeleft').innerHTML=`-${NSUI.formatTime(NSUI.audio.duration-NSUI.audio.currentTime)}`; + document.getElementById('ctime').style.width=NSUI.audio.currentTime/NSUI.audio.duration*100+'%'; + NSUI.bufferedUpdate(); + } }; NSAudio={ - audioctx:null, - srcnode:null, - anlznode:null, - audioInit:function() - { - window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext; - if(!window.AudioContext)alert('This page requires Web Audio API to work...'); - this.audioctx=new AudioContext; - this.anlznode=this.audioctx.createAnalyser(); - this.anlznode.fftSize=2*NSVisualization.nbins; - NSUI.audio.volume=1; - }, - connect:function() - { - this.srcnode=this.audioctx.createMediaElementSource(NSUI.audio); - this.srcnode.connect(this.anlznode); - this.anlznode.connect(this.audioctx.destination); - }, + audioctx:null, + srcnode:null, + anlznode:null, + audioInit:function() + { + window.AudioContext=window.AudioContext||window.webkitAudioContext||window.mozAudioContext||window.msAudioContext; + if(!window.AudioContext)alert('This page requires Web Audio API to work...'); + this.audioctx=new AudioContext; + this.anlznode=this.audioctx.createAnalyser(); + this.anlznode.fftSize=2*NSVisualization.nbins; + NSUI.audio.volume=1; + }, + connect:function() + { + this.srcnode=this.audioctx.createMediaElementSource(NSUI.audio); + this.srcnode.connect(this.anlznode); + this.anlznode.connect(this.audioctx.destination); + }, }; NSVisualization={ - nbinsp:10, - nbins:Math.pow(2,10), - spectgrmw:1200, - spectrw:0.7, - spectrm:0.08125, - caps:[], - cctx:null, - spectgrmp:0, - _61spbins:29, - _61spfintv:Math.pow(1024,1./29), - _61spbinw:9, - _61spaccel:.35, - _61spmaxvel:6.17274873, - _61spgvel:.025, - _61spelas:1.33*.617274873, - _61spf:6.17274873, - _61spelasth:.017274873, - _61spcaps:new Float32Array(29), - _61spcapsv:new Float32Array(29), + nbinsp:10, + nbins:Math.pow(2,10), + spectgrmw:1200, + spectrw:0.7, + spectrm:0.08125, + caps:[], + cctx:null, + spectgrmp:0, + _61spbins:29, + _61spfintv:Math.pow(1024,1./29), + _61spbinw:9, + _61spaccel:.617274873, + _61spdamp:Math.pow(.617274873,6.17274873), + _61spvelcap:2*6.17274873, + _61spgvel:.025, + _61spelas:.617274873, + _61spf:6.17274873*6.17274873, + _61spelasth:.017274873, + _61spcaps:new Float32Array(29), + _61spcapsv:new Float32Array(29), _61spft:new Date(), - init:function() - { - window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame; - this.cctx=NSUI.canvas.getContext('2d'); - this.spectrw=NSUI.canvas.width/this.nbins; - this.spectrm=this.spectrw/10;this.spectrw*=0.9; - for(let i=0;i<this.nbins;++i)this.caps[i]=0; - }, - update_spectrum:function() - { - const cctx=this.cctx,canvas=NSUI.canvas; - cctx.clearRect(0,0,canvas.width,canvas.height); - try{ - let freqdomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); - NSAudio.anlznode.getByteFrequencyData(freqdomv); - for(let i=0;i<this.nbins;++i) - { - cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,50%)'; - cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-(canvas.height*freqdomv[i]/255.),this.spectrw,canvas.height*freqdomv[i]/255.); - if(this.caps[i]<freqdomv[i])this.caps[i]=freqdomv[i];else if(this.caps[i]>0)--this.caps[i]; - cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,25%)'; - cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-(canvas.height*this.caps[i]/255.)-1,this.spectrw,1); - } - }catch(e){ - for(let i=0;i<this.nbins;++i) - { - if(this.caps[i]>0)--this.caps[i]; - cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,25%)'; - cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-this.caps[i]-1,this.spectrw,1); - } - } - }, - update_61_spectrum:function() - { - const cctx=this.cctx,canvas=NSUI.canvas; - cctx.clearRect(0,0,canvas.width,canvas.height); - try{ - let freqdomv=new Float32Array(NSAudio.anlznode.frequencyBinCount); - NSAudio.anlznode.getFloatFrequencyData(freqdomv); - let binl=Math.pow(2,(this._61spbinw-1)*this.nbinsp/(this._61spbins-1+this._61spbinw))-1; - let _61spfdomv=new Float32Array(this._61spbins); + init:function() + { + window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame; + this.cctx=NSUI.canvas.getContext('2d'); + this.spectrw=NSUI.canvas.width/this.nbins; + this.spectrm=this.spectrw/10;this.spectrw*=0.9; + for(let i=0;i<this.nbins;++i)this.caps[i]=0; + }, + update_spectrum:function() + { + const cctx=this.cctx,canvas=NSUI.canvas; + cctx.clearRect(0,0,canvas.width,canvas.height); + try{ + let freqdomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); + NSAudio.anlznode.getByteFrequencyData(freqdomv); + for(let i=0;i<this.nbins;++i) + { + cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,50%)'; + cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-(canvas.height*freqdomv[i]/255.),this.spectrw,canvas.height*freqdomv[i]/255.); + if(this.caps[i]<freqdomv[i])this.caps[i]=freqdomv[i];else if(this.caps[i]>0)--this.caps[i]; + cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,25%)'; + cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-(canvas.height*this.caps[i]/255.)-1,this.spectrw,1); + } + }catch(e){ + for(let i=0;i<this.nbins;++i) + { + if(this.caps[i]>0)--this.caps[i]; + cctx.fillStyle='hsl('+i*360.0/this.nbins+',100%,25%)'; + cctx.fillRect(i*(this.spectrw+this.spectrm),canvas.height-this.caps[i]-1,this.spectrw,1); + } + } + }, + update_61_spectrum:function() + { + const cctx=this.cctx,canvas=NSUI.canvas; + cctx.clearRect(0,0,canvas.width,canvas.height); + try{ + let freqdomv=new Float32Array(NSAudio.anlznode.frequencyBinCount); + NSAudio.anlznode.getFloatFrequencyData(freqdomv); + let binl=Math.pow(2,(this._61spbinw-1)*this.nbinsp/(this._61spbins-1+this._61spbinw))-1; + let _61spfdomv=new Float32Array(this._61spbins); const ft=new Date()-this._61spft; this._61spft=new Date(); const rft=ft/1000*24; - for(let i=0;i<this._61spbins;++i) - { - let binr=Math.pow(2,(i+this._61spbinw)*this.nbinsp/(this._61spbins-1+this._61spbinw))-1; - if(Math.floor(binr)<=Math.floor(binl))binr=binl+1; + for(let i=0;i<this._61spbins;++i) + { + let binr=Math.pow(2,(i+this._61spbinw)*this.nbinsp/(this._61spbins-1+this._61spbinw))-1; + if(Math.floor(binr)<=Math.floor(binl))binr=binl+1; let binli=Math.floor(binl); let binri=Math.floor(binr); const clamp=(x)=>Math.max(0,Math.min(1,x)); - _61spfdomv[i]=Math.pow(freqdomv. - slice(binli,binri+1). - reduce( + _61spfdomv[i]=Math.pow(freqdomv. + slice(binli,binri+1). + reduce( (s,c)=>s+ clamp( (c-NSAudio.anlznode.minDecibels) /(NSAudio.anlznode.maxDecibels-NSAudio.anlznode.minDecibels) )/(binri-binli+1) ,0),2);//iS tHiS dBv^2? - binl=binr; + binl=binr; if(ft>1000) { @@ -508,235 +509,238 @@ NSVisualization={ this._61spcapsv[i]=0; continue; } - let vel=this._61spgvel*this._61spcapsv[i]; - if(this._61spcaps[i]-vel*rft<=_61spfdomv[i]) - { - let elf=0; - if(vel>rft*this._61spelasth) - elf=this._61spcapsv[i]*this._61spelas; - this._61spcapsv[i]=(this._61spcaps[i]-vel*rft-_61spfdomv[i])*this._61spf-elf; - this._61spcaps[i]=_61spfdomv[i]; - } - else - { - if(this._61spcapsv[i]+rft*this._61spaccel<=this._61spmaxvel) - this._61spcapsv[i]+=rft*this._61spaccel; - else this._61spcapsv[i]=this._61spmaxvel; + let vel=this._61spgvel*this._61spcapsv[i]; + if(this._61spcaps[i]-vel*rft<=_61spfdomv[i]) + { + let elf=0; + if(vel>this._61spgvel*this._61spvelcap) + { + vel=this._61spgvel*this._61spvelcap;//cap this so that Newton could rest in peace. + this._61spcapsv[i]=this._61spvelcap; + } + if(vel>rft*this._61spelasth) + elf=this._61spcapsv[i]*this._61spelas; + this._61spcapsv[i]=(this._61spcaps[i]-vel*rft-_61spfdomv[i])*this._61spf-elf; + this._61spcaps[i]=_61spfdomv[i]; + } + else + { + this._61spcapsv[i]+=rft*(this._61spaccel-this._61spdamp*Math.sign(this._61spcapsv[i])*Math.pow(this._61spcapsv[i],2)); vel=this._61spgvel*this._61spcapsv[i]; - this._61spcaps[i]-=Math.min(rft*vel,this._61spcaps[i]); - } + this._61spcaps[i]-=Math.min(rft*vel,this._61spcaps[i]); + } - cctx.fillStyle=`rgba(70,130,180,${0.36+0.64*_61spfdomv[i]})`; - cctx.fillRect(i*(canvas.width/this._61spbins),canvas.height-(canvas.height*_61spfdomv[i]),canvas.width/this._61spbins*0.96,canvas.height*_61spfdomv[i]); + cctx.fillStyle=`rgba(70,130,180,${0.36+0.64*_61spfdomv[i]})`; + cctx.fillRect(i*(canvas.width/this._61spbins),canvas.height-(0.617274873*canvas.height*_61spfdomv[i]),canvas.width/this._61spbins*0.96,0.617274873*canvas.height*_61spfdomv[i]); - cctx.fillStyle='rgb(110,139,161)'; - cctx.fillRect(i*(canvas.width/this._61spbins),canvas.height-(canvas.height*this._61spcaps[i])-4,canvas.width/this._61spbins*0.96,4); - } - }catch(e){} - }, - update_scope:function() - { - const cctx=this.cctx,canvas=NSUI.canvas; - cctx.clearRect(0,0,canvas.width,canvas.height); - try{ - let timedomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); - NSAudio.anlznode.getByteTimeDomainData(timedomv); - cctx.lineWidth=window.devicePixelRatio; - cctx.strokeStyle='#000'; - if(athm)cctx.strokeStyle='#FFF'; - cctx.beginPath(); - for(let i=0,x=0;i<this.nbins;++i) - { - if(i==0)cctx.moveTo(x,timedomv[i]/128.*canvas.height/2); - else cctx.lineTo(x,timedomv[i]/128.*canvas.height/2); - x+=canvas.width*1./this.nbins; - } - cctx.stroke(); - }catch(e){ - cctx.beginPath(); - cctx.moveTo(0,canvas.height/2); - cctx.lineTo(canvas.width,canvas.height/2); - cctx.stroke(); - } - }, - update_spectrogram:function() - { - const cctx=this.cctx,canvas=NSUI.canvas; - try{ - let freqdomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); - NSAudio.anlznode.getByteFrequencyData(freqdomv); - cctx.clearRect(this.spectgrmp/this.spectgrmw*canvas.width,0,canvas.width/this.spectgrmw,canvas.height); - for(let i=0;i<this.nbins;++i) - { - let color=(athm?'rgba(255,255,255,':'rgba(0,0,0,')+freqdomv[i]/256.+')'; - cctx.fillStyle=color; - cctx.fillRect(this.spectgrmp/this.spectgrmw*canvas.width,(this.nbins-i)/this.nbins*canvas.height,canvas.width/this.spectgrmw,canvas.height/this.nbins); - } - if(!NSUI.audio.paused)++this.spectgrmp; - if(this.spectgrmp>=this.spectgrmw)this.spectgrmp=0; - }catch(e){ - this.spectgrmp=0; - cctx.clearRect(0,0,canvas.width,canvas.height); - } - }, - updateVisualization:function() - { - switch(NSUI.vissel.value) - { - case 'spectrum': - NSVisualization.update_spectrum(); - break; - case 'spspectrum': - NSVisualization.update_61_spectrum(); - break; - case 'scope': - NSVisualization.update_scope(); - break; - case 'spectrogram': - NSVisualization.update_spectrogram(); - break; - case 'inkfountain': - NSInk.update(); - break; - } - if(NSUI.vissel.value!='none') - requestAnimationFrame(NSVisualization.updateVisualization); - } + cctx.fillStyle='rgb(110,139,161)'; + cctx.fillRect(i*(canvas.width/this._61spbins),canvas.height-(0.617274873*canvas.height*this._61spcaps[i])-4,canvas.width/this._61spbins*0.96,4); + } + }catch(e){} + }, + update_scope:function() + { + const cctx=this.cctx,canvas=NSUI.canvas; + cctx.clearRect(0,0,canvas.width,canvas.height); + try{ + let timedomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); + NSAudio.anlznode.getByteTimeDomainData(timedomv); + cctx.lineWidth=window.devicePixelRatio; + cctx.strokeStyle='#000'; + if(athm)cctx.strokeStyle='#FFF'; + cctx.beginPath(); + for(let i=0,x=0;i<this.nbins;++i) + { + if(i==0)cctx.moveTo(x,timedomv[i]/128.*canvas.height/2); + else cctx.lineTo(x,timedomv[i]/128.*canvas.height/2); + x+=canvas.width*1./this.nbins; + } + cctx.stroke(); + }catch(e){ + cctx.beginPath(); + cctx.moveTo(0,canvas.height/2); + cctx.lineTo(canvas.width,canvas.height/2); + cctx.stroke(); + } + }, + update_spectrogram:function() + { + const cctx=this.cctx,canvas=NSUI.canvas; + try{ + let freqdomv=new Uint8Array(NSAudio.anlznode.frequencyBinCount); + NSAudio.anlznode.getByteFrequencyData(freqdomv); + cctx.clearRect(this.spectgrmp/this.spectgrmw*canvas.width,0,canvas.width/this.spectgrmw,canvas.height); + for(let i=0;i<this.nbins;++i) + { + let color=(athm?'rgba(255,255,255,':'rgba(0,0,0,')+freqdomv[i]/256.+')'; + cctx.fillStyle=color; + cctx.fillRect(this.spectgrmp/this.spectgrmw*canvas.width,(this.nbins-i)/this.nbins*canvas.height,canvas.width/this.spectgrmw,canvas.height/this.nbins); + } + if(!NSUI.audio.paused)++this.spectgrmp; + if(this.spectgrmp>=this.spectgrmw)this.spectgrmp=0; + }catch(e){ + this.spectgrmp=0; + cctx.clearRect(0,0,canvas.width,canvas.height); + } + }, + updateVisualization:function() + { + switch(NSUI.vissel.value) + { + case 'spectrum': + NSVisualization.update_spectrum(); + break; + case 'spspectrum': + NSVisualization.update_61_spectrum(); + break; + case 'scope': + NSVisualization.update_scope(); + break; + case 'spectrogram': + NSVisualization.update_spectrogram(); + break; + case 'inkfountain': + NSInk.update(); + break; + } + if(NSUI.vissel.value!='none') + requestAnimationFrame(NSVisualization.updateVisualization); + } }; NSInk={ - ic1:['#FF3333','#FF8800','#FFFF00','#CCFF00','#33CCFF','#0000FF','#9966FF'], - ic2:['rgba(204,51,51,0.6)','rgba(187,85,0,0.6)','rgba(255,204,0,0.6)','rgba(153,204,0,0.6)','rgba(51,153,255,0.6)','rgba(0,0,102,0.6)','rgba(153,51,204,0.6)'], - inks:[], - inkimg:[], - ifcaps:[], - nbinsif:128, - inkPrepare:function() - { - for(let i=0;i<7;++i) - { - this.inkimg[i]=document.createElement('canvas'); - this.inkimg[i].width=this.inkimg[i].height=10*window.devicePixelRatio; - const cctx=this.inkimg[i].getContext('2d'); - cctx.fillStyle=this.ic1[i]; - cctx.beginPath(); - cctx.arc(5*window.devicePixelRatio,5*window.devicePixelRatio,3*window.devicePixelRatio,0,2*Math.PI); - cctx.fill(); - cctx.fillStyle=this.ic2[i]; - cctx.beginPath(); - cctx.arc(5*window.devicePixelRatio,5*window.devicePixelRatio,5*window.devicePixelRatio,0,2*Math.PI); - cctx.fill(); - } - for(let i=0;i<NSVisualization.nbins;++i)this.ifcaps[i]=0; - this.nbinsif=NSVisualization.nbins/8; - }, - createInk:function(_vx,_vy,_c1,_c2) - { - let f=false; - for(let i=0;i<this.inks.length;++i) - { - if(!this.inks[i].active) - {this.inks[i]=new Ink(_vx,_vy,_c1,_c2);f=true;break;} - } - if(!f&&this.inks.length<512)this.inks.push(new Ink(_vx,_vy,_c1,_c2)); - }, - frms:0,lastfpsupd:null,fps:0, - update:function() - { - const canvas=NSUI.canvas; - const cctx=canvas.getContext('2d'),ts=Date.now(); - cctx.clearRect(0,0,canvas.width,canvas.height); - ++this.frms;if(Date.now()-this.lastfpsupd>500) - { - if(this.lastfpsupd) - this.fps=1000*this.frms/(Date.now()-this.lastfpsupd),this.frms=0; - this.lastfpsupd=Date.now(); - } - try{ - let freqarr=new Uint8Array(NSAudio.anlznode.frequencyBinCount); - NSAudio.anlznode.getByteFrequencyData(freqarr); - for(let i=0;i<this.nbinsif;++i) - { - let r=0; - for(let j=0;j<8;++j)r+=freqarr[i*8+j]; - r/=8.; - if(r-this.ifcaps[i]>7) - { - let color=Math.floor(i*8.0/this.nbinsif),rad=Math.random()*Math.PI*2; - let ndrops=(128-i)/128.*3+1;ndrops*=(r/128.);ndrops=Math.floor(ndrops);if(ndrops<1)ndrops=1; - for(let k=0;k<ndrops;++k) - { - this.createInk(((r-this.ifcaps[i]-7)/32*24+12)*Math.cos(rad),((r-this.ifcaps[i]-7)/32*24+12)*Math.sin(rad),color); - rad=Math.random()*Math.PI*2; - } - } - if(r>this.ifcaps[i])this.ifcaps[i]=r;else this.ifcaps[i]-=2; - } - }catch(e){ - cctx.clearRect(0,0,canvas.width,canvas.height); - } - const tu=Date.now(); - let aa=0; - for(let i=0;i<this.inks.length;++i) - if(this.inks[i].active){this.inks[i].update();this.inks[i].draw(cctx);++aa;} - cctx.fillStyle='#000'; - cctx.font="1em 'CMU Typewriter Text w', 'CMU Typewriter Text', 'TeX Gyre Cursor', 'FreeMono', 'Courier New', Courier, monospace"; - cctx.fillText('Active droplets '+aa+', '+this.fps.toFixed(2)+' FPS',0,10); - cctx.fillText('Update time '+(tu-ts)+'ms, render time '+(Date.now()-tu)+'ms',0,24); - } + ic1:['#FF3333','#FF8800','#FFFF00','#CCFF00','#33CCFF','#0000FF','#9966FF'], + ic2:['rgba(204,51,51,0.6)','rgba(187,85,0,0.6)','rgba(255,204,0,0.6)','rgba(153,204,0,0.6)','rgba(51,153,255,0.6)','rgba(0,0,102,0.6)','rgba(153,51,204,0.6)'], + inks:[], + inkimg:[], + ifcaps:[], + nbinsif:128, + inkPrepare:function() + { + for(let i=0;i<7;++i) + { + this.inkimg[i]=document.createElement('canvas'); + this.inkimg[i].width=this.inkimg[i].height=10*window.devicePixelRatio; + const cctx=this.inkimg[i].getContext('2d'); + cctx.fillStyle=this.ic1[i]; + cctx.beginPath(); + cctx.arc(5*window.devicePixelRatio,5*window.devicePixelRatio,3*window.devicePixelRatio,0,2*Math.PI); + cctx.fill(); + cctx.fillStyle=this.ic2[i]; + cctx.beginPath(); + cctx.arc(5*window.devicePixelRatio,5*window.devicePixelRatio,5*window.devicePixelRatio,0,2*Math.PI); + cctx.fill(); + } + for(let i=0;i<NSVisualization.nbins;++i)this.ifcaps[i]=0; + this.nbinsif=NSVisualization.nbins/8; + }, + createInk:function(_vx,_vy,_c1,_c2) + { + let f=false; + for(let i=0;i<this.inks.length;++i) + { + if(!this.inks[i].active) + {this.inks[i]=new Ink(_vx,_vy,_c1,_c2);f=true;break;} + } + if(!f&&this.inks.length<512)this.inks.push(new Ink(_vx,_vy,_c1,_c2)); + }, + frms:0,lastfpsupd:null,fps:0, + update:function() + { + const canvas=NSUI.canvas; + const cctx=canvas.getContext('2d'),ts=Date.now(); + cctx.clearRect(0,0,canvas.width,canvas.height); + ++this.frms;if(Date.now()-this.lastfpsupd>500) + { + if(this.lastfpsupd) + this.fps=1000*this.frms/(Date.now()-this.lastfpsupd),this.frms=0; + this.lastfpsupd=Date.now(); + } + try{ + let freqarr=new Uint8Array(NSAudio.anlznode.frequencyBinCount); + NSAudio.anlznode.getByteFrequencyData(freqarr); + for(let i=0;i<this.nbinsif;++i) + { + let r=0; + for(let j=0;j<8;++j)r+=freqarr[i*8+j]; + r/=8.; + if(r-this.ifcaps[i]>7) + { + let color=Math.floor(i*8.0/this.nbinsif),rad=Math.random()*Math.PI*2; + let ndrops=(128-i)/128.*3+1;ndrops*=(r/128.);ndrops=Math.floor(ndrops);if(ndrops<1)ndrops=1; + for(let k=0;k<ndrops;++k) + { + this.createInk(((r-this.ifcaps[i]-7)/32*24+12)*Math.cos(rad),((r-this.ifcaps[i]-7)/32*24+12)*Math.sin(rad),color); + rad=Math.random()*Math.PI*2; + } + } + if(r>this.ifcaps[i])this.ifcaps[i]=r;else this.ifcaps[i]-=2; + } + }catch(e){ + cctx.clearRect(0,0,canvas.width,canvas.height); + } + const tu=Date.now(); + let aa=0; + for(let i=0;i<this.inks.length;++i) + if(this.inks[i].active){this.inks[i].update();this.inks[i].draw(cctx);++aa;} + cctx.fillStyle='#000'; + cctx.font="1em 'CMU Typewriter Text w', 'CMU Typewriter Text', 'TeX Gyre Cursor', 'FreeMono', 'Courier New', Courier, monospace"; + cctx.fillText('Active droplets '+aa+', '+this.fps.toFixed(2)+' FPS',0,10); + cctx.fillText('Update time '+(tu-ts)+'ms, render time '+(Date.now()-tu)+'ms',0,24); + } }; function init() { - if(!window.devicePixelRatio)window.devicePixelRatio=1; - NSUI.setup_ui(); - NSUI.load_playlists() - .then(()=>{ - sh.elem('overlaytext').innerHTML+="Done!<br>Click or tap anywhere to start." - sh.elem('overlay').onclick=function(){ - NSAudio.audioInit();NSAudio.connect(); - if(window.location.hash.length) - { - let p=window.location.hash.substr(1).split('/'); - for(let i=0;i<p.length;++i)p[i]=decodeURIComponent(p[i]); - NSUI.switch_playlist(p[0],true); - let id=0; - for(;id<NSPlayer.tracks.length&&NSPlayer.tracks[id].title!=p[1];++id); - if(id<NSPlayer.tracks.length)NSUI.switch_track(id); - } - sh.elem('overlay').style.display='none'; - } - }); - NSVisualization.init();NSInk.inkPrepare(); - NSUI.audio.ontimeupdate=NSUI.timeUpdate; - NSUI.audio.onended=NSPlayer.next.bind(NSPlayer); - NSUI.audio.onplay=NSUI.audio.ondurationchange=function(){ - if(NSUI.audio.audioTracks.length==2) - sh.elem('mt').style.display='inline'; - else - sh.elem('mt').style.display='none'; - }; - switch(sh.getcookie('playershuffle')) - { - case '1':NSPlayer.shuffle=1;break; - default: - case '0':NSPlayer.shuffle=0;break; - } - switch(sh.getcookie('playerrepeat')) - { - case '1': - NSPlayer.repeat=1; - NSUI.audio.loop=true; - break; - default: - case '0': - NSPlayer.repeat=0; - NSUI.audio.loop=false; - break; - } - NSUI.ishuffle.style.backgroundPosition=`${NSPlayer.shuffle?NSUI.bshonrect:NSUI.bsoffrect}`; - NSUI.irepeat.style.backgroundPosition=`${NSPlayer.repeat?NSUI.bronerect:NSUI.brallrect}`; - if(sh.getcookie('playervisualization').length!==0) - NSUI.vissel.value=sh.getcookie('playervisualization'); - requestAnimationFrame(NSVisualization.updateVisualization); + if(!window.devicePixelRatio)window.devicePixelRatio=1; + NSUI.setup_ui(); + NSUI.load_playlists() + .then(()=>{ + sh.elem('overlaytext').innerHTML+="Done!<br>Click or tap anywhere to start." + sh.elem('overlay').onclick=function(){ + NSAudio.audioInit();NSAudio.connect(); + if(window.location.hash.length) + { + let p=window.location.hash.substr(1).split('/'); + for(let i=0;i<p.length;++i)p[i]=decodeURIComponent(p[i]); + NSUI.switch_playlist(p[0],true); + let id=0; + for(;id<NSPlayer.tracks.length&&NSPlayer.tracks[id].title!=p[1];++id); + if(id<NSPlayer.tracks.length)NSUI.switch_track(id); + } + sh.elem('overlay').style.display='none'; + } + }); + NSVisualization.init();NSInk.inkPrepare(); + NSUI.audio.ontimeupdate=NSUI.timeUpdate; + NSUI.audio.onended=NSPlayer.next.bind(NSPlayer); + NSUI.audio.onplay=NSUI.audio.ondurationchange=function(){ + if(NSUI.audio.audioTracks.length==2) + sh.elem('mt').style.display='inline'; + else + sh.elem('mt').style.display='none'; + }; + switch(sh.getcookie('playershuffle')) + { + case '1':NSPlayer.shuffle=1;break; + default: + case '0':NSPlayer.shuffle=0;break; + } + switch(sh.getcookie('playerrepeat')) + { + case '1': + NSPlayer.repeat=1; + NSUI.audio.loop=true; + break; + default: + case '0': + NSPlayer.repeat=0; + NSUI.audio.loop=false; + break; + } + NSUI.ishuffle.style.backgroundPosition=`${NSPlayer.shuffle?NSUI.bshonrect:NSUI.bsoffrect}`; + NSUI.irepeat.style.backgroundPosition=`${NSPlayer.repeat?NSUI.bronerect:NSUI.brallrect}`; + if(sh.getcookie('playervisualization').length!==0) + NSUI.vissel.value=sh.getcookie('playervisualization'); + requestAnimationFrame(NSVisualization.updateVisualization); } |