<!DOCTYPE html>
<!--
Author: Twily 2015 - 2025
Website: http://twily.info/
AI Generated music album, (no lora), using MusicGen from
hugginface run locally on home computer for experimenting.
Delivered in a very nostalgic inspired Winamp, (re)designed
by myself. Help from grok to setup visualizer and equalizer.
-->
<html>
<head>
<title>Twily AI Music</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name='viewport' content='width=device-width,initial-scale=1'>
<!--<link id="favicon" rel="shortcut icon" href="http://twily.info/favicon.ico" />-->
<!--<link rel="stylesheet" type="text/css" href="./css/style.css?v=1" />-->
<style type="text/css">
html,body {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: auto;
font-family: "Droid Sans", "Liberation Sans", "DejaVu Sans", "Segoe UI", Sans;
font-size: 12pt; font-weight: bold;
background: #02161c; color: #AAABAD;
user-select: none;
/*overflow-x: hidden;
overflow-Y: auto;*/
overflow: hidden;
}
* {
box-sizing: border-box;
/* Firefox and modern browsers */
scrollbar-color: #525793 #1A224B;
scrollbar-width: 8px;
/* WebKit-based browsers */
&::-webkit-scrollbar {
width: 8px;
background-color: #1A224B; /* no change */
}
&::-webkit-scrollbar-track {
background-color: #1A224B; /* back */
border-radius: 1px;
}
&::-webkit-scrollbar-thumb {
background-color: #525793; /* drag */
border-radius: 1px;
&:hover {
background-color: #7D80AA; /* no effect */
}
}
}
*:focus { outline: none !important; }
a:link, a:visited { color: #606163; text-decoration: none; }
a:hover, a:active { color: #0f0; }
a.red:hover, a.red:active { color: #f06 !important; }
a.blue:hover, a.blue:active { color: #06f !important; }
#log {
position: fixed; top: 0; left: 0;
background: #111;
color: #f02;
border: 2px solid #600;
padding: 8px;
z-index: 1000000;
pointer-events: none;
display: none /*inline-block*/;
}
.tbl { display: table; width: 100%; }
.tr { display: table-row; }
.td { display: table-cell; vertical-align: middle; /*border: 1px solid transparent; box-shadow: inset 0 0 2px 2px #000;*/ }
.sidebar { width: 28px; min-width: 28px; }
/*
#wrap { width: 100%; height: 100%; display: flex; position: absolute; z-index: 9; }
#wrap #box { padding: 128px; background: #111113; margin: auto; display: inline-block; position: relative; }*/
.brd { border-top: 1px solid #620; }
.frm {
width: 100%; height: 100%;
position: relative;
margin: 0; padding: 0;
}
#backdrop {
position: fixed; top: 0; left: 0; z-index: 1;
width: 100%; height: 100%;
}
#above {
position: absolute; top: 0; left: 0; z-index: 10000;
width: 100%; height: 100%;
}
#backlay {
position: fixed; top: 0; left: 0; z-index: 2;
width: 100%; height: 100%;
background: transparent;
background: radial-gradient(ellipse at 50%, rgba(26,72,68,.25), rgba(44,53,70,.25) 50%, transparent 100%);
/*background: radial-gradient(ellipse at 50%, transparent, rgba(35,52,84,.25) 50%, rgba(52,112,114,.25) 100%);*/
opacity: 1;
}
#lcd_cont {
position: fixed; top: 0; left: 0;
z-index: 5000;
width: 100%; height: 100%;
background: transparent;
pointer-events: none;
opacity: 0; /* start hidden with ship */
visibility: hidden;
}
#lcd_frm {
width: 0;
height: 0;
position: absolute;
/*top: 443px; left: 50px;*/
top: 200px; left: 50%; margin-left: -215px;
/*top: 50%; left: 50%;
margin-left: -212px;
margin-top: -344px;*/
transform: perspective(300px) rotateX(-3deg) scale(1);
}
.td label:nth-child(1) {
margin-right: 10px;
}
.playing.selected::before {
content: "►";
/*content: "♬"▶;*/
}
.track.selected {
color: #0f8;
}
#triangle.on::before, #triangleMini.on::before {
font-size: 22pt; color: #0f0;
content: "►";
position: absolute; z-index: 100;
}
.pad18 {
padding: 4px;
}
#player_frm {
width: 100%;
/*min-height: 443px;*/
}
#player {
border: 1px solid #620;
border-radius: 2px;
width: 100%;
max-width: 602px;
text-align: left;
box-shadow: 0 0 600px #00f9cb36;
position: relative;
z-index: 10;
}
.btn {
border-right: 1px solid #2f303c;
border-bottom: 1px solid #2f303c;
border-left: 1px solid #747cd3;
border-top: 1px solid #747cd3;
background: #525793;
color: #0f0;
-webkit-appearance: none; border-radius: 2px; cursor: pointer;
}
.btn:hover {
background: #5f5ea9;
}
.btn:active, .btn.tog {
border-top: 1px solid #2f303c;
border-left: 1px solid #2f303c;
border-right: 1px solid #747cd3;
border-bottom: 1px solid #747cd3;
background: #3e4270;
}
#bar {
/*position: fixed; bottom: 0; left: 0;*/
display: block; height: 7px; width: 100%;
background: #525793;
background: linear-gradient(0deg, #2d3a7e, #4d2f95);
border-top: 1px solid #2f303c;
border-left: 1px solid #2f303c;
border-right: 1px solid #747cd3;
border-bottom: 1px solid #747cd3;
}
#progress {
display: block; height: 100%; width: 0%;
background: #0f0;
background: linear-gradient(0deg, #01af01, #00ff2c);
}
#lbloop { display: none; }
#lbshuf { display: none; }
.center { text-align: center; }
.grey {
padding-left: 6px;
color: #666;
font-size: 8pt;
font-family: monospace;
}
#vol {
/*position: fixed; bottom: 0; left: 0;*/
display: inline-block; height: 7px; width: 100px;
background: #525793;
background: linear-gradient(0deg, #2d3a7e, #4d2f95);
border-top: 1px solid #2f303c;
border-left: 1px solid #2f303c;
border-right: 1px solid #747cd3;
border-bottom: 1px solid #747cd3;
}
#level {
display: block; height: 100%; width: 100%;
background: #0f0;
background: linear-gradient(0deg, #01af01, #00ff2c);
}
.eqbar {
/*position: fixed; bottom: 0; left: 0;*/
position: relative;
display: inline-block; height: 60px; width: 7px;
background: #525793;
background: linear-gradient(270deg, #2d3a7e, #4d2f95);
border-top: 1px solid #2f303c;
border-left: 1px solid #2f303c;
border-right: 1px solid #747cd3;
border-bottom: 1px solid #747cd3;
}
.eqlevel {
position: absolute; bottom: 0;
display: block; height: 100%; width: 100%;
background: #0f0;
background: linear-gradient(270deg, #01af01, #00ff2c);
}
#eq0 { height: 50%; }
#eq1 { height: 50%; }
#eq2 { height: 50%; }
#eq3 { height: 50%; }
#eq4 { height: 50%; }
#eq5 { height: 50%; }
#eq6 { height: 50%; }
#eq7 { height: 50%; }
#eq8 { height: 50%; }
#eq9 { height: 50%; }
#loliadd {
position: fixed;
top: 0;
right: 0;
z-index: 10025;
width: 32px;
height: 36px;
border-bottom-left-radius: 36px;
background: transparent;
/*box-shadow: 0 0 5px #621F33*/;
opacity: 0.8;
cursor: pointer;
transition: .5s ease;
}
#loli_frm {
position: fixed; top: 0; left: 0;
z-index: 10024;
width: 100%; height: 100%;
pointer-events: none;
background: transparent;
}
.lolion { background: rgba(255,124,197,.3) !important; }
.lolion.blue { background: rgba(124,105,255,.3) !important; }
.lolion.grey { background: rgba(97,97,97,.3) !important; }
#displayMini_cont {
position: fixed; top: 28px; left: 28px;
width: 142px; height: 82px;
display: none;
z-index: 10025;
}
#display, #displayMini {
display: block;
background: #1f1f1f;
border: 1px solid #363; border-radius: 2px;
width:100%; height: 100%;
position: relative;
}
#displayMini {
border-radius: 10px;
background: transparent;
user-select: none;
}
#time, #timeMini {
font-size: 22pt;
font-family: monospace;
color: #0f0; /*background: #333;*/
float: right;
padding: 4px;
position: relative; z-index: 100;
}
#title {
background: #06070a;
color: #0f0;
border: 1px solid #026; border-radius: 2px;
/*position: relative;*/
}
#inner {
display: inline-block;
}
#visualizer, #visualizerMini {
background: transparent;
width: 100%; height: 69%;
position: absolute; bottom: 0;
z-index: 1;
}
#visualizerMini {
border-radius: 10px;
}
#spaceship {
position: fixed; top: 0; left: 0;
width: 100%; height: 100%;
/*background: url('./spaceship.png') no-repeat center center transparent;
background-size: cover;*/
background: transparent;
visibility: hidden;
opacity: 0; /* start hidden - preload async */
z-index: 5;
/*filter: sepia(.8) brightness(2) contrast(1.2);*/ /* sunshine */
/*filter: brightness(.8) contrast(1.1);*/ /* dimlights */
}
#spaceship_sun {
position: fixed; top: 0; left: 0;
width: 100%; height: 100%;
/*background: url('./spaceship.png') no-repeat center center transparent;
background-size: cover;*/
background: transparent;
visibility: hidden;
opacity: 0; /* start hidden - preload async */
z-index: 6;
/*filter: sepia(.8) brightness(2) contrast(1.2);*/ /* sunshine */
/*filter: brightness(.8) contrast(1.1);*/ /* dimlights */
/* do these transition steps with js with theta from mg1 camera orbit
/* light from right to left - entering light mode */
/* fully dark */
mask-image: linear-gradient(90deg, transparent 100%, black 110%);
-webkit-mask-image: linear-gradient(90deg, transparent 100%, black 110%);
/* fully light */
/*mask-image: linear-gradient(90deg, transparent -10%, black 0%);
-webkit-mask-image: linear-gradient(90deg, transparent -10%, black 0%);*/
/* light from left to right - leaving light mode */
/* fully light */
/*mask-image: linear-gradient(90deg, black 100%, transparent 110%);
-webkit-mask-image: linear-gradient(90deg, black 100%, transparent 110%);*/
/* fully dark */
/*mask-image: linear-gradient(90deg, black -10%, transparent 0%);
-webkit-mask-image: linear-gradient(90deg, black -10%, transparent 0%);*/
display: none;
}
.lnkbtn {
padding: 8px;
border: 1px solid #aaa;
border-radius: 10px;
}
/*#btn_ship { margin-right: 28px; }
#btn_dir { margin-left: 28px; }*/
#btn_ship { position: fixed; bottom: 28px; right: 28px; }
#btn_full { position: relative; top: 22px; border: 1px solid transparent; transition: border 1s ease-in; }
#btn_dir { position: fixed; bottom: 28px; left: 28px; }
#btn_fot { position: fixed; bottom: 28px; left: 50%; margin-left: -150px; border: 1px solid transparent; transition: border 1s ease-in; }
#footer_c, #title_c {
/*visibility: visible;*/
opacity: 1;
transition: opacity 1s ease-out;
user-select: none;
}
#footer_swap, #title_swap {
/*visibility: visible;*/
opacity: 0;
transition: opacity 1s ease-in;
user-select: none;
}
#btn_fot:hover #footer_c, #btn_fot:active #footer_c { opacity: 0; }
#btn_fot:hover #footer_swap, #btn_fot:active #footer_swap { opacity: 1; }
#btn_fot:hover { border: 1px solid #aaa; }
#btn_full:hover #title_c, #btn_full:active #title_c { opacity: 0; }
#btn_full:hover #title_swap, #btn_full:active #title_swap { opacity: 1; }
#btn_full:hover { border: 1px solid #aaa; }
#mg1_tim {
display: none;
position: fixed;
left: 28px;
bottom: 28px;
color: #666;
}
#listfrm {
/*max-height: 256px;*/
height: 100%;
overflow-x: hidden;
overflow-y: auto;
/*resize: vertical;*/
}
#resizeFrm {
height: 184px;
min-height: 90px;
/*min-width: 600px;*/
min-width: 240px;
position: relative;
}
.custom-resize-handle {
width: 10px;
height: 10px;
background-color: transparent;
border-left: 5px solid transparent;
/*border-top: 5px solid #0f0;*/
border-bottom: 5px solid #525793;
cursor: nwse-resize;
position: absolute;
bottom: 0;
right: 0;
}
</style>
<!--<script type="text/javascript" src="./js/main.js?v=1"></script>-->
<script type="text/javascript">
var $=function(id) { return document.getElementById(id); };
var lerp=function(a,b,t) { return a + t * ( b - a ) };
var clamp=function(val,min,max,) { return Math.min(Math.max(val,min), max) };
var playing=false;
var idxPlaying=1;
var idxText="1. ";
var volume=100;
var idxCurrentTime=0;
var idxDuration=0;
function playpause() {
if(!playing) {
play(idxPlaying);
} else {
clearplay();
}
}
function prev() {
var elms=$('player').getElementsByClassName('playing');
if(loopon) {
play(idxPlaying);
return;
}
if(idxCurrentTime>1) {
// rewind song
play(idxPlaying);
} else {
if(idxPlaying-1 <= 0) {
// rewind list
play(elms.length);
} else {
// prev
play(idxPlaying-1);
}
}
}
function rndMinMax(min,max) { // min and max included
return Math.floor(Math.random()*(max-min+1)+min);
}
function next() {
var elms=$('player').getElementsByClassName('playing');
if(loopon) {
play(idxPlaying);
return;
}
if(idxPlaying-1 >= elms.length-1) {
// rewind
play(1);
} else {
// next
play(idxPlaying+1);
}
}
var shufindexes=[];
function rearrangelist(firstload=0) {
var tracks=[];
var cidxPlaying=localtracks[0];
if(shufon) {
cidxPlaying=localtracks[((idxPlaying-1)*2)]; // multidim array
//console.log("from normal cidxPlaying: Track"+cidxPlaying);
shufindexes=[]; // clear
var tmptracks=JSON.parse(JSON.stringify(localtracks)); // make copy
var maxtries=100+tmptracks.length;
var rndnum=0;
while(tmptracks.length>0 && maxtries>0) {
if(tmptracks.length>1) {
rndnum=rndMinMax(0,Math.floor((tmptracks.length-1)/2)); // -1 is vital
rndnum*=2; // multidim array
} else {
rndnum=0;
}
tracks.push(tmptracks[rndnum]);
tracks.push(tmptracks[(rndnum+1)]);
if(tmptracks[rndnum]==cidxPlaying) {
idxPlaying=Math.floor(tracks.length/2); // multidim arr
}
//console.log("push "+tmptracks[rndnum]);
//console.log("push "+tmptracks[(rndnum+1)]);
//console.log("splice "+rndnum+" "+(rndnum+1));
shufindexes.push(tmptracks[rndnum]);
tmptracks.splice(rndnum,2); // multidim array
maxtries--;
}
if(maxtries==0) {
console.log("rearrange list shufon maxtries exceeded");
}
} else {
tracks=localtracks; // ref is fine
cidxPlaying=shufindexes[(idxPlaying-1)]; // multidim array
//console.log("from shuffle cidxPlaying: Track"+cidxPlaying);
for(let i=0;i<tracks.length;i+=2) {
if(tracks[i]==cidxPlaying) {
idxPlaying=Math.floor(i/2)+1; // multidim arr
}
}
}
//console.dir(tracks);
$('listfrm').innerHTML="";
var c=0;
var playmins=0;
var playsecs=0;
var maxtry=0;
var html="";
for(var i=0;i<tracks.length;i+=2) {
c++;
let t=tracks[i];
let secs=tracks[i+1];
playsecs+=secs;
var playingstr="";
//if(c==1) {
// playingstr=" selected";
//}
maxtry=1000;
var mins=0;
while(secs>=60 && maxtry>0) {
secs-=60;
mins++;
maxtry--;
//console.log('maxtry1: '+maxtry);
}
html="<a href=\"javascript:play("+c+");\" class=\"track\" id=\"aud"+c+"\">";
html+="<div class=\"tbl\">";
html+="<div class=\"tr\">";
html+="<div class=\"td\" style=\"width: 24px;\">";
html+="<span class=\"playing"+playingstr+"\">";
html+="</div>";
html+="<div class=\"td\" style=\"width: 48px;\">";
html+="#"+c+"";
html+="</div>";
html+="<div class=\"td\">";
html+="Track"+t+"";
html+="</div>";
html+="<div class=\"td\" style=\"width: 50px;\">";
html+=""+mins+":"+secs+"";
html+="</div>\n";
html+="</div>";
html+="</div>";
html+="<input type=\"hidden\" class=\"mp3name\" value=\""+t+"\" />";
html+="</a>\n\n";
$('listfrm').insertAdjacentHTML('beforeend',html);
}
if(firstload==1) {
maxtry=1000;
while(playsecs>60 && maxtry>0) {
playmins++;
playsecs-=60;
maxtry--;
//console.log('maxtry2: '+maxtry);
}
$('runtime').innerHTML="";
$('runtime').insertAdjacentHTML('beforeend',playmins+" min "+playsecs+" sec");
} else {
$('lcd_frm').contentWindow.postMessage(['new_text',idxPlaying+'. Track'+t],'*');
}
if(playing) {
highlightplaying(idxPlaying);
//console.log(idxPlaying);
}
}
var shufon=false;
function shuftog() {
shufon=!shufon;
if(shufon) {
if(loopon) {
looptog();
}
$('lbshuf').style.display="inline-block";
$('btnshuftog').className="btn tog";
} else {
$('lbshuf').style.display="none";
$('btnshuftog').className="btn";
}
rearrangelist();
}
var loopon=false;
function looptog() {
loopon=!loopon;
if(loopon) {
if(shufon) {
shuftog();
}
$('lbloop').style.display="inline-block";
$('btnlooptog').className="btn tog";
} else {
$('lbloop').style.display="none";
$('btnlooptog').className="btn";
}
}
var eqon=false;
function eqtog() {
eqon=!eqon;
if(eqon) {
$('btneqtog').className="btn tog";
$('eqfrm').style.display="block";
$('eqbrd').style.border="";
} else {
$('btneqtog').className="btn";
$('eqfrm').style.display="none";
$('eqbrd').style.border="none";
}
}
var liston=false;
function listtog() {
liston=!liston;
if(liston) {
$('btnlisttog').className="btn tog";
$('listfrm').style.display="block";
$('listbrd').style.border="";
if(resizableElement.getAttribute('data-height')) {
resizableElement.style.height=resizableElement.getAttribute('data-height')+"px";
} else {
resizableElement.style.height="";
}
resizableElement.style.minHeight="";
//resizeHandle.style.display="";
$('aud'+idxPlaying).scrollIntoView({behavior: 'smooth',block: 'nearest'});
} else {
$('btnlisttog').className="btn";
$('listfrm').style.display="none";
$('listbrd').style.border="none";
resizableElement.style.height="0";
resizableElement.style.minHeight="0";
//resizeHandle.style.display="none";
}
}
// set colors here
var mColor=[ // [color1],[color2] = [inner],[outer]
//[255,0,0],[0,255,0], // red,green
//[255,255,0],[255,0,255], // yellow,pink
//[0,255,255],[0,0,255] // cyan,blue
[165,49,83],[44,53,70], // stage0 red,blue
[56,164,83],[75,75,25], // stage1 green,yellow
[26,72,68],[143,49,165] // stage2 cyan,violet
];
var mStage=0;
var mLapse=0; // 0-100, once 100 mStage++ or reset
var color1=[0,0,0];
var color2=[0,0,0];
var pos0=0;
var pos1=1;
var alpha=0.0;
var wW,wH,wH2,bH,bH2;
var bgAspect=15/10; // 16/9
var speed=1; // percentage per tick
function animloop() {
mLapse+=speed;
if(mLapse>=100) {
mLapse=0;
mStage++;
if(mStage>2) mStage=0;
//console.log("new stage = "+mStage);
}
pos0=mStage*2; // skip every other for multi array
pos1=pos0+2;
alpha=mLapse/100;
if(pos1>2*2) pos1=0;
//console.log("pos0:"+pos0+", pos1:"+pos1);
color1[0]=lerp(mColor[pos0][0],mColor[pos1][0],alpha);
color1[1]=lerp(mColor[pos0][1],mColor[pos1][1],alpha);
color1[2]=lerp(mColor[pos0][2],mColor[pos1][2],alpha);
color2[0]=lerp(mColor[pos0+1][0],mColor[pos1+1][0],alpha);
color2[1]=lerp(mColor[pos0+1][1],mColor[pos1+1][1],alpha);
color2[2]=lerp(mColor[pos0+1][2],mColor[pos1+1][2],alpha);
$('backlay').style.background="radial-gradient(ellipse at 50%, rgba("+color1.toString()+",0.25), rgba("+color2.toString()+",.25) 50%, transparent 100%)";
}
var kAT;
var fps=12;
var switchNext=-1; // automatic for end of song unless loop on
var updateTime=0;
var mgLightValSet=0;
var mgLightTunSet=0;
var playerGlow=0;
var playerGlowVal=0;
var pglowc;
var maxgrad=50; // 10
function keepAlive() {
clearTimeout(kAT);
if(playing) {
idxCurrentTime=$('myAudio').currentTime;
//idxDuration//
//console.log(idxCurrentTime);
// seekpos = percentage * duration / 100 = time
var iPercent = idxCurrentTime*100/idxDuration;
iPercent=clamp(iPercent,0,100);
$('progress').style.width=iPercent+"%";
if(switchNext>-1) {
switchNext--;
//console.log("ready switch "+switchNext);
if(switchNext==0) {
// switch now
switchNext=-1;
//console.log("switching next done")
next();
}
} else if((idxDuration - idxCurrentTime <= 1) && !loopon) {
switchNext=fps;
}
if(updateTime<=0) {
var cmin=0;
var csec=parseInt(idxCurrentTime);
while(csec>=60) {
csec-=60;
cmin++;
}
var strcsec=(csec<10)?"0"+csec:csec;
var strcmin=(cmin<10)?"0"+cmin:cmin;
$('time').innerHTML=strcmin+":"+strcsec;
$('timeMini').innerHTML=strcmin+":"+strcsec;
updateTime=fps; // 1 per fps
} else {
updateTime--;
}
//$('visualizer').width = $('visualizer').clientWidth;
//$('visualizer').height = $('visualizer').clientHeight;
}
animloop(); // always update bg colors
if(shipOn && shipOpa<100) { // fade in
let sval=(100-shipOpa)*.05; // inverted
if(sval<0.01) sval=0.01;
shipOpa+=sval; // default +3
if(shipOpa>=100) {
shipOpa=100;
}
if(lastShipOpa==0) {
$('spaceship').style.visibility="visible";
$('spaceship_sun').style.visibility="visible";
$('lcd_cont').style.visibility="visible";
}
} else if(!shipOn && shipOpa>0) { // fade out
let sval=shipOpa*.05;
if(sval<0.01) sval=0.01;
shipOpa-=sval; // default -3
if(shipOpa<=0) {
shipOpa=0;
$('spaceship').style.visibility="hidden";
$('spaceship_sun').style.visibility="hidden";
$('lcd_cont').style.visibility="hidden";
}
}
if(lastShipOpa!=shipOpa) {
$('spaceship').style.opacity=(shipOpa/100);
$('spaceship_sun').style.opacity=(shipOpa/100);
$('lcd_cont').style.opacity=(shipOpa/100);
lastShipOpa=shipOpa;
}
//console.log(mgLightVal+" "+mgLightValSet);
if(!mgLightOn && mgLightVal>0 && mgLightValSet<1) {
mgLightValSet=Math.abs(mgLightVal);
let mlv=((mgLightValSet)-.1)*(100+maxgrad);
let mlvo=mlv+maxgrad;
let transcolor="rgba(0,0,0,"+(mgLightValSet)+")";
$('spaceship_sun').style.maskImage="linear-gradient(90deg, black "+mlv+"%, "+transcolor+" "+mlvo+"%)";
$('spaceship_sun').style.webkitMaskImage="linear-gradient(90deg, black "+mlv+"%, "+transcolor+" "+mlvo+"%)";
//
let mlvi=((1-mgLightValSet)-.1)*(100+maxgrad);
let mlvio=mlvi+maxgrad;
transcolor="rgba(0,0,0,"+(1-mgLightValSet)+")";
$('spaceship').style.maskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
$('spaceship').style.webkitMaskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
if(mgLightValSet>=1) {
mgLightOn=true;
}
//console.log("Turning light on mlv: "+mlv+", mlvo: "+mlvo);
} else if(mgLightOn && mgLightVal<1 && mgLightValSet>0) {
mgLightValSet=Math.abs(mgLightVal);
let mlv=((1-mgLightValSet)-.1)*(100+maxgrad);
let mlvo=mlv+maxgrad;
let transcolor="rgba(0,0,0,"+(mgLightValSet)+")";
$('spaceship_sun').style.maskImage="linear-gradient(90deg, "+transcolor+" "+mlv+"%, black "+mlvo+"%)";
$('spaceship_sun').style.webkitMaskImage="linear-gradient(90deg, "+transcolor+" "+mlv+"%, black "+mlvo+"%)";
//
let mlvi=((mgLightValSet)-.1)*(100+maxgrad);
let mlvio=mlvi+maxgrad;
transcolor="rgba(0,0,0,"+(1-mgLightValSet)+")";
$('spaceship').style.maskImage="linear-gradient(-90deg, "+transcolor+" "+mlvi+"%, black "+mlvio+"%)";
$('spaceship').style.webkitMaskImage="linear-gradient(-90deg, "+transcolor+" "+mlvi+"%, black "+mlvio+"%)";
if(mgLightValSet<=0) {
mgLightOn=false;
}
//console.log("Turning light off mlv: "+mlv+", mlvo: "+mlvo);
} else if(mgLightOn && mgLightTun>mgLightTunSet && mgLightTun!=1) { // eclipse in
mgLightTunSet=Math.abs(mgLightTun);
let mlv=((1-mgLightTunSet)-.1)*(100+maxgrad);
let mlvo=mlv+maxgrad;
let transcolor="rgba(0,0,0,"+(1-(mgLightTunSet*.9))+")";
$('spaceship_sun').style.maskImage="linear-gradient(90deg, black "+mlv+"%, "+transcolor+" "+mlvo+"%)";
$('spaceship_sun').style.webkitMaskImage="linear-gradient(90deg, black "+mlv+"%, "+transcolor+" "+mlvo+"%)";
//
let mlvi=((mgLightTunSet)-.1)*(100+maxgrad);
let mlvio=mlvi+maxgrad;
transcolor="rgba(0,0,0,"+(mgLightTunSet)+")";
$('spaceship').style.maskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
$('spaceship').style.webkitMaskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
//console.log("eclipse in "+mgLightTun);
} else if(mgLightOn && mgLightTun<mgLightTunSet) { // eclipse out
mgLightTunSet=Math.abs(mgLightTun);
let mlv=((mgLightTunSet)-.1)*(100+maxgrad);
let mlvo=mlv+maxgrad;
let transcolor="rgba(0,0,0,"+(1-(mgLightTunSet*.9))+")";
$('spaceship_sun').style.maskImage="linear-gradient(90deg, "+transcolor+" "+mlv+"%, black "+mlvo+"%)";
$('spaceship_sun').style.webkitMaskImage="linear-gradient(90deg, "+transcolor+" "+mlv+"%, black "+mlvo+"%)";
//
let mlvi=((mgLightTunSet)-.1)*(100+maxgrad);
let mlvio=mlvi+maxgrad;
transcolor="rgba(0,0,0,"+(mgLightTunSet)+")";
$('spaceship').style.maskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
$('spaceship').style.webkitMaskImage="linear-gradient(-90deg, black "+mlvi+"%, "+transcolor+" "+mlvio+"%)";
//console.log("eclipse out "+mgLightTun);
}
if(playerGlow==0) {
playerGlowVal+=.05;
if(playerGlowVal>=1.0) {
playerGlow=1;
playerGlowVal=1.0;
}
} else {
playerGlowVal-=.05;
if(playerGlowVal<=0.0) {
playerGlow=0;
playerGlowVal=0.0;
}
}
$('player').style.boxShadow="0 0 "+(10+(60*playerGlowVal))+"px #00f9cb36";
//pglowc="rgba("+(0*playerGlowVal)+","+((249*playerGlowVal)+100)+","+((203*playerGlowVal)+100)+",.54)";
//pglowc="rgba(0,249,203,."+parseFloat(playerGlowVal).toFixed(2)+")";
//$('player').style.boxShadow="0 0 600px "+pglowc;
//console.log(playerGlowVal+" - "+playerGlow);
if(!backlayHide && backlayOpa<100) { // fade in
let sval=(100-backlayOpa)*.05; // inverted
if(sval<0.01) sval=0.01;
backlayOpa+=sval; // default +3
if(backlayOpa>=100) {
backlayOpa=100;
}
if(lastBacklayOpa==0) {
$('backlay').style.visibility="visible";
}
} else if(backlayHide && backlayOpa>0) { // fade out
let sval=backlayOpa*.05;
if(sval<0.01) sval=0.01;
backlayOpa-=sval; // default -3
if(backlayOpa<=0) {
backlayOpa=0;
$('backlay').style.visibility="hidden";
}
}
if(lastBacklayOpa!=backlayOpa) {
$('backlay').style.opacity=(backlayOpa/100);
lastBacklayOpa=backlayOpa;
}
kAT=setTimeout(function() { keepAlive(); },1000/fps);
}
function highlightplaying(idx) {
var elms=$('player').getElementsByClassName('playing');
for(var i=0;i<elms.length;i++) {
var c=i+1;
if(c==idx) {
elms[i].className="playing selected";
$('aud'+c).className="track selected";
idxText=c+". "+$('aud'+c).getElementsByClassName('td')[2].innerHTML; // idx|name
t=$('aud'+c).getElementsByClassName('mp3name')[0].value;
elms[i].scrollIntoView({behavior: 'smooth',block: 'nearest'});
} else {
elms[i].className="playing";
$('aud'+c).className="track";
}
}
}
var cache=24;
var t="";
function play(idx) {
//alert(idx);
var reloading=true;
if(idx==idxPlaying && !playing) {
reloading=false;
} else {
switchNext=-1;
}
idxPlaying=idx;
highlightplaying(idx);
playing=true;
$('btnplaypause').value="∎";
$('triangle').className="triangle on";
$('triangleMini').className="triangleMini on";
if(reloading) {
//$('myAudio').src=idx+".mp3"; // need t, not c
$('myAudio').src=t+".mp3?c="+cache;
}
$('inner').innerHTML=idxText;
let dur=$('aud'+idx).getElementsByClassName('td')[3].innerHTML;
$('lcd_frm').contentWindow.postMessage(['new_text',idxText+" ("+dur+")"],'*');
$('myAudio').play();
if(!audioContextInitiated) {
createAudioContext();
}
if(eqloaded==1 || eqtrig==1) {
updateeq();
eqloaded=2;
}
}
var initClear=0;
function clearplay() {
var elms=$('player').getElementsByClassName('playing');
for(var i=0;i<elms.length;i++) {
var c=i+1;
if(c==idxPlaying) {
elms[i].className="playing"; // not playing
$('aud'+c).className="track selected";
idxText=c+". "+$('aud'+c).getElementsByClassName('td')[2].innerHTML; // idx|name
t=$('aud'+c).getElementsByClassName('mp3name')[0].value;
} else {
elms[i].className="playing";
$('aud'+c).className="track";
}
}
playing=false;
$('btnplaypause').value="►";
$('triangle').className="triangle";
$('triangleMini').className="triangleMini";
if(initClear==0) {
$('myAudio').src=t+".mp3?c="+cache;
initClear=1;
}
$('inner').innerHTML=idxText;
//let dur=$('aud'+idxPlaying).getElementsByClassName('td')[3].innerHTML;
//$('lcd_frm').contentWindow.postMessage(['new_text',idxText+" ("+dur+")"],'*');
$('lcd_frm').contentWindow.postMessage(['new_text',"Stand-by"],'*');
$('myAudio').pause();
}
var plX=-1;
var plY=-1;
var logstr="";
var touchDetect=false;
function mousehandle(e) {
e=event || window.event;
var lX=e.clientX || e.targetTouches[0].pageX;
var lY=e.clientY || e.targetTouches[0].pageY;
var sY=window.scrollY;
var sX=window.scrollX;
plX=lX;
plY=lY;
if(touchDetect) {
plX-=sX;
plY-=sY;
}
// logstr="lX = "+lX;
// logstr+="<br />lY = "+lY;
// logstr+="<br />sX = "+sX;
// logstr+="<br />sY = "+sY;
// logstr+="<br />irX = "+irX;
// logstr+="<br />irY = "+irY;
// logstr+="<br />touchDetect = "+(touchDetect)?"True":"False";
// $('log').innerHTML=logstr;
// update on move (and hold)
if(seeklock) {
seekpos();
} else if(vollock) {
setvol();
} else if(eqlock!=-1) {
seteq(eqlock);
}
if (isResizing && irY != 0 && irX != 0) {
let ilX=(plX-irX) * 2;
let ilY=(plY-irY) * 2;
//console.log(ilX+" "+ilY);
let nh=resizableElement.clientHeight+ilY;
let nw=resizableElement.clientWidth+ilX;
let dw=(600-nw);
if(liston) {
//console.log(nh);
//console.log(window.innerHeight);
if(nh>(window.innerHeight-(200))) nh=window.innerHeight-(200);
resizableElement.style.height=nh+"px";
resizableElement.setAttribute('data-height',nh);
}
//if(dw>0) dw=0;
if(nw>(window.innerWidth-((28*2)+14))) nw=window.innerWidth-((28*2)+14);
//if(dw<0 && nw<(window.innerWidth-((28*2)+14))) {
resizableElement.style.width=nw+"px";
resizableElement.setAttribute('data-width',nw);
//$('player').style.marginLeft=dw+"px";
$('player').style.maxWidth=(602-dw)+"px";
//}
irX=plX;
irY=plY;
}
}
var seeklock=false;
var vollock=false;
var eqlock=-1;
function unlockHold() {
seeklock=false;
vollock=false;
eqlock=-1;
if (isResizing) {
isResizing = false;
for(let i=0;i<ifrm.length;i++) {
ifrm[i].style.pointerEvents="";
}
$('listfrm').style.pointerEvents="";
//console.log("resize off");
}
}
function lockseek() {
seeklock=true;
seekpos(); // initial
}
function lockvol() {
vollock=true;
setvol(); // initial
}
function lockeq(x) {
eqlock=x;
seteq(eqlock); // initial
}
function seekpos() {
var elm=$('bar').getBoundingClientRect();
var ilX=plX - elm.left;
var ilY=plY - elm.top;
var iPercent = ilX * 100 / elm.width; // 0 - 100
//alert("mouseX = "+ilX+" mouseY = "+ilY+" percent = "+iPercent);
iPercent=clamp(iPercent,0,100);
$('progress').style.width = iPercent+"%";
var seekpos = iPercent * idxDuration / 100;
$('myAudio').currentTime = seekpos;
}
function setvol() {
var elm=$('vol').getBoundingClientRect();
var ilX=plX - elm.left;
var ilY=plY - elm.top;
var iPercent = ilX * 100 / elm.width; // 0 - 100
//alert("mouseX = "+ilX+" mouseY = "+ilY+" percent = "+iPercent);
iPercent=clamp(iPercent,0,100);
$('level').style.width = iPercent+"%";
volume = parseInt(iPercent);
$('myAudio').volume = volume/100;
localStorage.setItem("volume",iPercent);
}
function loadvol() {
if(localStorage.getItem("volume")) {
var iPercent=localStorage.getItem("volume")
$('level').style.width = iPercent+"%";
volume = parseInt(iPercent);
$('myAudio').volume = volume/100;
}
}
var ryg=[
[1,175,1],[0,255,44], // green
[175,175,0],[255,255,0], // yellow
[175,50,0],[255,50,0] // red
];
var rcolor1=[0,0,0];
var rcolor2=[0,0,0];
var arpha=0.0;
function coloreq(x,iPercent) {
// lerp [0][0-2] to [2][0-2] and [1][0-2] to [3][0-2] 0-50
// lerp [2][0-2] to [4][0-2] and [3][0-2] to [5][0-2] 50-100
var ridx=0;
arpha=iPercent/50;
if(iPercent>50) {
ridx=2;
arpha-=1.0;
}
rcolor1[0]=lerp(ryg[ridx][0],ryg[ridx+2][0],arpha);
rcolor1[1]=lerp(ryg[ridx][1],ryg[ridx+2][1],arpha);
rcolor1[2]=lerp(ryg[ridx][2],ryg[ridx+2][2],arpha);
rcolor2[0]=lerp(ryg[ridx+1][0],ryg[ridx+3][0],arpha);
rcolor2[1]=lerp(ryg[ridx+1][1],ryg[ridx+3][1],arpha);
rcolor2[2]=lerp(ryg[ridx+1][2],ryg[ridx+3][2],arpha);
//
$('eq'+x).style.background="linear-gradient(270deg, rgb("+rcolor1+"), rgb("+rcolor2+"))";
//console.log("arpha = "+arpha+", ");
//console.log("rcolor1="+rcolor1.toString()+" rcolor2="+rcolor2.toString());
}
function seteq(x) {
var elm=$('eq'+x).parentNode.getBoundingClientRect();
var ilX=plX - elm.left;
var ilY=plY - elm.top;
var iPercent = 100 - (ilY * 100 / elm.height); // 0 - 100
//alert("mouseX = "+ilX+" mouseY = "+ilY+" percent = "+iPercent);
iPercent=clamp(iPercent,0,100);
$('eq'+x).style.height = iPercent+"%";
coloreq(x,iPercent);
// convert 0 - 100 iPercent to
// -20 to 0 to 20 where 0 = 50
audioFilters[x][1] = parseFloat((iPercent * .4) - 20);
//volume = parseInt(iPercent);
//$('myAudio').volume = volume/100;
updateeq();
saveeq();
}
var eqpreset=[
[50,50,50,50,50,50,50,50,50,50], // flat
[42,52,58,38,50,40,30,50,46,40], // preset1
[45,60,83,45,35,30,30,70,80,50], // preset2
[36,45,65,80,70,70,85,80,50,44], // preset3
[35,48,65,75,86,86,75,65,48,35], // preset4
];
function loadpreset(x) {
loadeq(x);
}
var eqloaded=0;
var eqtrig=0;
function updateeq() {
eqtrig=1;
if(eqloaded==0) {
eqloaded=1;
} else if(eqloaded==1) {
if(!audioContextInitiated) {
createAudioContext();
}
eqloaded=2;
} else if(eqloaded==2) {
eqtrig=0;
for(var i=0;i<audioFilters.length;i++) {
audioFilters[i][2].gain.value=audioFilters[i][1];
//console.log("update gain eq "+i+" to "+audioFilters[i][1]);
}
}
}
function saveeq() {
var arr=[];
var iPercent=0;
for(var i=0;i<audioFilters.length;i++) {
iPercent=(audioFilters[i][1]+20)*2.5; // realign and scale
iPercent=Math.floor(clamp(iPercent,0,100));
arr.push(iPercent);
//console.log("convert "+audioFilters[i][1]+" to "+iPercent);
}
//console.log(JSON.stringify(arr));
localStorage.setItem("eqdata",JSON.stringify(arr));
}
function loadeq(f=-1) {
var arr;
var iPercent=0;
if(localStorage.getItem("eqdata") && f==-1) {
var data=localStorage.getItem("eqdata")
arr=JSON.parse(data);
} else {
if(f==-1) f=1; // default load
arr=eqpreset[f];
}
for(var i=0;i<arr.length;i++) {
iPercent=arr[i];
$('eq'+i).style.height = iPercent+"%";
coloreq(i,iPercent);
audioFilters[i][1] = parseFloat((iPercent * .4) - 20);
//console.log("loading eq"+i+" = "+iPercent);
}
if(eqloaded==1 && f==-1) {
eqloaded=1;
} else {
updateeq();
saveeq();
}
}
function dl() {
//alert(idxPlaying+".mp3");
downloadResource('//twily.info/s/firefox/mp3/'+t+".mp3","twily-album1-track"+idxPlaying+".mp3");
}
function forceDownload(blob, filename) {
var a = document.createElement('a');
a.download = filename;
a.href = blob;
// For Firefox https://stackoverflow.com/a/32226068
document.body.appendChild(a);
a.click();
a.remove();
}
// Current blob size limit is around 500MB for browsers
function downloadResource(url, filename) {
if (!filename) filename = url.split('\\').pop().split('/').pop();
fetch(url, {
headers: new Headers({
'Origin': location.origin
}),
mode: 'cors'
})
.then(response => response.blob())
.then(blob => {
let blobUrl = window.URL.createObjectURL(blob);
forceDownload(blobUrl, filename);
})
.catch(e => console.error(e));
}
var audioFilters=[ // hz,db,obj
[60,0.0,null],
[170,0.0,null],
[310,0.0,null],
[600,0.0,null],
[1000,0.0,null],
[3000,0.0,null],
[6000,0.0,null],
[12000,0.0,null],
[14000,0.0,null],
[16000,0.0,null]
];
var audioContextInitiated=false;
var audioContext, source, analyser, bufferLength, dataArray;
var canvas={},canvasCtx={};
function createAudioContext() {
audioContextInitiated=true;
audioContext = new (window.AudioContext || window.webkitAudioContext)();
// Create a source node from the audio element
source = audioContext.createMediaElementSource($('myAudio'));
// Create an AnalyserNode for audio analysis
analyser = audioContext.createAnalyser();
analyser.fftSize = 128; // Number of samples for FFT (higher = more detail)
bufferLength = analyser.frequencyBinCount; // Half of fftSize
dataArray = new Uint8Array(bufferLength); // Array to store frequency data
for(var i=0;i<audioFilters.length;i++) {
audioFilters[i][2] = audioContext.createBiquadFilter();
var type="lowshelf";
if(i>6) {
type="highshelf";
} else if(i>3) {
type="peaking";
}
audioFilters[i][2].type=type;
audioFilters[i][2].frequency.value=audioFilters[i][0];
}
updateeq();
// Connect the audio source to the analyser and then to the output (speakers)
source.connect(analyser);
analyser.connect(audioFilters[0][2]);
for(var i=0;i<audioFilters.length-1;i++) {
audioFilters[i][2].connect(audioFilters[(i+1)][2]);
}
//analyser.connect(audioContext.destination);
audioFilters[9][2].connect(audioContext.destination);
canvas['norm'] = $('visualizer');
canvas['mini'] = $('visualizerMini');
canvasCtx['norm'] = canvas['norm'].getContext("2d");
canvasCtx['mini'] = canvas['mini'].getContext("2d");
// Start the visualization loop
draw();
}
var minimized="norm";
// Visualization function
var barWidth,barHeight;
var grad,red,green;
function draw() {
// Schedule the next frame
requestAnimationFrame(draw);
// Get the current frequency data
analyser.getByteFrequencyData(dataArray);
// Clear the canvas
canvasCtx[minimized].clearRect(0, 0, canvas[minimized].width, canvas[minimized].height);
//console.log(canvas[minimized].width+"x"+canvas[minimized].height);
// Calculate bar width for the spectrum
barWidth = ((canvas[minimized].width - 3) / bufferLength) * 2.5; // -3 adjust right edge last bar
let x = 0;
// Draw bars for each frequency bin
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i]; // Amplitude value (0-255)
//grad = canvasCtx[minimized].createLinearGradient(0, 0, 0, barHeight);
grad = canvasCtx[minimized].createLinearGradient(0, canvas[minimized].height / 4, 0, canvas[minimized].height);
red=barHeight-50;
green=255-red;
grad.addColorStop(0, "rgb(255,50,0)");
grad.addColorStop(0.5, "rgb(255,255,0)");
grad.addColorStop(1, "rgb(0,127,0)");
//canvasCtx[minimized].fillStyle = `rgb(${barHeight + 100}, 50, 50)`; // Dynamic color
canvasCtx[minimized].fillStyle = grad;
canvasCtx[minimized].fillRect(x, canvas[minimized].height - barHeight / 2, barWidth, barHeight / 2);
x += barWidth + 1; // Move to the next bar with a small gap
}
}
function newSize() {
wW=window.innerWidth;
wH=window.innerHeight;
wH2=wH/2;
//bW=wW;
bH=wW * bgAspect;
bH2 = bH/2;
}
function init() {
$('eqbrd').style.border="none"; // default off
init_cresizer();
listtog(); // default on
window_resize();
loliadd(0);
$('lcd_frm').style.height="48px";
$('lcd_frm').style.width="422px";
$('lcd_frm').contentWindow.postMessage(['new_height',48],'*');
$('lcd_frm').contentWindow.postMessage(['new_width',422],'*');
$('myAudio').addEventListener('loadedmetadata',function() {
idxDuration = $('myAudio').duration;
//console.log(idxDuration);
});
idxPlaying=1;
clearplay();
preloadSpaceship();
newSize();
keepAlive();
loadvol();
loadeq();
}
var shipOpa=0;
var lastShipOpa=0;
var shipOn=false;
var shipLoaded=false;
var shipSunLoaded=false;
function toggle_direction() {
//$('star_frm').src=$('star_frm').src;
//$('star_frm').contentWindow.postMessage('new_dir','https://analiestar.com');
$('star_frm').contentWindow.postMessage('new_dir','*');
// opposite way - parent.postMessage..
}
function toggle_ship() {
if(!shipLoaded) return;
shipOn=!shipOn;
if(shipOn) {
$('btn_ship').innerHTML="[ Float through space ]";
} else {
$('btn_ship').innerHTML="[ Return to spaceship ]";
}
}
async function preloadSpaceship() {
var img=new Image();
img.onload=function() {
shipLoaded=true;
$('spaceship').style.background="url("+this.src+") no-repeat center center transparent";
$('spaceship').style.backgroundSize="cover";
toggle_ship();
}
img.src="./spaceship.png?cache="+cache;
}
async function preloadSpaceshipSun() {
var img=new Image();
img.onload=function() {
$('spaceship_sun').style.background="url("+this.src+") no-repeat center center transparent";
$('spaceship_sun').style.backgroundSize="cover";
}
img.src="./spaceship_sunlit.png?cache="+cache;
}
function setSunDir() {
//
}
var resizableElement = null;
var resizeHandle = null;
var ifrm=[];
var isResizing = false;
var irX=0, irY=0;
function begin_resize(e,t) { // player resize
e.preventDefault();
if(t==2) {
touchDetect=true;
} else {
touchDetect=false;
}
if(plX!=-1 && plY!=-1) { // this and irY != 0 check prevent infinity glitch touch
irX=plX;
irY=plY;
}
for(let i=0;i<ifrm.length;i++) {
ifrm[i].style.pointerEvents="none";
}
$('listfrm').style.pointerEvents="none";
//console.log("resize on");
isResizing = true;
}
function init_cresizer() {
resizableElement = $('resizeFrm');
resizeHandle = document.querySelector('.custom-resize-handle');
ifrm=document.getElementsByTagName('iframe');
resizeHandle.addEventListener('mousedown', (e) => { begin_resize(e,1); });
resizeHandle.addEventListener('touchstart', (e) => { begin_resize(e,2); });
}
function window_resize() {
var biggest=Math.max(window.innerWidth,window.innerHeight);
var sca=biggest/960; // 1
$('lcd_frm').style.transform="perspective(300px) rotateX(-3deg) scale("+sca+")";
var invSca=1-sca;
console.log("sca: "+sca);
console.log("invSca: "+invSca);
$('star_frm').contentWindow.postMessage(['new_sca',sca],'*');
//$('lcd_frm').style.top=(biggest/2)+"px";
$('lcd_frm').style.top=((biggest*.245)-(invSca*25))+"px";
//$('lcd_frm').style.top=(biggest*.32)+"px";
//var bcr=$('lcd_frm').getBoundingClientRect();
//if(bcr.top<0)
// cover fit lcd container and backlay glow to fixed aspect~ (cover mode)
if(biggest>window.innerHeight) { // landscape
$('lcd_cont').style.height=biggest+"px";
$('lcd_cont').style.width=""; // 100%
$('backlay').style.height=biggest+"px";
$('backlay').style.width=""; // 100%
let diff=biggest-window.innerHeight;
$('lcd_cont').style.top=-(diff/2)+"px";
$('lcd_cont').style.left=""; // 0
$('backlay').style.top=-(diff/2)+"px";
$('backlay').style.left=""; // 0
} else { // portrait
$('lcd_cont').style.height=""; // 100%
$('lcd_cont').style.width=biggest+"px";
$('backlay').style.height=""; // 100%
$('backlay').style.width=biggest+"px";
let diff=biggest-window.innerWidth;
$('lcd_cont').style.top=""; // 0
$('lcd_cont').style.left=-(diff/2)+"px";
$('backlay').style.top=""; // 0
$('backlay').style.left=-(diff/2)+"px";
}
$('btn_fot').style.marginLeft=-($('btn_fot').clientWidth/2)+"px";
}
var rzT;
window.addEventListener('resize', (e) => { // window resize
clearTimeout(rzT);
window_resize();
rzT=setTimeout(function() { newSize(); }, 100);
});
var newtsmg1=[];
var newmg1str="";
var firstMG1=0;
var mgLightVal=0;
var mgLightTun=1;
var mgLightOn=false;
window.addEventListener('message', (event) => {
//if (event.origin === 'https://links.analiestar.com') {
//console.log('Message from parent:', event.data[0]);
switch(event.data[0]) {
case "new_tim":
newmg1str="";
newtsmg1=event.data[1].split(" ");
for(let i=0;i<4;i++) newmg1str+=newtsmg1[i]+" ";
newmg1str+="<br />";
for(let i=4;i<newtsmg1.length;i++) newmg1str+=newtsmg1[i]+" ";
updateTimeMg1(newmg1str);
//var lilen=0.5;
//var limul=2;
var lilen=0.25;
var limul=4;
//console.log(event.data[3]);
if(event.data[3]>=0 && event.data[3]<=Math.PI-lilen) {
//console.log("staying dark");
if(mgLightVal!=0) {
mgLightVal=0;
}
} else if(event.data[3]<=-0 && event.data[3]>=-lilen) {
//console.log("entering light");
mgLightVal=Math.abs(event.data[3]*limul);
} else if(event.data[3]<-lilen && event.data[3]>=-Math.PI) {
//console.log("staying light");
if(mgLightVal!=1) {
mgLightVal=1;
}
if(event.data[3]>-Math.PI/2-lilen && event.data[3]<-Math.PI/2+lilen) {
//mgLightTun=event.data[3];
//mgLightTun=-(-lilen-(Math.PI/2-lilen)-event.data[3])*limul;
//mgLightTun=Math.abs((-lilen-(Math.PI/2-lilen)-event.data[3])*limul);
//mgLightTun=1-Math.abs((-lilen-(Math.PI/2-lilen)-event.data[3])*limul);
mgLightTun=1-Math.abs((-(lilen*2)-(Math.PI/2-(lilen*2))-event.data[3])*(limul));
}
//console.log(mgLightTun); // 1 0 -1 or 1 0 1 or 0 1 0
} else if(event.data[3]>=Math.PI) {
//console.log("entering dark");
mgLightVal=((Math.PI-event.data[3])*limul);
}
//console.log("mgLightVal = "+mgLightVal);
if(firstMG1<2) {
let biggest=Math.max(window.innerWidth,window.innerHeight);
let sca=biggest/960; // 1
let invSca=1-sca;
$('star_frm').contentWindow.postMessage(['new_sca',sca],'*');
console.log("sending new-sca mg1");
firstMG1++;
}
break;
case "loli_cen":
if(event.data[1]==1) {
$('loli_frm').style.pointerEvents="auto"
} else {
$('loli_frm').style.pointerEvents="none"
}
break;
case "loli_blk":
if(event.data[1]==1) {
$('loliadd').style.display="none";
} else {
$('loliadd').style.display="";
}
break;
default:
}
//}
});
function minimize() {
minimized="mini";
$('player').style.display="none";
$('displayMini_cont').style.display="inline-block";
}
function maximize() {
minimized="norm";
$('player').style.display="";
$('displayMini_cont').style.display="";
if(liston) {
$('aud'+idxPlaying).scrollIntoView({behavior: 'smooth',block: 'nearest'});
}
}
var lolion=0;
function loliadd(x=1) {
if(lolion==0 && x!=0) {
lolion=1;
var lolifrm=document.createElement('iframe');
lolifrm.id="loli_frm";
lolifrm.src="/loli/index.php?cache="+cache;
lolifrm.frameBorder="0";
lolifrm.border="0";
document.body.appendChild(lolifrm);
$('loliadd').className="lolion";
} else if(lolion==1 && x!=0) {
lolion=2;
$('loliadd').className="lolion blue";
$('loli_frm').contentWindow.postMessage(['slowmode',1],'*');
} else if(lolion==2 && x!=0) {
lolion=3;
$('loliadd').className="lolion grey";
$('loli_frm').contentWindow.postMessage(['slowmode',2],'*');
} else {
lolion=0;
while($('loli_frm')) {
$('loli_frm').parentNode.removeChild($('loli_frm'));
}
$('loliadd').className="";
}
}
function updateTimeMg1(txt) {
$('mg1_tim').innerHTML=txt;
}
var currentScene=0;
var backlayHide=false;
var backlayOpa=100;
var lastBacklayOpa=100;
var anaSceneOn=false;
function changeScene() {
currentScene++;
if(currentScene>4) {
currentScene=0;
}
if(currentScene>3 && !anaSceneOn) {
currentScene=0;
}
var frmSrc="stars3d-transparent.html?cache="+cache;
$('mg1_tim').style.display=""; // none
$('btn_dir').style.display="none";
// missing a good forward 3d stars scene still x)
$('btn_fot').className="lnkbtn";
$('spaceship_sun').style.display=""; // none
$('spaceship').style.maskImage="none";
$('spaceship').style.webkitMaskImage="none";
switch(currentScene) {
case 1:
frmSrc="stars-transparent.html?cache="+cache;
//backlayHide=true;
$('btn_dir').style.display=""; // inline-block
break;
case 2:
firstMG1=0;
frmSrc="../simulations/mg1/index.html?cache="+cache;
//backlayHide=true;
$('mg1_tim').style.display="inline-block";
$('spaceship_sun').style.display="block";
if(!shipSunLoaded) {
preloadSpaceshipSun();
shipSunLoaded=true;
}
break;
case 3:
frmSrc="../void/void-2.html?cache="+cache;
//backlayHide=true;
if(lolion>0) {
anaSceneOn=true;
$('btn_fot').className="lnkbtn red";
}
break;
case 4:
frmSrc="//analiestar.com/immerse/index.php?cache="+cache;
//backlayHide=true;
$('btn_fot').className="lnkbtn blue";
anaSceneOn=false;
break;
default:
//backlayHide=false;
$('btn_dir').style.display=""; // inline-block
}
$('star_frm').src=frmSrc;
//alert("new scene : "+currentScene);
}
var fullScreen=false;
function toggle_full() {
fullScreen=!fullScreen;
//var elem = document.getElementById("myvideo");
var elem = document.documentElement;
if(fullScreen) {
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) { /* Safari */
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) { /* IE11 */
elem.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) { /* Safari */
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) { /* IE11 */
document.msExitFullscreen();
}
}
}
//window.addEventListener('fullscreenchange', (e) => {
// //fullScreen=!fullScreen;
// console.log("fullscreen trigger "+fullScreen);
//});
</script>
</head>
<body onload="init();" onmousemove="mousehandle(event);" onmouseup="unlockHold();" ontouchmove="mousehandle(event);" ontouchend="unlockHold();">
<div id="backdrop">
<iframe src="stars3d-transparent.html?cache=24" frameborder="0" class="frm" id="star_frm"></iframe>
</div>
<div id="spaceship"></div>
<div id="spaceship_sun"></div>
<div id="backlay"></div>
<div id="lcd_cont">
<iframe src="ship-lcd.html?cache=24" frameborder="0" class="frm" id="lcd_frm"></iframe>
</div>
<!-- Audio element with controls and a sample audio file -->
<audio loop id="myAudio">
<source src="1.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<div id="above">
<div class="tbl" style="height: 100%;">
<div class="tr" style="height: 50px;">
<div class="td" style="text-align: center; vertical-align: middle;">
<a href="javascript:toggle_full();" target="_self" id="btn_full" class="lnkbtn">
<div id="title_swap" style="text-align: center; position: absolute; display: inline-block; left: 0; top: 8px; width: 100%;">
[ Fullscreen ]
</div>
<div id="title_c" style="display: inline-block; position: relative; color: #666 !important;">
Twily AI Album #1
</div>
</a>
</div>
</div>
<div class="tr">
<div class="td">
<div class="tbl">
<div class="tr">
<div class="td sidebar">
</div>
<div class="td">
<center>
<div id="player_frm">
<div id="player">
<div class="tbl">
<div class="tr">
<div class="td" style="background: rgba(25,32,70,1.0); background: linear-gradient(0deg, #192046, #1e275c); /*#46192e, #172158);*/ border-radius: 2px;">
<!-- player -->
<div class="tbl" style="height: 100%;">
<div class="tr">
<div class="td" style="width: 150px; height: 100%; /* ff fix */">
<!-- player left -->
<div class="pad18" style="height: 100%;">
<div id="display">
<span id="triangle"></span>
<span id="time">00:00</span>
<!-- Canvas for visualization -->
<canvas id="visualizer"></canvas>
</div>
</div>
</div>
<div class="td">
<!-- player right -->
<div class="pad18">
<!--<div id="title"><marquee><div id="inner">1. </div></marquee></div>-->
<div id="title"><div id="inner">1. </div><input type="button" class="btn" value="-" onclick="minimize();" style="float: right;" /></div>
<br />
<div id="bar" onmousedown="lockseek();" ontouchstart="lockseek();">
<div id="progress"></div>
</div>
<br />
<div id="controls">
<input type="button" class="btn" value="⊲" onclick="prev();" />
<input type="button" class="btn" value="►" id="btnplaypause" onclick="playpause();" />
<input type="button" class="btn" value="⊳" onclick="next();" />
<input type="button" class="btn" value="≠" id="btnshuftog" onclick="shuftog();" /><label class="grey" id="lbshuf">Shuffle</label>
<input type="button" class="btn" value="∞" id="btnlooptog" onclick="looptog();" /><label class="grey" id="lbloop">Loop one</label>
<input type="button" class="btn" value="⏏" onclick="dl();" title="Download" alt="Download" />
<div style="float: right;">
<input type="button" class="btn" value="~" id="btneqtog" onclick="eqtog();" />
<input type="button" class="btn" value="≣" id="btnlisttog" onclick="listtog();" />
<label id="lbvol">Vol:</label><div id="vol" onmousedown="lockvol();" ontouchstart="lockvol();">
<div id="level"></div>
</div>
</div>
<div style="clear:both;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- separate equalizer start -->
<div class="tr">
<div class="td brd" id="eqbrd" style="background: rgba(25,32,70,1.0); background: linear-gradient(0deg, #1e275c, #192046); /*#46192e, #172158);*/ border-radius: 2px;">
<div class="pad18" id="eqfrm" style="display: none;">
<!--Equalizer
<br />-->
<center>
<div class="tbl">
<div class="tr">
<div class="td" style="vertical-align: top; text-align: left;">
<!-- left -->
<input type="button" class="btn" value="flat" onclick="loadpreset(0);" />
<br />
</div>
<div class="td">
<div class="tbl" style="width: 75%;"> <!-- db from +20 to 0 to -20 -->
<div class="tr">
<div class="td" style="width: 9%;">
<div class="tbl" style="height: 100%;text-align: right;">
<div class="tr">
<div class="td" style="vertical-align: top; padding-bottom: 6px;">
<label class="grey">+20</label>
</div>
</div>
<div class="tr">
<div class="td">
<label class="grey">-</label>
</div>
</div>
<div class="tr">
<div class="td" style="vertical-align: bottom; padding-top: 6px;">
<label class="grey">-20</label>
</div>
</div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(0);" ontouchstart="lockeq(0);">
<div class="eqlevel" id="eq0"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(1);" ontouchstart="lockeq(1);">
<div class="eqlevel" id="eq1"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(2);" ontouchstart="lockeq(2);">
<div class="eqlevel" id="eq2"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(3);" ontouchstart="lockeq(3);">
<div class="eqlevel" id="eq3"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(4);" ontouchstart="lockeq(4);">
<div class="eqlevel" id="eq4"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(5);" ontouchstart="lockeq(5);">
<div class="eqlevel" id="eq5"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(6);" ontouchstart="lockeq(6);">
<div class="eqlevel" id="eq6"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(7);" ontouchstart="lockeq(7);">
<div class="eqlevel" id="eq7"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(8);" ontouchstart="lockeq(8);">
<div class="eqlevel" id="eq8"></div>
</div>
</div>
<div class="td" style="width: 9%;">
<div class="eqbar" onmousedown="lockeq(9);" ontouchstart="lockeq(9);">
<div class="eqlevel" id="eq9"></div>
</div>
</div>
</div>
<div class="tr">
<div class="td center"><label class="grey"> </label></div>
<div class="td center"><label class="grey">60</label></div>
<div class="td center"><label class="grey">170</label></div>
<div class="td center"><label class="grey">310</label></div>
<div class="td center"><label class="grey">600</label></div>
<div class="td center"><label class="grey">1K</label></div>
<div class="td center"><label class="grey">3K</label></div>
<div class="td center"><label class="grey">6K</label></div>
<div class="td center"><label class="grey">12K</label></div>
<div class="td center"><label class="grey">14K</label></div>
<div class="td center"><label class="grey">16K</label></div>
</div>
</div>
</div>
<div class="td" style="vertical-align: top; text-align: right;">
<!-- right -->
<input type="button" class="btn" value="preset1" onclick="loadpreset(1);" />
<br />
<input type="button" class="btn" value="preset2" onclick="loadpreset(2);" />
<br />
<input type="button" class="btn" value="preset3" onclick="loadpreset(3);" />
<br />
<input type="button" class="btn" value="preset4" onclick="loadpreset(4);" />
<br />
</div>
</div>
</div>
</center>
</div><!--pad18-->
</div>
</div>
<!-- separate playlist start -->
<div class="tr">
<div class="td brd" id="listbrd" style="background: rgba(16,20,38,.5);">
<!-- list -->
<div id="resizeFrm">
<div class="pad18" id="listfrm">
</div>
<div class="custom-resize-handle"></div>
</div>
</div>
</div>
</div>
</div> <!-- end player -->
</div>
</center>
</div>
<div class="td sidebar">
</div>
</div>
</div>
</div>
</div>
<div class="tr" style="height: 50px;">
<div class="td" style="text-align: center; vertical-align: middle;">
<div class="tbl">
<div class="tr">
<div class="td" style="width: 33%; text-align:left; padding-top: 28px;">
<a href="javascript:toggle_direction();" target="_self" id="btn_dir" class="lnkbtn">[ Change direction ]</a>
<span id="mg1_tim"></span>
</div>
<div class="td" style="width: 34%;">
<div id="jswarning">This website requires JavaScript to function</div>
<br />
<a href="javascript:changeScene();" target="_self" class="lnkbtn" id="btn_fot">
<div class="tbl" style="position: absolute; width: 100%; height: 100%; margin-top: -8px; margin-left: -4px;"><div class="tr">
<div id="footer_swap" style="text-align: center; vertical-align: middle;" class="td">
[ Change Scene ]
</div>
</div></div>
<div id="footer_c" style="display: inline-block; color: #666 !important;">
Runtime: <span id="runtime"></span>
<br />
<br />
(produced with MusicGen~)
<br />
<br />
(ɔ) Twily 2025
</div>
</a>
<br />
<br />
</div>
<div class="td" style="width: 33%; text-align: right; padding-top: 28px;">
<a href="javascript:toggle_ship();" target="_self" id="btn_ship" class="lnkbtn">[ Loading spaceship ]</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<a id="displayMini_cont" href="javascript:maximize();" target="_self">
<div id="displayMini">
<span id="triangleMini"></span>
<span id="timeMini">00:00</span>
<!-- Canvas for visualization -->
<canvas id="visualizerMini"></canvas>
</div>
</a>
<div id="log"></div>
<a href="javascript:loliadd();" target="_self" id="loliadd"></a>
<script type="text/javascript">
$('jswarning').style.display="none";
var localtracks=[
"1",90,
"2",90,
"3",90,
"4",90,
"5",90,
"6",90,
"7",90,
"8",90,
"9",90,
"10",90,
"11",80,
"12",80,
"13",80,
"14",80,
"15",80,
"16",90,
"17",90,
"18",90,
"19",90,
"20",90,
"21",90,
"22",90,
"23",90,
"24",90,
"25",90,
"26",90,
"27",90,
"28",90,
"29",90,
"30",90,
"31",90,
"32",90,
"33",90,
"34",90
];
rearrangelist(1);
// grok visualizer implement
//Adapting for Volume
///To visualize volume instead, you can use time-domain data:
//
//Replace getByteFrequencyData(dataArray) with getFloatTimeDomainData(timeDataArray) (where timeDataArray is a Float32Array of length analyser.fftSize).
//
//
//
//Calculate the root mean square (RMS) to estimate volume:
//
//javascript
//
//
//const timeDataArray = new Float32Array(analyser.fftSize);
//analyser.getFloatTimeDomainData(timeDataArray);
//let sum = 0;
//for (let i = 0; i < timeDataArray.length; i++) {
// sum += timeDataArray[i] * timeDataArray[i];
//}
//const rms = Math.sqrt(sum / timeDataArray.length); // Volume level
//
//
//Use rms to adjust the height of a single bar or scale a waveform.
//
//Notes on Pitch
//
//Extracting pitch directly is more complex and requires pitch
// detection algorithms (e.g., autocorrelation or finding the
// dominant frequency from the frequency data). The frequency
// spectrum provided by getByteFrequencyData gives raw frequency
// amplitudes, which can hint at pitch but don’t directly isolate
// it for complex sounds. For a simple visualization, the spectrum i
// s often sufficient, as pitch relates to frequency content.
</script>
</body>
</html>
Top