2 lines
47 KiB
HTML
2 lines
47 KiB
HTML
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>white rain</title><link rel="icon" href="data:,"><style>:root{--bg:#050505;--bg2:#0b0b0b;--text:#f5f5f2;--text-2:rgba(245,245,242,.72);--text-3:rgba(245,245,242,.42);--line:rgba(255,255,255,.08);--line-2:rgba(255,255,255,.14);--hover:rgba(255,255,255,.92);--active:#fff;--track:#121212;--track-2:#1a1a1a}*{box-sizing:border-box}html,body{height:100%;margin:0;background:var(--bg);color:var(--text);font:13px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;letter-spacing:.01em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{color:var(--text);text-decoration:none}a:hover{color:var(--hover)}button,input,select,textarea{font:inherit}#app{min-height:100%;display:grid;grid-template-rows:auto auto 1fr}.hideu{opacity:0;display:none}.top{position:sticky;top:0;z-index:5;background:rgba(5,5,5,.86);backdrop-filter:blur(14px);border-bottom:1px solid var(--line)}.hero{padding:18px 18px 8px}.title{font-size:22px;font-weight:500;letter-spacing:.08em;text-transform:lowercase;color:var(--text)}.sub{display:block;margin-top:2px;color:var(--text-3);font-size:11px;letter-spacing:.08em;text-transform:lowercase}.msg{min-height:18px;color:var(--text-3);padding:0 18px 14px;font-size:12px;letter-spacing:.04em}.layout{display:grid;grid-template-columns:1fr;gap:18px;padding:14px 16px 28px;max-width:1120px;width:100%;margin:0 auto}.panel{background:transparent;border:none;border-radius:0;padding:4px 0}.transport{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:center;padding-bottom:10px;border-bottom:1px solid var(--line)}.controls{display:flex;gap:16px;flex-wrap:wrap;align-items:center}.btn,.pill{appearance:none;background:transparent;border:none;color:var(--text-3);border-radius:0;padding:4px 0;cursor:pointer;transition:color .16s ease,opacity .16s ease,transform .16s ease;position:relative;letter-spacing:.06em;text-transform:lowercase}.btn::after,.pill::after{content:"";position:absolute;left:0;bottom:-3px;width:100%;height:1px;background:transparent;transition:background .16s ease,opacity .16s ease;opacity:.7}.btn:hover,.pill:hover{color:var(--hover)}.btn:hover::after,.pill:hover::after{background:var(--line-2)}.btn:active,.pill:active{color:var(--active);transform:translateY(1px)}.btn.active,.pill.active{color:var(--text)}.btn.active::after,.pill.active::after{background:var(--active)}.readout{display:flex;gap:12px;align-items:center;justify-content:flex-end;color:var(--text-3);font-variant-numeric:tabular-nums}.mixer{display:grid;grid-template-columns:repeat(10,minmax(24px,1fr));gap:12px;align-items:end;justify-items:center;height:360px;padding:18px 2px 4px}.band{display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:10px;height:100%}.band label{font-size:10px;color:var(--text-3);white-space:nowrap;letter-spacing:.06em;text-transform:lowercase}.v{-webkit-appearance:none;appearance:none;width:20px;height:260px;background:transparent;writing-mode:vertical-lr;direction:rtl}.v::-webkit-slider-runnable-track{width:8px;height:100%;background:linear-gradient(to bottom,var(--track),var(--track-2));border-radius:999px}.v::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:18px;height:18px;border-radius:50%;background:#f1f1ec;border:none;box-shadow:0 0 0 5px var(--bg);margin-left:-5px}.v::-moz-range-track{width:8px;height:100%;background:linear-gradient(to bottom,var(--track),var(--track-2));border:none;border-radius:999px}.v::-moz-range-progress{background:#dcdcd7;border-radius:999px}.v::-moz-range-thumb{width:18px;height:18px;border:none;border-radius:50%;background:#f1f1ec;box-shadow:0 0 0 5px var(--bg)}.os{width:auto;height:auto;border-radius:0;padding:0;color:var(--text-3);font-size:12px}.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}.input{background:transparent;color:var(--text);border:none;border-bottom:1px solid var(--line);border-radius:0;padding:6px 0;outline:none;min-width:48px}.input:focus{border-bottom-color:var(--active);color:var(--active)}.small{font-size:12px;color:var(--text-3)}.grid2{display:grid;grid-template-columns:1fr 1fr;gap:28px}.list{display:flex;flex-wrap:wrap;gap:14px}#presetList .pill,#stereoList .pill{color:var(--text-2)}canvas#fft{width:120px;height:36px;background:#090909;border:1px solid var(--line);border-radius:999px}.text{color:var(--text-2)}code,kbd{background:#0a0a0a;border:1px solid var(--line);border-radius:4px;padding:1px 5px}details{border-top:none;padding-top:0}summary{cursor:pointer;color:var(--text-2)}.footer{display:none}.bg{position:fixed;inset:0;background:center/cover no-repeat;opacity:.08;filter:grayscale(1) blur(12px);pointer-events:none;transform:translateZ(0) scale(1.02)}strong{font-weight:500;color:var(--text);letter-spacing:.06em;text-transform:lowercase}@media (max-width:800px){.grid2{grid-template-columns:1fr}.mixer{gap:8px;height:310px}.v{height:220px;width:18px}.title{font-size:20px}.controls{gap:12px}}</style></head><body><div id="app"></div><script>const cfg={live:0,oneshot:false,custom:0,noiseDir:"RAIN2",cdn:"",shortUrl:"/NoiseMachines/whiteRainNoiseGenerator.php",srcA:["./audio/0a","./audio/1a","./audio/2b","./audio/3a","./audio/4a","./audio/5b","./audio/6a","./audio/7b","./audio/8a","./audio/9a"],srcB:["./audio/0b","./audio/1b","./audio/2a","./audio/3b","./audio/4b","./audio/5a","./audio/6b","./audio/7a","./audio/8b","./audio/9b"],totSizeMP3:5628436,totSizeOGG:5400163,stretch:[1.25,1.25,1.25,1.25,1.25,1.25,1.25,1.25,1.25,1.25],detune:"0",defaultCurve:[.3,.3,.3,.3,.3,.3,.3,.3,.3,.3],magicParam:"",uIDS:"",patronMessage:false,mediaTitle:"White Rain",albumDir:"RAIN2"};const state={iNUMBERBANDS:10,bCALIBRATE:0,bMUTE:0,bMUTEsaved:0,bANIMATE:0,bDISABLE:0,bMEDITATIONSESSION:0,bFINISHEDLOADING:0,bSUPPORTOGG:0,bSUPPORTMP3:0,bSUSPENDED:0,bSTARTMUTED:0,bPITCHRAN:0,bOSAUTO:0,bEQ:0,bWAVEVISUALIZER:0,bANIMATIONONSTART:0,bANIMATIONPROFILESET:0,bANIMATIONUSERPROFILESET:0,bDynamics:1,MOBILE:false,bUSE_STREAM_DESTINATION:0,fMASTERGAIN:.5,fTARGETSLIDERLEVEL:.5,fAUDIOFADETIME:cfg.live?.5:.1,fLevelMultiplier:1.1,fSTEREOWIDTH:1,gainForEQ:1,currentLevel:Array(10).fill(.3),savedCurrentLevel:Array(10).fill(.3),savedLevel:Array(10).fill(.3),randomLevel:Array(10).fill(.3),selSliders:[1,1,1,1,1,1,1,1,1,1,0],movedSlider:null,lastSlider:null,detune:cfg.detune,playbackFactor:Array(10).fill(1),pitchTable:[1],stretch:cfg.stretch.slice(),iINITIALANIMATIONSPEED:32,iAnimationFactor:1,iAnimationMode:"s",iCurrentAnimationSpeed:32,randomCounter:0,animationProfileLow:Array(10).fill(0),animationProfileHigh:Array(10).fill(.5),animatedIndices:[],nzSliderIndex:[],mmMin:1,mmMax:0,modulationTimeout:null,iTimer:-1,iMTimer:-1,epoch:0,timerTimeout:null,fadeTimeOut:null,meditationInterval:null,meditationInterval2:null,osInterval:null,meditationBell:null,timeOutOS:Array(10),cloneURL:"",cookieURL:"",appShareURL:"",URLlevels:"",URLanimate:"",URLmute:"",URLbell:"",URLtimer:"",URLdetune:"",URLmagic:"",URLtitle:"",URLwidth:"",uIDS:cfg.uIDS,fileExt:".ogg",bDOWNLOADED:[],iSTARTED:[],iLOADED:[],iTOTAL:[],totSizeMP3:cfg.totSizeMP3,totSizeOGG:cfg.totSizeOGG,serverTotal:cfg.totSizeOGG,dlMonitorThrottle:-500,launchCounter:0,voiceover:[],allContents:"",sto:[],meditationRoomBaselineSliderLevel:.4,l:[],fCONTEXTSTART:0,longPressTimer:null,isLongPress:false,samplesArray:null,analyser:null,levelHistory:[],levelHistorySize:20,levelHistoryIndex:0,smoothedMasterLevel:.3,bLEVELHISTORYINIT:false,aWeighting:[.003,.05,.16,.35,.5,1,1.12,1.12,1.12,1.06,1,.89,.75,.63,.5,.45],preDuckGain:0,isDucking:false,interval:Array(10),nextA:Array(10),nextB:Array(10),lastPlayedOS:[1,1,1,1,1,1,1,1,1,1],sourceFileA:[],sourceFileB:[],sourceA:Array(10),sourceB:Array(10),bufferList:Array(20),gainNode:Array(10),stemAnalyser:Array(10),eqNode:Array(10),context:null,masterGain:null,dynCompressor:null,streamDestination:null,streamAudio:null,splitterNode:null,mergerNode:null,midGain:null,sideGain:null,negateR:null,negateSide:null,schedulerTimer:null,lastSchedulerTime:0,fftData:null,fftCanvas:null,fftCtx:null,pos:[0,0,0,0],posOld:[0,0,0,0],visualizerStartedAt:0};const qs=s=>document.querySelector(s),qsa=s=>[...document.querySelectorAll(s)];const app=qs("#app");app.innerHTML='<div class="bg" id="bg"></div><div class="top"><div class="hero"><div class="title"></div><div class="sub">rain noise</div></div><div class="msg" id="msg"></div></div><div class="layout"><div class="panel transport"><div class="controls"><button class="btn" id="playBtn">play</button><button class="btn" id="resetBtn">default</button><button class="btn hideu" id="downBtn">down</button><button class="btn hideu" id="upBtn">up</button><button class="btn" id="animBtn">motion</button><button class="btn hideu" id="bellBtn">bell</button><input class="input hideu" id="bellInput" size="7" placeholder=""><button class="btn" id="timerBtn">sleep</button><input class="input" id="timerInput" size="4" placeholder="min"></div><div></div><div class="readout"><canvas id="fft" width="120" height="36"></canvas><span class="hideu" id="stateTxt">idle</span></div></div><div class="panel"><div class="mixer" id="mixer"></div></div><div class="grid2"><div class="panel"><div class="row"><strong>curves</strong></div><div class="list" id="presetList"></div><div class="row" style="margin-top:10px"><strong>image</strong></div><div class="list" id="stereoList"></div><div class="row" style="margin-top:10px"><strong>speed</strong></div><div class="list"><button class="pill" data-tune=".9438743126816935">432hz</button><button class="pill" data-tune="1">reset</button><button class="pill" id="slowerBtn">slower</button><button class="pill" id="fasterBtn">faster</button><button class="pill" id="alternateBtn">alternate</button></div><div class="row" style="margin-top:10px"><strong>contour</strong></div><div class="list"><button class="pill" data-ieq="0">none</button><button class="pill" data-ieq=".5">balanced</button><button class="pill" data-ieq="1">full</button><button class="pill" id="applyCalBtn">apply</button></div></div><div class="panel"><div class="row"><strong>motion</strong></div><div class="list"><button class="pill" data-am="s">soft</button><button class="pill" data-am="h">hard</button><button class="pill" data-am="i">solo</button><button class="pill" data-am="d">duo</button><button class="pill" data-am="t">trio</button><button class="pill" data-am="q">quad</button></div><div class="list" style="margin-top:8px"><button class="pill" data-as=".125">÷8</button><button class="pill" data-as=".25">÷4</button><button class="pill" data-as=".5">÷2</button><button class="pill" data-as="1">normal</button><button class="pill" data-as="2">x2</button><button class="pill" data-as="4">x4</button><button class="pill" data-as="8">x8</button></div><div class="list" style="margin-top:8px"><button class="pill" id="setLoBtn">save low</button><button class="pill" id="loadLoBtn">low</button><button class="pill" id="loadHiBtn">high</button><button class="pill" id="setHiBtn">save high</button></div><div class="row" style="margin-top:10px"><strong>share</strong></div><div class="list"><button class="pill" id="saveUrlBtn">copy link</button><button class="pill hideu" id="saveCookieBtn">save browser</button><button class="pill hideu" id="loadCookieBtn">load browser</button><button class="pill hideu" id="miniBtn">miniplayer</button><button class="pill hideu" id="qrBtn">app url</button></div></div></div><div class="panel hideu"><details open><summary></summary><div class="text hideu"><p><code>./audio/</code>:</p><p><code>0a.ogg 0b.ogg 1a.ogg 1b.ogg 2a.ogg 2b.ogg 3a.ogg 3b.ogg 4a.ogg 4b.ogg 5a.ogg 5b.ogg 6a.ogg 6b.ogg 7a.ogg 7b.ogg 8a.ogg 8b.ogg 9a.ogg 9b.ogg</code></p></div></details></div></div>';const bands=["sub bass","low bass","bass","high bass","low mids","mids","high mids","low treble","treble","high treble"];const colors=Array(10).fill("#f1f1ec");qs("#mixer").innerHTML=bands.map((b,i)=>`<div class="band"><button class="btn os" id="os${i}">▶</button><input class="v" id="s${i}" type="range" min="0" max="0.99" step="0.001" value="0.3"><label>${b}</label></div>`).join("");const presets=[["brown",[.5,.46,.42,.38,.34,.3,.27,.24,.21,.18]],["pink",[.3,.3,.3,.3,.3,.3,.3,.3,.3,.3]],["white",[.16,.19,.22,.25,.27,.31,.35,.38,.42,.45]],["grey",[.5,.3,.25,.2,.2,.2,.18,.16,.2,.3]],["infra",[.6,.4,.25,.15,.07,.03,0,0,0,0]],["ultra",[0,0,0,0,.03,.06,.12,.19,.3,.45]],["60hz",[.35,.5,.35,0,0,0,0,0,0,0]],["125hz",[0,.4,.5,.4,0,0,0,0,0,0]],["250hz",[0,0,.35,.45,.35,0,0,0,0,0]],["500hz",[0,0,0,.3,.4,.3,0,0,0,0]],["1khz",[0,0,0,0,.3,.4,.3,0,0,0]],["2khz",[0,0,0,0,0,.3,.4,.3,0,0]],["4khz",[0,0,0,0,0,0,.3,.4,.3,0]],["8khz",[0,0,0,0,0,0,0,.35,.45,.35]],["speech blocker",[.14,.22,.28,.4,.46,.42,.28,.21,.13,.05]],["gentle rain",[0,0,.1,.21,.29,.33,.33,.31,.25,.18]]];qs("#presetList").innerHTML=presets.map((p,i)=>`<button class="pill" data-preset="${i}">${p[0]}</button>`).join("");qs("#stereoList").innerHTML='<button class="pill" data-width="0">mono</button><button class="pill" data-width=".5">narrow</button><button class="pill" data-width="1">normal</button><button class="pill" data-width="1.8">wide</button>';function msg(t){qs("#msg").textContent=t}function createCookie(name,value,days){let expires="";if(days){const date=new Date;date.setTime(date.getTime()+days*24*60*60*1e3);expires="; expires="+date.toUTCString()}document.cookie=name+"="+encodeURIComponent(value)+expires+"; path=/"}function readCookie(name){const nameEQ=name+"=",ca=document.cookie.split(";");for(let c of ca){for(;" "==c.charAt(0);)c=c.substring(1);if(0==c.indexOf(nameEQ))return decodeURIComponent(c.substring(nameEQ.length)).replace(/%2C/g,",")}return null}function getUrlVars(str){str=str||location.href;const vars={};return str.replace(/[?&]+([^=&]+)=([^&]*)/gi,(m,key,value)=>vars[key]=value),vars}function pad(n){let s="000"+n;return s.substr(s.length-2)}function packVector(v){let str="";for(let i=0;i<10;i++)str+=pad(Math.round(100*v[i]));return str}function unpackVector(code,target){code=(code||"").replace(/\D/g,"");for(let i=0;i<10;i++)target[i]=code.substring(2*i,2*i+2)/100||0;return target}function quantizeLevel(val){if(val<=0)return 0;if(val>=.99)return .99;const step=.001,m=val%step;let a=val-m;return Math.abs(m)*2>=step&&(a+=m>0?step:-step),parseFloat(a.toFixed(5))}function levelToGain(level){return Math.pow(level,3)}function slider(i){return qs("#s"+i)}function sliderViewGet(i){return parseFloat(slider(i).value)}function sliderViewSet(i,v){slider(i).value=v}function afterLevelsChanged(){state.bANIMATE||updateDocumentLinks()}function setLevel(i,v,source="program"){state.currentLevel[i]=quantizeLevel(v),state.bFINISHEDLOADING&&setStemGain(i,state.currentLevel[i],state.fAUDIOFADETIME),"user"!==source&&sliderViewSet(i,state.currentLevel[i]),afterLevelsChanged()}function setLevels(vector,source="program"){for(let i=0;i<10;i++)setLevel(i,vector[i],source);"anim"!==source&&afterLevelsChanged()}function getCurrentLevelsFromSliders(){for(let i=0;i<10;i++)state.currentLevel[i]=sliderViewGet(i)}function setCurrentLevelsToSliders(){setLevels(state.currentLevel,"program")}function setAllLevels(){for(let i=0;i<10;i++)setStemGain(i,state.currentLevel[i],state.fAUDIOFADETIME)}function normalizeLevels(vector){const boostTable=[0,1.5,1.36,1.23,1.12,1.13,1.02,1,.98,.95,.9];let max=0;for(let i=0;i<10;i++)vector[i]>max&&(max=vector[i]);let active=0;for(let i=0;i<10;i++)vector[i]>.8*max&&active++;if(active>0&&max>0){const mult=state.fTARGETSLIDERLEVEL/max*boostTable[active];for(let i=0;i<10;i++)vector[i]=Math.min(vector[i]*mult,.9)}return vector}function setPreset(...args){let text=args[10];state.bMUTE&&toggleMute();let levels=args.slice(0,10);state.bCALIBRATE||(levels=normalizeLevels(levels));for(let i=0;i<10;i++)state.currentLevel[i]=levels[i];saveRandomExchange(),state.bANIMATE||(setCurrentLevelsToSliders(),msg(text||""))}function defaultLevels(){return cfg.defaultCurve||Array(10).fill(state.fTARGETSLIDERLEVEL)}function resetSliders(){setPreset(...defaultLevels(),"default curve restored")}function randomSettings(){const r=[];for(let i=0;i<10;i++)r[i]=Math.random()>.3?Math.random():0;setPreset(...r,"random")}function slidersUp(){if(state.bMUTE&&toggleMute(),state.bMUTE);for(let i=0;i<10;i++)state.currentLevel[i]=Math.min(.99,state.currentLevel[i]*state.fLevelMultiplier),state.savedLevel[i]=Math.min(.99,state.savedLevel[i]*state.fLevelMultiplier),state.randomCounter=0,state.bANIMATE&&(state.animationProfileLow[i]=Math.min(.99,state.animationProfileLow[i]*state.fLevelMultiplier),state.animationProfileHigh[i]=Math.min(.99,state.animationProfileHigh[i]*state.fLevelMultiplier));setCurrentLevelsToSliders()}function slidersDown(){if(state.bMUTE&&toggleMute(),state.bMUTE);for(let i=0;i<10;i++)state.currentLevel[i]/=state.fLevelMultiplier,state.savedLevel[i]/=state.fLevelMultiplier,state.randomCounter=0,state.bANIMATE&&(state.animationProfileLow[i]/=state.fLevelMultiplier,state.animationProfileHigh[i]/=state.fLevelMultiplier);setCurrentLevelsToSliders()}function createAudioContext(){const AC=window.AudioContext||window.webkitAudioContext;return!!AC&&(state.context=new AC,!0)}function assignSources(){state.fileExt=".ogg",state.meditationBell=new Audio("./audio/bell"+state.fileExt),state.meditationBell.preload="auto",state.sourceFileA=cfg.srcA.map(u=>u+state.fileExt),state.sourceFileB=cfg.srcB.map(u=>u+state.fileExt)}let onLoadProgress=null,onStemDecoded=null;function loadAllSounds(progressCb,decodedCb){onLoadProgress=progressCb,onStemDecoded=decodedCb;for(let i=0;i<10;i++)loadWebAudioSound(state.sourceFileA[i],i);for(let i=0;i<10;i++)loadWebAudioSound(state.sourceFileB[i],i+10)}function loadWebAudioSound(url,i){const req=new XMLHttpRequest;req.open("GET",url,!0),req.responseType="arraybuffer",req.onload=()=>{state.context.decodeAudioData(req.response,d=>{if(1===d.numberOfChannels){const stereo=state.context.createBuffer(2,d.length,d.sampleRate),mono=d.getChannelData(0);stereo.copyToChannel(mono,0),stereo.copyToChannel(mono,1),state.bufferList[i]=stereo}else state.bufferList[i]=d;countIn(i)},()=>msg("decode failed: "+url))},req.onerror=()=>msg("load failed: "+url),req.onprogress=e=>{req.NextSecond||(req.NextSecond=0),Date.now()<req.NextSecond||(req.NextSecond=Date.now()+state.dlMonitorThrottle,state.dlMonitorThrottle<1e3&&state.dlMonitorThrottle++,dlMonitor(i,e,req,url))},state.bDOWNLOADED[i]=0,state.iSTARTED[i]=Date.now(),req.send()}function dlMonitor(index,report,initiator,url){if(Date.now()-state.iSTARTED[index]>1e4&&state.iLOADED[index]==report.loaded)return initiator.abort(),void loadWebAudioSound(url,index);if(report.lengthComputable){state.iTOTAL[index]=report.total,state.iLOADED[index]=report.loaded;let grand=0,loaded=0;for(let i=0;i<20;i++)state.iTOTAL[i]&&(grand+=state.iTOTAL[i],loaded+=state.iLOADED[i]);grand>state.serverTotal&&(state.serverTotal=grand),onLoadProgress&&onLoadProgress(loaded,grand,state.serverTotal)}}function countIn(index){state.bDOWNLOADED[index]=1,++state.launchCounter,onStemDecoded&&onStemDecoded(state.launchCounter)}function makeSource(buffer,rate){const src=state.context.createBufferSource();return src.buffer=buffer,src.playbackRate.value=rate,src}function buildAudioGraph(){state.masterGain=state.context.createGain(),state.masterGain.gain.value=.5;for(let i=0;i<10;i++)state.sourceA[i]=makeSource(state.bufferList[i],state.playbackFactor[i]),state.gainNode[i]=state.context.createGain(),state.gainNode[i].gain.value=0,state.sourceA[i].connect(state.gainNode[i]).connect(state.masterGain);for(let i=0;i<10;i++)state.sourceB[i]=makeSource(state.bufferList[i+10],state.playbackFactor[i]),state.sourceB[i].connect(state.gainNode[i]).connect(state.masterGain);state.dynCompressor=new DynamicsCompressorNode(state.context,{threshold:-12,knee:6,ratio:10,attack:.05,release:2}),state.dynCompressor.connect(state.context.destination),state.splitterNode=state.context.createChannelSplitter(2),state.mergerNode=state.context.createChannelMerger(2),state.midGain=state.context.createGain(),state.midGain.gain.value=.5,state.sideGain=state.context.createGain(),state.sideGain.gain.value=.5*state.fSTEREOWIDTH,state.negateR=state.context.createGain(),state.negateR.gain.value=-1,state.negateSide=state.context.createGain(),state.negateSide.gain.value=-1,state.masterGain.connect(state.splitterNode),state.splitterNode.connect(state.midGain,0),state.splitterNode.connect(state.midGain,1),state.splitterNode.connect(state.sideGain,0),state.splitterNode.connect(state.negateR,1),state.negateR.connect(state.sideGain),state.midGain.connect(state.mergerNode,0,0),state.midGain.connect(state.mergerNode,0,1),state.sideGain.connect(state.mergerNode,0,0),state.sideGain.connect(state.negateSide),state.negateSide.connect(state.mergerNode,0,1),state.mergerNode.connect(state.dynCompressor)}function compressorReduction(){return state.dynCompressor&&"number"==typeof state.dynCompressor.reduction?-state.dynCompressor.reduction:0}function attachMasterAnalyser(){return state.analyser=state.context.createAnalyser(),state.analyser.fftSize=32,state.analyser.smoothingTimeConstant=0,state.mergerNode.connect(state.analyser),state.analyser}function stemAnalyserFor(i){return state.stemAnalyser[i]||(state.stemAnalyser[i]=state.context.createAnalyser(),state.stemAnalyser[i].fftSize=512),state.stemAnalyser[i]}function connectStemAnalysers(on){for(let i=0;i<10;i++){const method=on?"connect":"disconnect";try{state.sourceA[i][method](state.stemAnalyser[i])}catch(e){}try{state.sourceB[i][method](state.stemAnalyser[i])}catch(e){}}}function setStemGain(i,level,fadeTime){state.gainNode[i].gain.setTargetAtTime(levelToGain(level),state.context.currentTime,fadeTime)}function audioContextState(){return state.context.state}function resumeAudioContext(force){(force||"running"!==state.context.state)&&state.context.resume()}function suspendAudioContext(){state.context.suspend()}function suspendEngine(){"suspended"!==state.context.state&&state.context.suspend(),stopScheduler()}function fadeMaster(target,seconds,onDone){const now=state.context.currentTime;state.masterGain.gain.cancelScheduledValues(now),state.masterGain.gain.setValueAtTime(state.masterGain.gain.value,now),state.masterGain.gain.linearRampToValueAtTime(target,now+seconds),clearTimeout(state.fadeTimeOut),state.fadeTimeOut=setTimeout(onDone,1e3*seconds)}function duckAudio(levelRatio,fadeTime){if(!state.isDucking){state.isDucking=!0;const now=state.context.currentTime;state.preDuckGain=state.masterGain.gain.value,state.masterGain.gain.cancelScheduledValues(now),state.masterGain.gain.setValueAtTime(state.preDuckGain,now),state.masterGain.gain.linearRampToValueAtTime(state.preDuckGain*levelRatio,now+fadeTime)}}function unduckAudio(fadeTime){if(state.isDucking){state.isDucking=!1;const now=state.context.currentTime;state.masterGain.gain.cancelScheduledValues(now),state.masterGain.gain.setValueAtTime(state.masterGain.gain.value,now),state.masterGain.gain.linearRampToValueAtTime(state.preDuckGain,now+fadeTime)}}function setWidthGains(width){state.midGain.gain.setTargetAtTime(.5,state.context.currentTime,.2),state.sideGain.gain.setTargetAtTime(.5*width,state.context.currentTime,.2)}const SCHEDULE_LOOKAHEAD=.5,SCHEDULE_INTERVAL=100;function startScheduler(){state.schedulerTimer||(state.schedulerTimer=setInterval(schedulerTick,SCHEDULE_INTERVAL))}function stopScheduler(){state.schedulerTimer&&(clearInterval(state.schedulerTimer),state.schedulerTimer=null)}function halfPeriod(i){return Math.round(8*state.bufferList[i].duration)/16*state.stretch[i]/state.playbackFactor[i]}function computeIntervals(){for(let i=0;i<10;i++){const durA=Math.round(8*state.sourceA[i].buffer.duration)/8,durB=Math.round(8*state.sourceB[i].buffer.duration)/8;state.interval[i]=(durA+durB)/2*state.stretch[i]/state.playbackFactor[i]}}function schedulerTick(){const now=state.context.currentTime;if(state.lastSchedulerTime>0&&now-state.lastSchedulerTime>2)for(let i=0;i<10;i++)0!==state.stretch[i]&&(state.nextA[i]=Math.ceil(now+.1),state.nextB[i]=state.nextA[i]+halfPeriod(i));state.lastSchedulerTime=now;for(let i=0;i<10;i++)if(0!==state.stretch[i]){for(;state.nextA[i]<now+SCHEDULE_LOOKAHEAD;)scheduleDue(i,0,state.nextA[i],now),state.nextA[i]+=state.interval[i];for(;state.nextB[i]<now+SCHEDULE_LOOKAHEAD;)scheduleDue(i,1,state.nextB[i],now),state.nextB[i]+=state.interval[i]}}function scheduleDue(i,side,when,now){if(when>=now)scheduleStem(i,side,when);else{const offset=(now-when)*state.playbackFactor[i];offset<state.bufferList[i+10*side].duration&&scheduleStem(i,side,now,offset)}}function scheduleStem(item,side,when,offset=0){const src=state.context.createBufferSource();src.buffer=state.bufferList[item+10*side],src.playbackRate.value=state.playbackFactor[item],src.connect(state.gainNode[item]),state.bWAVEVISUALIZER&&state.stemAnalyser[item]&&src.connect(state.stemAnalyser[item]),src.onended=()=>{try{src.disconnect()}catch(e){}src.onended=null},src.start(when,offset),0===side?state.sourceA[item]=src:state.sourceB[item]=src}function scheduleA(item,when,offset){scheduleStem(item,0,when,offset)}function scheduleB(item,when,offset){scheduleStem(item,1,when,offset)}function playAllSounds(){for(let i=0;i<10;i++)startWebAudio(i)}function startWebAudio(i){const wallNow=Date.now(),nextBeat=Math.ceil(wallNow/1e3)*1e3,startTime=state.context.currentTime+(nextBeat-wallNow)/1e3;if(0===state.stretch[i])return state.sourceA[i].loop=1,state.sourceB[i].loop=1,state.sourceB[i].playbackRate.value=state.playbackFactor[i],state.sourceA[i].start(startTime),void state.sourceB[i].start(startTime);state.nextA[i]=startTime,state.nextB[i]=startTime+halfPeriod(i),scheduleA(i,state.nextA[i]),state.nextA[i]+=state.interval[i],scheduleB(i,state.nextB[i]),state.nextB[i]+=state.interval[i]}function restartWebAudio(i){const fadeTime=.05,now=state.context.currentTime,originalGain=levelToGain(state.currentLevel[i]);state.gainNode[i].gain.cancelScheduledValues(now),state.gainNode[i].gain.setValueAtTime(state.gainNode[i].gain.value,now),state.gainNode[i].gain.linearRampToValueAtTime(0,now+fadeTime),setTimeout(()=>{try{state.sourceA[i].onended=null}catch(e){}try{state.sourceB[i].onended=null}catch(e){}try{state.sourceA[i].disconnect()}catch(e){}try{state.sourceB[i].disconnect()}catch(e){}if(0===state.stretch[i])for(const side of[0,1]){const src=makeSource(state.bufferList[i+10*side],state.playbackFactor[i]);src.loop=1,src.connect(state.gainNode[i]),src.start(0),0===side?state.sourceA[i]=src:state.sourceB[i]=src}else{const restartTime=Math.ceil(state.context.currentTime+.05);state.nextA[i]=restartTime,state.nextB[i]=restartTime+halfPeriod(i)}const resumeTime=state.context.currentTime;state.gainNode[i].gain.setValueAtTime(0,resumeTime),state.gainNode[i].gain.linearRampToValueAtTime(originalGain,resumeTime+fadeTime)},1e3*fadeTime)}function setPlaybackFactors(){computeIntervals();for(let i=0;i<10;i++)restartWebAudio(i)}function playOneShot(stem){state.playbackFactor[stem]=state.pitchTable[Math.floor(Math.random()*state.pitchTable.length)];let side,duration;return state.lastPlayedOS[stem]?(scheduleB(stem,state.context.currentTime),duration=state.sourceB[stem].buffer.duration,side="a"):(scheduleA(stem,state.context.currentTime),duration=state.sourceA[stem].buffer.duration,side="b"),state.lastPlayedOS[stem]=1-state.lastPlayedOS[stem],{side:side,duration:1e3*duration/state.playbackFactor[stem]}}function toggleMute(){state.bMUTE=!state.bMUTE,state.bMUTE?(0==state.iTimer?fadeOut(1,30):fadeOut(1,.5),state.iMTimer>0&&setMeditationBell(0),updateButtons(),stopScheduler(),msg("paused")):(0==state.iTimer?fadeOut(0,15):fadeOut(0,1),updateButtons(),resumeContext(),updatefftData(),startScheduler(),msg("playing")),0==state.iTimer&&(state.iTimer=-1),updateDocumentLinks()}function updateButtons(){qs("#playBtn").textContent=state.bMUTE?"play":"pause",qs("#animBtn").classList.toggle("active",!!state.bANIMATE)}function fadeOut(out,duration_s){let target=0;0==out&&(target=state.fMASTERGAIN),state.bANIMATE&&1==out&&clearTimeout(state.modulationTimeout),fadeMaster(target,duration_s,()=>{1==out?suspendEngine():(startScheduler(),state.bANIMATE&&modulationRandom())})}function resumeContext(){resumeAudioContext(!0),startScheduler(),state.bANIMATIONONSTART&&(startModulation(),state.bANIMATIONONSTART=0),msg("playing")}function applyAutoplayPolicy(){msg("click play if browser suspended audio"),"suspended"==audioContextState()?(suspendAudioContext(),state.bSUSPENDED=1):nowPlaying()}function nowPlaying(){msg("ready"),updateButtons()}function progressDots(done,percent,remaining,unknown){return`${"•".repeat(done)} ${percent}% ${"•".repeat(Math.max(0,remaining))}${void 0===unknown?"":" "+"•".repeat(Math.max(0,unknown))}`}function showLoadProgress(loaded,grand,server){const loadedMB=Math.floor(loaded/1048576),grandMB=Math.floor(grand/1048576),serverMB=Math.floor(server/1048576),percent=server?Math.round(100*loaded/server):0;msg("loading audio "+progressDots(loadedMB,percent,grandMB-loadedMB,serverMB-grandMB))}function showDecodeProgress(count){20==count?finishedLoading():msg("preparing channels "+progressDots(count,Math.round(count/20*100),20-count))}function playBell(volume=1){state.meditationBell&&state.meditationBell.paused&&!state.bMUTE&&(state.meditationBell.volume=Math.min(1,Math.max(.1,2*state.smoothedMasterLevel*volume)),duckAudio(.66,.001),setTimeout(()=>{state.meditationBell.onended=()=>unduckAudio(10),state.meditationBell.play().catch(()=>unduckAudio(10))},1))}function playOS(stem){const played=playOneShot(stem);msg(`${bands[stem]} · ${played.side} · ${state.playbackFactor[stem].toFixed(3)}`),clearTimeout(state.timeOutOS[stem]),state.timeOutOS[stem]=setTimeout(()=>{state.bOSAUTO&&playOS(Math.floor(10*Math.random()))},played.duration)}function setStereoWidth(widthFactor){state.fSTEREOWIDTH=widthFactor,updateDocumentLinks(),setWidthGains(widthFactor),msg("stereo width "+Math.round(100*widthFactor)+"%")}function userSettingsCookieName(){return state.uIDS?"uSET_"+state.uIDS:"uSET_unlogged"}function readUserSettings(){const tmp=readCookie(userSettingsCookieName());return null!=tmp?JSON.parse(tmp):{}}function writeUserSettings(userData){createCookie(userSettingsCookieName(),JSON.stringify(userData),36500)}function initTuning(){for(let i=0;i<10;i++)state.playbackFactor[i]=1;const args=getUrlVars();void 0!==args.d&&(state.detune=args.d.replace(/(?!^-)[^0-9.]/g,"")),computePlaybackFactorsFromDetune()}function computePlaybackFactorsFromDetune(){const isScalar=state.detune<999;for(let i=0;i<10;i++)if(isScalar)state.playbackFactor[i]=Math.pow(2,state.detune/12);else{const step=parseInt(state.detune.toString().substring(2*i,2*i+2))-50;state.playbackFactor[i]=Math.pow(2,step/12)}}function updatePlaybackRate(){computePlaybackFactorsFromDetune(),setPlaybackFactors()}function tune(factor,bRelative=!1){if(bRelative){const currentFactor=Math.pow(2,state.detune/12);factor=currentFactor*factor}state.detune=Math.round(12*Math.log2(factor)*1e3)/1e3,updatePlaybackRate(),updateDocumentLinks(),msg("now playing at "+Math.round(100*factor)/100+"x speed")}function transposeDetune(amount,limitMin,limitMax){const str=state.detune.toString();if(str.length<4){const newValue=parseFloat(state.detune)+amount;newValue>=limitMin&&newValue<=limitMax?(state.detune=newValue,msg(0===state.detune?"original speed":"master tape "+Math.round(100*Math.pow(2,state.detune/12))/100+"x")):msg("no further speed change allowed")}else if(20===str.length){let nd="";for(let i=0;i<20;i+=2){const nv=parseInt(str.substring(i,i+2),10)+amount;if(!(nv>=50+limitMin&&nv<=50+limitMax))return void msg("tape speed out of range");nd+=String(nv).padStart(2,"0")}state.detune=nd}updatePlaybackRate(),updateDocumentLinks()}function tuneDown(dec){transposeDetune(-dec,-48,36)}function tuneUp(inc){transposeDetune(inc,-48,36)}function mixedTune(keyScale=null){let str="";for(let i=0;i<10;i++){let s;s=Array.isArray(keyScale)&&keyScale.length>0?keyScale[Math.floor(Math.random()*keyScale.length)]:Math.round(7*Math.random())*(Math.random()<.5?-1:1),str+=String(50+s).padStart(2,"0")}state.detune=str,updateDocumentLinks(),updatePlaybackRate(),msg("alternate tuning")}const ANIMATION_SPEEDS=[.125,.25,.5,1,2,4,8],ANIMATION_MODES=["s","h","i","d","t","q"];function cycleValue(entries,current){const idx=entries.findIndex(e=>e==current);return idx<0?current:entries[(idx+1)%entries.length]}function setAnimationSpeed(value){state.iAnimationFactor=void 0===value?cycleValue(ANIMATION_SPEEDS,state.iAnimationFactor):value,updateDocumentLinks(),msg("animation speed "+state.iAnimationFactor)}function setAnimationMode(value){state.iAnimationMode=void 0===value?cycleValue(ANIMATION_MODES,state.iAnimationMode):value,updateDocumentLinks(),msg("animation mode "+state.iAnimationMode)}function setAnimationProfile(type){state.bANIMATIONUSERPROFILESET=1,"lo"==type&&(state.animationProfileLow=state.currentLevel.slice(0),msg("saved low bound")),"hi"==type&&(state.animationProfileHigh=state.currentLevel.slice(0),msg("saved high bound")),updateDocumentLinks()}function loadAnimationProfile(type){"lo"==type&&(state.currentLevel=state.animationProfileLow.slice(0),msg("low profile")),"hi"==type&&(state.currentLevel=state.animationProfileHigh.slice(0),msg("high profile")),setCurrentLevelsToSliders()}function deriveAnimationProfile(){for(let i=0;i<10;i++)state.animationProfileHigh[i]=Math.min(1.25*state.currentLevel[i],.99),state.animationProfileLow[i]=.5*state.currentLevel[i]}function toggleModulation(noMsg){if(state.bANIMATE=!state.bANIMATE,state.bANIMATE){state.bANIMATIONUSERPROFILESET||(deriveAnimationProfile(),(()=>{let sum=0;for(let i=0;i<10;i++)sum+=state.currentLevel[i];if(0==sum)for(let i=0;i<10;i++)state.animationProfileHigh[i]=1.25*state.fTARGETSLIDERLEVEL})()),state.savedLevel=state.currentLevel.slice(0),state.savedCurrentLevel=state.currentLevel.slice(0),state.nzSliderIndex=[],state.mmMin=1,state.mmMax=0;for(let i=0;i<10;i++)state.savedLevel[i]>0&&(state.savedLevel[i]<state.mmMin&&(state.mmMin=state.savedLevel[i]),state.savedLevel[i]>state.mmMax&&(state.mmMax=state.savedLevel[i]),state.nzSliderIndex.push(i));updateButtons(),modulationRandom()}else clearTimeout(state.modulationTimeout),updateButtons(),setCurrentLevelsToSliders(),state.randomCounter=0;1!=noMsg&&msg(state.bANIMATE?"motion engaged":"motion stopped"),updateDocumentLinks()}function startModulation(){state.bANIMATE||toggleModulation(1)}function getRandomIndices(count,eligible){count=Math.min(count,eligible.length);const copy=eligible.slice();for(let i=copy.length-1;i>copy.length-1-count;i--){const j=Math.floor(Math.random()*(i+1));[copy[i],copy[j]]=[copy[j],copy[i]]}return copy.slice(-count)}function rotateAnimatedIndices(count,eligible){if(1===count||!Array.isArray(state.animatedIndices)||state.animatedIndices.length!==count)return getRandomIndices(count,eligible);const ni=state.animatedIndices.slice(),avail=eligible.filter(x=>!state.animatedIndices.includes(x));if(avail.length>0){const pos=Math.floor(Math.random()*count);ni[pos]=avail[Math.floor(Math.random()*avail.length)]}return ni}function drawAnimationTarget(){for(let i=0;i<10;i++)state.randomLevel[i]=state.savedLevel[i];if("s"==state.iAnimationMode)for(let i=0;i<10;i++)state.randomLevel[i]=state.animationProfileLow[i]+Math.random()*(state.animationProfileHigh[i]-state.animationProfileLow[i]);if("h"==state.iAnimationMode)for(let i=0;i<10;i++)state.randomLevel[i]=Math.random()<.5?state.animationProfileHigh[i]:state.animationProfileLow[i];if(["i","d","t","q"].includes(state.iAnimationMode)){const eligible=[];for(let i=0;i<10;i++)state.animationProfileLow[i]!==state.animationProfileHigh[i]&&eligible.push(i);const count={i:1,d:2,t:3,q:4}[state.iAnimationMode];state.animatedIndices=rotateAnimatedIndices(count,eligible);for(let i=0;i<10;i++)state.randomLevel[i]=state.animatedIndices.includes(i)?Math.max(state.animationProfileLow[i],state.animationProfileHigh[i]):Math.min(state.animationProfileLow[i],state.animationProfileHigh[i])}}function modulationRandom(){state.iCurrentAnimationSpeed=state.iINITIALANIMATIONSPEED/state.iAnimationFactor;const nCycle=50;0==state.randomCounter&&(state.savedCurrentLevel=state.currentLevel.slice(0),drawAnimationTarget());for(let i=0;i<10;i++)state.selSliders[i]&&(state.currentLevel[i]=state.savedCurrentLevel[i]+state.randomCounter*(state.randomLevel[i]-state.savedCurrentLevel[i])/nCycle);setLevels(state.currentLevel,"anim"),++state.randomCounter==nCycle+1&&(state.randomCounter=0),clearTimeout(state.modulationTimeout),state.modulationTimeout=setTimeout(modulationRandom,1e3*state.iCurrentAnimationSpeed/nCycle)}function saveRandomExchange(){state.savedLevel=state.currentLevel.slice(0),state.randomLevel=state.currentLevel.slice(0),state.randomCounter=0}const TIMER_STEPS=[[1,"timer set to 1 minute"],[5,"timer set to 5 minutes"],[10,"timer set to 10 minutes"],[15,"timer set to 15 minutes"],[20,"timer set to 20 minutes"],[25,"pomodoro 25 minutes"],[30,"timer set to 30 minutes"],[60,"timer set to 1 hour"],[120,"timer set to 2 hours"],[240,"timer set to 4 hours"],[480,"timer set to 8 hours"]];function setTimer(time){if(void 0===time||isNaN(time)){state.iTimer=Math.max(0,state.iTimer-(Date.now()-state.epoch)/6e4+2);const step=TIMER_STEPS.find(s=>state.iTimer<s[0]);step?(state.iTimer=step[0],msg(step[1])):(state.iTimer=-1,msg("timer disabled"))}else 0==time?(state.iTimer=0,updateTimer()):(state.iTimer=+time,msg("timer set to "+time+" min"));state.URLtimer=-1==state.iTimer?"":"&tm="+state.iTimer,updateDocumentLinks(),qs("#timerInput").value=state.iTimer>0?state.iTimer:"",state.epoch=Date.now(),clearTimeout(state.timerTimeout),state.timerTimeout=setTimeout(updateTimer,1e4)}function updateTimer(){if(state.iTimer<0)return;const remaining=60*state.iTimer-(Date.now()-state.epoch)/1e3;remaining<=0?(state.iTimer=0,toggleMute(),qs("#timerInput").value=""):(qs("#timerInput").value=Math.ceil(remaining/60),clearTimeout(state.timerTimeout),state.timerTimeout=setTimeout(updateTimer,1e4))}const BELL_STEPS=[[1,1],[5,5],[10,10],[15,15],[20,20],[25,25],[30,30],[60,60],[99999,"5:60"]];function setMeditationBell(time){playBell(),clearTimeout(state.meditationInterval),clearTimeout(state.meditationInterval2);if(void 0===time){const step=BELL_STEPS.find(s=>state.iMTimer<s[0]);step?(state.iMTimer=step[0],time=step[1]):(state.iMTimer=-1,time=-1)}const bellInput=qs("#bellInput");if(isNaN(time)){if(time=String(time).replace("?",":").replace("-",":"),2==(parts=time.split(":")).length){if(isNaN(parts[0])||isNaN(parts[1]))return;const minTime=Math.min(parts[0],parts[1]),maxTime=Math.max(parts[0],parts[1]),nextBell=Math.round(+minTime+Math.random()*(maxTime-minTime));state.meditationInterval=setTimeout(()=>setMeditationBell(time),6e4*nextBell),msg("random bells "+minTime+" to "+maxTime+" min"),bellInput.value="r"}else{var parts;if(2==(parts=time.split("+")).length){if(isNaN(parts[0])||isNaN(parts[1]))return;const firstTime=parts[0],secondTime=parts[1],totalTime=parseFloat(firstTime)+parseFloat(secondTime);state.meditationInterval=setTimeout(()=>playBell(),6e4*firstTime),state.meditationInterval2=setTimeout(()=>setMeditationBell(time),6e4*totalTime),msg("dual session bell "+firstTime+"·"+secondTime),bellInput.value="d"}}}else state.iMTimer=+time,state.iMTimer>0?(msg(1==state.iMTimer?"bell every minute":25==state.iMTimer?"pomodoro bell":"bell every "+time+" min"),bellInput.value=state.iMTimer):(msg("bell disabled"),bellInput.value=""),state.iMTimer>0&&(state.meditationInterval=setInterval(()=>playBell(),6e4*state.iMTimer));state.URLbell=-1==time?"":"&bl="+encodeURIComponent(time),updateDocumentLinks()}function buildAnimationParams(){let seg="&a="+state.iAnimationFactor+"&am="+state.iAnimationMode;return state.bANIMATIONUSERPROFILESET&&(seg+="&apl="+packVector(state.animationProfileLow)+"&aph="+packVector(state.animationProfileHigh)),state.bANIMATE&&(seg+="&astart=1"),seg}function updateDocumentLinks(){clearTimeout(updateDocumentLinks._timer),updateDocumentLinks._timer=setTimeout(()=>{const stripped=location.origin+location.pathname;state.URLlevels="l="+packVector(state.currentLevel),state.URLanimate=buildAnimationParams(),state.URLmagic=cfg.magicParam,state.URLdetune=state.detune?"&d="+state.detune:"",void 0!==state.fSTEREOWIDTH&&1!=state.fSTEREOWIDTH&&(state.URLwidth="&w="+state.fSTEREOWIDTH),state.URLmute=state.bMUTE?"&mt=1":"",state.URLtitle="&title="+encodeURIComponent("white rain");const q=state.URLlevels+state.URLanimate+state.URLmagic+state.URLdetune+state.URLwidth+state.URLmute+state.URLbell+state.URLtimer+state.URLtitle;state.cloneURL=stripped+"?"+q+"&c=1",state.cookieURL=q.substring(2),state.appShareURL=stripped+"?"+q},10)}function saveCurrentLevelsToCookie(tag){tag=void 0===tag?"CAL":tag;const userData=readUserSettings();userData[tag]=state.cookieURL,writeUserSettings(userData),"CAL"!=tag&&msg("saved in browser")}function loadCurrentLevelsFromCookieAndSetSliders(tag){tag=void 0===tag?"CAL":tag;const userData=readUserSettings();null!=userData[tag]?(loadURLsettings(getUrlVars("?l="+userData[tag]),!1),initTuning(),updatePlaybackRate(),msg("CAL"==tag?"your personal curve":"loaded custom settings")):msg("CAL"==tag?"no calibration found":"no user setting found")}function loadURLsettings(args,bNormalizeLevels=!0){if(void 0!==args.l&&(unpackVector(args.l,state.currentLevel),bNormalizeLevels&&(state.currentLevel=normalizeLevels(state.currentLevel)),setCurrentLevelsToSliders()),void 0!==args.apl&&(unpackVector(args.apl,state.animationProfileLow),state.bANIMATIONUSERPROFILESET=1),void 0!==args.aph&&(unpackVector(args.aph,state.animationProfileHigh),state.bANIMATIONUSERPROFILESET=1),void 0!==args.a&&setAnimationSpeed(+args.a),void 0!==args.am&&setAnimationMode(args.am),void 0!==args.astart&&1==args.astart&&2!=cfg.custom&&(state.bANIMATIONONSTART=1),void 0!==args.d&&(state.detune=args.d,state.bFINISHEDLOADING&&updatePlaybackRate()),void 0!==args.tm){const minutes=parseInt(args.tm,10);isNaN(minutes)||setTimer(minutes)}if(void 0!==args.bl){const minutes=decodeURIComponent(args.bl);(minutes>0||"string"==typeof minutes&&minutes.includes(":"))&&setMeditationBell(minutes)}if(void 0!==args.mt&&1===parseInt(args.mt,10)&&toggleMute(),void 0!==args.w){const width=parseFloat(args.w);isNaN(width)||setStereoWidth(width)}}function waveVisualizer(){if(state.bWAVEVISUALIZER=1-state.bWAVEVISUALIZER,state.bWAVEVISUALIZER){msg("visualizer on");for(let i=0;i<10;i++){const created=!state.stemAnalyser[i],a=stemAnalyserFor(i);created&&0===i&&(state.samplesArray=new Uint8Array(a.frequencyBinCount))}connectStemAnalysers(!0)}else msg("visualizer off"),connectStemAnalysers(!1)}function startVisualizer(){state.fftCanvas=qs("#fft"),state.fftCtx=state.fftCanvas.getContext("2d"),attachMasterAnalyser(),state.fftData=new Float32Array(state.analyser.frequencyBinCount),state.visualizerStartedAt=performance.now(),updatefftData()}function updatefftData(){if(!state.bMUTE&&setTimeout(()=>requestAnimationFrame(updatefftData),100),state.bMUTE||!state.analyser)return;state.analyser.getFloatFrequencyData(state.fftData),state.bLEVELHISTORYINIT||(state.levelHistory=Array(state.levelHistorySize).fill(.3),state.bLEVELHISTORYINIT=!0);let weighted=0;for(let j=0;j<state.fftData.length&&j<state.aWeighting.length;j++)weighted+=Math.pow(10,state.fftData[j]/20)*state.aWeighting[j];const instant=20*weighted;state.levelHistory[state.levelHistoryIndex]=instant,state.levelHistoryIndex=(state.levelHistoryIndex+1)%state.levelHistorySize;let sum=0;for(let j=0;j<state.levelHistorySize;j++)sum+=state.levelHistory[j];state.smoothedMasterLevel=sum/state.levelHistorySize,state.pos[0]=(state.fftData[0]+75)/2,state.pos[1]=(Math.max(state.fftData[2],state.fftData[3])+77)/2,state.pos[2]=(Math.max(state.fftData[5],state.fftData[6],state.fftData[7])+81)/2,state.pos[3]=(Math.max(state.fftData[9],state.fftData[10],state.fftData[11],state.fftData[12],state.fftData[13],state.fftData[14],state.fftData[15])+89)/2;let gr=compressorReduction();performance.now()-state.visualizerStartedAt<2e3&&(gr=0);let t=gr/6;t=t<0?0:t>1?1:t;const ctx=state.fftCtx,c=state.fftCanvas,color=`rgba(255,255,255,${(.18+.82*t).toFixed(3)})`;ctx.clearRect(0,0,c.width,c.height),ctx.beginPath(),ctx.rect(0,0,c.width,c.height),ctx.fillStyle=color,ctx.fill(),ctx.closePath();const order=[3,1,0,2];for(let j=0;j<4;j++){const i=order[j];state.pos[i]>state.posOld[i]?state.posOld[i]=state.pos[i]:state.posOld[i]--,state.posOld[i]<0&&(state.posOld[i]=0),state.posOld[i]>15&&(state.posOld[i]=15);const h=1.6*state.posOld[i],x=18+22*j,y=c.height-h-6,w=10,rad=3;ctx.beginPath(),"function"==typeof ctx.roundRect?ctx.roundRect(x,y,w,h,rad):ctx.rect(x,y,w,h),ctx.fillStyle="#fff",ctx.fill(),ctx.closePath()}qs("#stateTxt").textContent=state.bMUTE?"paused":"playing"}function finishedLoading(){buildAudioGraph(),computeIntervals(),getCurrentLevelsFromSliders(),playAllSounds(),setAllLevels(),startScheduler(),state.bFINISHEDLOADING=1,startVisualizer(),loadURLsettings(getUrlVars(),!1),qs("#bg").style.backgroundImage="url(./bg.jpg)",updateDocumentLinks(),applyAutoplayPolicy()}function init(){createAudioContext()?(initTuning(),msg("loading audio"),assignSources(),loadAllSounds(showLoadProgress,showDecodeProgress),setPreset(...defaultLevels()),state.bANIMATIONUSERPROFILESET||deriveAnimationProfile()):msg("web audio api not found")}function bindUi(){for(let i=0;i<10;i++)slider(i).addEventListener("input",e=>{state.bFINISHEDLOADING&&(state.movedSlider=String(i),setLevel(i,parseFloat(e.target.value),"user")),updateDocumentLinks()}),qs("#os"+i).addEventListener("click",()=>state.bFINISHEDLOADING&&playOS(i)),slider(i).style.color=colors[i];qs("#playBtn").onclick=()=>state.bFINISHEDLOADING?toggleMute():resumeContext(),qs("#resetBtn").onclick=resetSliders,qs("#downBtn").onclick=slidersDown,qs("#upBtn").onclick=slidersUp,qs("#animBtn").onclick=()=>toggleModulation(),qs("#bellBtn").onclick=()=>setMeditationBell(qs("#bellInput").value||void 0),qs("#timerBtn").onclick=()=>setTimer(qs("#timerInput").value||void 0),qs("#bellInput").addEventListener("keydown",e=>{"Enter"===e.key&&setMeditationBell(qs("#bellInput").value)}),qs("#timerInput").addEventListener("keydown",e=>{"Enter"===e.key&&setTimer(qs("#timerInput").value)}),qsa("[data-preset]").forEach(el=>el.onclick=()=>setPreset(...presets[+el.dataset.preset][1],presets[+el.dataset.preset][0])),qsa("[data-width]").forEach(el=>el.onclick=()=>setStereoWidth(parseFloat(el.dataset.width))),qsa("[data-tune]").forEach(el=>el.onclick=()=>tune(parseFloat(el.dataset.tune))),qs("#slowerBtn").onclick=()=>tuneDown(1),qs("#fasterBtn").onclick=()=>tuneUp(1),qs("#alternateBtn").onclick=()=>mixedTune(),qsa("[data-am]").forEach(el=>el.onclick=()=>setAnimationMode(el.dataset.am)),qsa("[data-as]").forEach(el=>el.onclick=()=>setAnimationSpeed(parseFloat(el.dataset.as))),qs("#setLoBtn").onclick=()=>setAnimationProfile("lo"),qs("#loadLoBtn").onclick=()=>loadAnimationProfile("lo"),qs("#setHiBtn").onclick=()=>setAnimationProfile("hi"),qs("#loadHiBtn").onclick=()=>loadAnimationProfile("hi"),qs("#saveUrlBtn").onclick=async()=>{updateDocumentLinks(),await navigator.clipboard.writeText(state.cloneURL),msg("link copied")},qs("#saveCookieBtn").onclick=()=>saveCurrentLevelsToCookie("RAIN2"),qs("#loadCookieBtn").onclick=()=>loadCurrentLevelsFromCookieAndSetSliders("RAIN2"),qs("#miniBtn").onclick=()=>{updateDocumentLinks(),window.open(state.cloneURL,"_blank")},qs("#qrBtn").onclick=()=>{updateDocumentLinks(),navigator.clipboard.writeText(state.appShareURL),msg("app url copied")},addEventListener("keydown",e=>{if(["INPUT","TEXTAREA"].includes(document.activeElement.tagName))return;const k=e.key.toLowerCase();"p"===k||"Space"===e.code?(e.preventDefault(),toggleMute()):"r"===k?resetSliders():"a"===k?toggleModulation():"j"===k?slidersDown():"k"===k?slidersUp():"t"===k?setTimer():"l"===k?setMeditationBell():"v"===k?waveVisualizer():"w"===k?setPreset(.18,.21,.24,.27,.3,.34,.38,.42,.46,.5,"white"):"n"===k?setPreset(.3,.3,.3,.3,.3,.3,.3,.3,.3,.3,"pink"):"b"===k?setPreset(.5,.46,.42,.38,.34,.3,.27,.24,.21,.18,"brown"):"z"===k?setPreset(0,0,0,0,0,0,0,0,0,0,"zeroed"):"o"===k?(state.bMUTE?setTimer(5):setTimer(25),msg("pomodoro timer set")):"?"===k?randomSettings():"y"===k&&(tune(432/440,!0),msg("tuned to a4=432hz"))})}bindUi(),init();</script></body></html>
|