summaryrefslogtreecommitdiff
path: root/app/studio.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/studio.php')
-rw-r--r--app/studio.php445
1 files changed, 0 insertions, 445 deletions
diff --git a/app/studio.php b/app/studio.php
deleted file mode 100644
index 4f002f7..0000000
--- a/app/studio.php
+++ /dev/null
@@ -1,445 +0,0 @@
-<?php header("X-Frame-Options: SAMEORIGIN"); require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/session.php"; ?>
-<!doctype html>
-<html lang="en">
-<head>
- <script>
- if (typeof require === "undefined") {
- location.href = "/app/";
- }
- </script>
- <style>
- * {
- outline: none;
- user-select: none;
- -webkit-user-drag: none;
- }
-
- *:hover {
- outline: 1px solid #00bbff;
- }
-
- button.active {
- outline: 1px solid #00ff04 !important;
- }
-
- *::placeholder {
- font-style: italic;
- }
- </style>
- <meta charset="UTF-8">
- <meta name="viewport"
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Mist Studio</title>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
- <script src="/assets/js/pako.js"></script>
- <script src="/assets/js/stella.js"></script>
-</head>
-<body style="background-color: #111111;">
- <div id="app" style="position: fixed; inset: 0; background-color: #111111; display: none;">
- <div id="header" style="position: fixed; top: 5px; left: 5px; right: 5px; height: 48px; background-color: #222222;"></div>
- <div id="controls" style="position: fixed; top: 60px; left: 5px; bottom: 5px; width: 256px; background-color: #222222;">
- <div style="background-color: #333; height: 24px;" id="seek">
- <div style="background-color: #444; height: 24px; pointer-events: none;" id="seek-inner"></div>
- <span id="seek-cursor" style="pointer-events: none; top: -24px; background-color: red; width: 1px; height: 24px; position: relative; display: none;"></span>
- </div>
- <script>
- document.getElementById("seek").onmouseenter = () => {
- document.getElementById("seek-cursor").style.display = "inline-block";
- }
-
- document.getElementById("seek").onmouseleave = () => {
- document.getElementById("seek-cursor").style.display = "none";
- }
-
- document.getElementById("seek").onmousemove = (e) => {
- document.getElementById("seek-cursor").style.left = ((e.offsetX / document.getElementById("seek").clientWidth) * 100) + "%";
- }
-
- document.getElementById("seek").onclick = (e) => {
- let factor = e.offsetX / document.getElementById("seek").clientWidth;
- document.getElementById("audio-stream-0").currentTime = document.getElementById("audio-stream-0").duration * factor;
-
- if (playingStella) {
- document.getElementById("audio-stream-1").currentTime =
- document.getElementById("audio-stream-2").currentTime =
- document.getElementById("audio-stream-3").currentTime =
- document.getElementById("audio-stream-4").currentTime =
- document.getElementById("audio-stream-5").currentTime = document.getElementById("audio-stream-0").currentTime;
- }
- }
- </script>
- <div style="color: white; text-align: center; margin-top: 20px;" id="status">Empty queue</div>
- <div id="buttons" style="text-align: center;">
- <button id="btn-prev" style="border: 1px solid #151515; background-color: #333; color: white;"><</button>
- <button id="btn-play" onclick="togglePlay();" style="border: 1px solid #151515; background-color: #333; color: white;">Play</button>
- <button id="btn-next" style="border: 1px solid #151515; background-color: #333; color: white;">></button>
- </div>
- <div id="details" style="margin-top: 20px; color: white; font-family: monospace;">
- <div id="time">--:--.--- / ---:--.---</div>
- <div id="delay">------ samples</div>
- <div id="delay-ms">---- ms</div>
- </div>
- <div id="clip-indicators" style="display: grid; height: 8px; grid-template-columns: repeat(6, 1fr); pointer-events: none; grid-gap: 2px; position: absolute; bottom: 210px; left: 0; right: 0; margin: 10px; margin-bottom: 5px;">
- <div id="ci-0" style="background-color: #151515;"></div>
- <div id="ci-1" style="background-color: #151515;"></div>
- <div id="ci-2" style="background-color: #151515;"></div>
- <div id="ci-3" style="background-color: #151515;"></div>
- <div id="ci-4" style="background-color: #151515;"></div>
- <div id="ci-5" style="background-color: #151515;"></div>
- </div>
- <div id="meters" style="display: grid; grid-template-columns: repeat(6, 1fr); pointer-events: none; grid-gap: 2px; position: absolute; bottom: 0; left: 0; right: 0; margin: 10px;">
- <div id="meter-0" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-0-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- <div id="meter-1" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-1-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- <div id="meter-2" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-2-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- <div id="meter-3" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-3-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- <div id="meter-4" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-4-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- <div id="meter-5" style="background-image: linear-gradient(0deg, rgba(124,255,129,1) 0%, rgba(253,255,124,1) 75%, rgba(255,124,124,1) 100%); height: 200px; display: flex; align-items: start;">
- <div id="meter-5-inner" style="background-color: #151515; width: 100%; height: 100%;"></div>
- </div>
- </div>
- </div>
- <div id="queue" style="position: fixed; top: 60px; left: 269px; right: 5px; height: calc((100vh - 72px) / 2); background-color: #222222; overflow: auto;"></div>
- <div id="library" style="display: grid; grid-template-rows: 42px 1fr; position: fixed; top: calc((60px) + (100vh - 58px) / 2); left: 269px; right: 5px; height: calc((100vh - 72px) / 2); background-color: #222222;">
- <input id="query" placeholder="Search..." style="background-color: #252525; border: 1px solid #151515; color: white;" onkeydown="refreshSearch();" onkeyup="refreshSearch();" onchange="refreshSearch();">
- <div id="items" style="overflow: auto;"></div>
- </div>
- </div>
-
- <audio id="audio-stream-0"></audio>
- <audio id="audio-stream-1"></audio>
- <audio id="audio-stream-2"></audio>
- <audio id="audio-stream-3"></audio>
- <audio id="audio-stream-4"></audio>
- <audio id="audio-stream-5"></audio>
-
- <script>
- for (let id of [0, 1, 2, 3, 4, 5]) {
- let audioContext = new AudioContext();
- let analyser = audioContext.createAnalyser();
- let source = audioContext.createMediaElementSource(document.getElementById("audio-stream-" + id));
- let javascriptNode = audioContext.createScriptProcessor(2048, 1, 1);
-
- analyser.fftSize = 1024;
-
- source.connect(analyser);
- analyser.connect(javascriptNode);
- javascriptNode.connect(audioContext.destination);
- source.connect(audioContext.destination);
-
- javascriptNode.onaudioprocess = function() {
- let array = new Uint8Array(analyser.frequencyBinCount);
- analyser.getByteFrequencyData(array);
- let values = 0;
-
- let length = array.length;
- for (let i = 0; i < length; i++) {
- values += (array[i]);
- }
-
- let average = values / length;
- let value = average / (playingStella ? 40 : 60);
-
- if (value < 0) value = 0;
- if (value > 3) {
- value = 3;
- if (document.getElementById("ci-" + id).style.backgroundColor !== "rgb(21, 21, 21)") document.getElementById("ci-" + id).style.backgroundColor = "#ff7c7c";
- } else {
- if (document.getElementById("ci-" + id).style.backgroundColor !== "rgb(21, 21, 21)") document.getElementById("ci-" + id).style.backgroundColor = "#8dff7c";
- }
-
- document.getElementById("meter-" + id + "-inner").style.height = Math.abs(100 - ((value / 3) * 100)) + "%";
- }
- }
-
- window.queue = [];
- window.shouldPlay = false;
-
- function getTime(time) {
- let minutes = Math.floor(time / 60);
- let seconds = Math.floor(time) - minutes * 60;
- let ms = Math.floor(time * 1000) - minutes * 60000 - seconds * 1000;
-
- return "00".substring(0, 2 - minutes.toString().length) + minutes + ":" + "00".substring(0, 2 - seconds.toString().length) + seconds + "." + "000".substring(0, 3 - ms.toString().length) + ms
- }
-
- function togglePlay() {
- if (!shouldPlay) {
- document.getElementById("btn-play").classList.add("active");
- } else {
- document.getElementById("btn-play").classList.remove("active");
- }
-
- shouldPlay = !shouldPlay;
- }
-
- document.getElementById("audio-stream-0").onplay = () => {
- if (playingStella) {
- document.getElementById("ci-0").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-1").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-2").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-3").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-4").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-5").style.backgroundColor = "#8dff7c";
- } else {
- document.getElementById("ci-0").style.backgroundColor = "#8dff7c";
- document.getElementById("ci-1").style.backgroundColor = "#151515";
- document.getElementById("ci-2").style.backgroundColor = "#151515";
- document.getElementById("ci-3").style.backgroundColor = "#151515";
- document.getElementById("ci-4").style.backgroundColor = "#151515";
- document.getElementById("ci-5").style.backgroundColor = "#151515";
- }
-
- window.uiUpdateInt = setInterval(() => {
- document.getElementById("time").innerText = getTime(document.getElementById("audio-stream-0").currentTime) + " / -" + getTime(Math.abs(document.getElementById("audio-stream-0").duration - document.getElementById("audio-stream-0").currentTime));
-
- if (playingStella) {
- let delay = Math.max(
- document.getElementById("audio-stream-1").currentTime - document.getElementById("audio-stream-0").currentTime,
- document.getElementById("audio-stream-2").currentTime - document.getElementById("audio-stream-0").currentTime,
- document.getElementById("audio-stream-3").currentTime - document.getElementById("audio-stream-0").currentTime,
- document.getElementById("audio-stream-4").currentTime - document.getElementById("audio-stream-0").currentTime,
- document.getElementById("audio-stream-5").currentTime - document.getElementById("audio-stream-0").currentTime,
- );
-
- let oldReal;
- let real = oldReal = Math.round(delay * 44100);
- real = "00000".substring(0, 5 - Math.abs(real).toString().length) + Math.abs(real);
- let realMs = "000".substring(0, 3 - Math.abs(Math.round(real / 44.100)).toString().length) + Math.abs(Math.round(real / 44.100));
-
- document.getElementById("delay").innerText = (oldReal > 0 ? "+" : (oldReal < 0 ? "-" : "0")) + real + " samples";
- document.getElementById("delay-ms").innerText = (oldReal > 0 ? "+" : (oldReal < 0 ? "-" : "0")) + realMs + " ms";
- } else {
- document.getElementById("delay").innerText = "------ samples";
- document.getElementById("delay-ms").innerText = "---- ms";
- }
- });
- }
-
- document.getElementById("audio-stream-0").onpause = () => {
- clearInterval(window.uiUpdateInt);
- document.getElementById("ci-0").style.backgroundColor = "#151515";
- document.getElementById("ci-1").style.backgroundColor = "#151515";
- document.getElementById("ci-2").style.backgroundColor = "#151515";
- document.getElementById("ci-3").style.backgroundColor = "#151515";
- document.getElementById("ci-4").style.backgroundColor = "#151515";
- document.getElementById("ci-5").style.backgroundColor = "#151515";
- }
-
- document.getElementById("audio-stream-0").onended = () => {
- queue.shift();
- refreshQueue();
-
- if (queue.length > 0) {
- loadSong();
- } else {
- document.getElementById("audio-stream-0").src = "";
- document.getElementById("audio-stream-1").src = "";
- document.getElementById("audio-stream-2").src = "";
- document.getElementById("audio-stream-3").src = "";
- document.getElementById("audio-stream-4").src = "";
- document.getElementById("audio-stream-5").src = "";
- document.getElementById("btn-play").classList.remove("active");
- shouldPlay = false;
- document.getElementById("time").innerText = "--:--.--- / ---:--.---";
- }
- }
-
- function loadSong() {
- window.playingStella = false;
- let id = queue[0];
-
- if (window.preloaded[id] instanceof Stella) {
- document.getElementById("audio-stream-0").src = window.preloaded[id].urls.hpf;
- document.getElementById("audio-stream-1").src = window.preloaded[id].urls.bass;
- document.getElementById("audio-stream-2").src = window.preloaded[id].urls.drums;
- document.getElementById("audio-stream-3").src = window.preloaded[id].urls.other;
- document.getElementById("audio-stream-4").src = window.preloaded[id].urls.piano;
- document.getElementById("audio-stream-5").src = window.preloaded[id].urls.vocals;
- window.playingStella = true;
- } else {
- document.getElementById("audio-stream-0").src = window.preloadedURLs[id];
- }
- }
-
- setInterval(() => {
- if (shouldPlay && document.getElementById("audio-stream-0").paused) {
- document.getElementById("audio-stream-0").play();
-
- if (playingStella) {
- document.getElementById("audio-stream-1").currentTime =
- document.getElementById("audio-stream-2").currentTime =
- document.getElementById("audio-stream-3").currentTime =
- document.getElementById("audio-stream-4").currentTime =
- document.getElementById("audio-stream-5").currentTime = document.getElementById("audio-stream-0").currentTime;
- document.getElementById("audio-stream-1").play();
- document.getElementById("audio-stream-2").play();
- document.getElementById("audio-stream-3").play();
- document.getElementById("audio-stream-4").play();
- document.getElementById("audio-stream-5").play();
- }
- } else if (!shouldPlay && !document.getElementById("audio-stream-0").paused) {
- document.getElementById("audio-stream-0").pause();
-
- if (playingStella) {
- document.getElementById("audio-stream-1").pause();
- document.getElementById("audio-stream-2").pause();
- document.getElementById("audio-stream-3").pause();
- document.getElementById("audio-stream-4").pause();
- document.getElementById("audio-stream-5").pause();
- }
- }
-
- document.getElementById("seek-inner").style.width = ((document.getElementById("audio-stream-0").currentTime / document.getElementById("audio-stream-0").duration) * 100) + "%";
-
- refreshStatus();
- }, 1000);
-
- window.onload = async () => {
- window.songs = await (await fetch("/assets/content/songs.json?_=" + [...crypto.getRandomValues(new Uint8Array(40))].map(m=>('0'+m.toString(16)).slice(-2)).join(''))).json();
-
- document.getElementById("items").innerHTML = Object.entries(songs).map(i => `
- <div onclick="enqueue('${i[0]}');" class="item" id="song-${i[0]}" style="display: grid; grid-template-columns: 1fr 1fr 1fr; color: white;">
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].title}</div>
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].artist}</div>
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].album}</div>
- </div>
- `).join("");
- document.getElementById("app").style.display = "";
- }
-
- function refreshQueue() {
- document.getElementById("queue").innerHTML = queue.map((i, j) => [i, songs[i], j]).map(i => `
- <div class="queue" id="queue-${i[0]}" onclick="playImmediately(${i[2]});" style="display: grid; grid-template-columns: 1fr 1fr 1fr; color: white;">
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].title}</div>
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].artist}</div>
- <div style="white-space: nowrap;overflow: hidden !important;text-overflow: ellipsis;">${i[1].album}</div>
- </div>
- `).join("");
- preloadMore();
- }
-
- function playImmediately(index) {
- let item = queue.splice(index, 1);
- queue.unshift(item);
- document.getElementById("audio-stream-0").pause();
-
- if (playingStella) {
- document.getElementById("audio-stream-1").pause();
- document.getElementById("audio-stream-2").pause();
- document.getElementById("audio-stream-3").pause();
- document.getElementById("audio-stream-4").pause();
- document.getElementById("audio-stream-5").pause();
- }
- refreshQueue();
- loadSong();
- }
-
- function refreshSearch() {
- let query = document.getElementById("query").value.trim().toLowerCase();
-
- if (query === "") {
- Array.from(document.getElementsByClassName("item")).map(i => i.style.display = "grid");
- } else {
- Array.from(document.getElementsByClassName("item")).map(i => {
- let id = i.id.substring(5);
- let song = songs[id];
-
- if (song.title.toLowerCase().includes(query) || song.artist.toLowerCase().includes(query)) {
- i.style.display = "grid";
- } else {
- i.style.display = "none";
- }
- });
- }
- }
-
- function enqueue(id) {
- queue.push(id);
- refreshQueue();
- refreshStatus();
- }
-
- function refreshStatus() {
- if (window.preloaded[queue[0]]) {
- if (document.getElementById("audio-stream-0").paused) {
- document.getElementById("status").innerText = "Ready to play";
- } else {
- if (playingStella) {
- document.getElementById("status").innerText = "Playing 6 streams";
- } else {
- document.getElementById("status").innerText = "Playing 1 stream";
- }
- }
- } else {
- if (queue.length > 0) {
- document.getElementById("status").innerText = "Waiting for audio";
- } else {
- document.getElementById("status").innerText = "Empty queue";
- }
- }
- }
-
- window.preloaded = {};
- window.preloadedURLs = {};
- window.preloadedBlobs = {};
-
- async function preloadMore() {
- for (let i = 0; i < queue.length; i++) {
- if (queue[i]) {
- let id = queue[i];
- let stellaCompatible = await (await fetch("/api/hasStella.php?id=" + id)).text() === "true";
-
- if (stellaCompatible) {
- if (!window.preloaded[id]) {
- window.preloaded[id] = await Stella.build("/assets/content/" + id + ".stella");
- if (i === 0) loadSong();
- }
- } else {
- if (!window.preloaded[id]) {
- if (localStorage.getItem("data-saving") === "true") {
- window.preloaded[id] = await (await fetch("/assets/content/" + id + ".m4a")).arrayBuffer();
- window.preloadedBlobs[id] = new Blob([window.preloaded[id]], { type: "audio/mp4" });
- } else {
- window.preloaded[id] = await (await fetch("/assets/content/" + id + ".flac")).arrayBuffer();
- window.preloadedBlobs[id] = new Blob([window.preloaded[id]], { type: "audio/flac" });
- }
- }
-
- if (!window.preloadedURLs[id]) {
- window.preloadedURLs[id] = URL.createObjectURL(window.preloadedBlobs[id]);
- if (i === 0) loadSong();
- }
- }
-
- refreshStatus();
- }
- }
-
- cleanupPreload();
- }
-
- function cleanupPreload() {
- let keys = Object.keys(window.preloaded).slice(-30);
-
- for (let key of Object.keys(window.preloaded)) {
- if (!keys.includes(key)) {
- if (window.preloadedURLs[key]) URL.revokeObjectURL(window.preloadedURLs[key]);
- delete window.preloaded[key];
- }
- }
- }
- </script>
-</body>
-</html> \ No newline at end of file