From 5e21f50d81e387b00a511afc711109bc846618ce Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 22 May 2020 12:00:00 +0800 Subject: Improved simulation for the spectrum visualization from ShadowPlayer. Also re-indented the entire file so that it doesn't set the reader's eyes on fire. --- libs/music/player.d/main_static.js | 1374 ++++++++++++++++++------------------ 1 file changed, 689 insertions(+), 685 deletions(-) (limited to 'libs') 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{ - const ra=shuffle?a.sord:a.ord; - const rb=shuffle?b.sord:b.ord; - return ra{ + const ra=shuffle?a.sord:a.ord; + const rb=shuffle?b.sord:b.ord; + return ra10)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{ - for(let i=0;i{ - tarr[rp.plistord]=rp; - if(--cnt<=0)a(null); - }); - } - }); - await p; - for(let i=0;i=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(;cid10)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{ + for(let i=0;i{ + tarr[rp.plistord]=rp; + if(--cnt<=0)a(null); + }); + } + }); + await p; + for(let i=0;i=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(;cid0)--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;i0)--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;i0)--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;i0)--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;iMath.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.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.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;i500) - { - 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;i7) - { - 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;kthis.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;i500) + { + 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;i7) + { + 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;kthis.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{ - sh.elem('overlaytext').innerHTML+="Done!
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{ + sh.elem('overlaytext').innerHTML+="Done!
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