200 lines
6.5 KiB
HTML
200 lines
6.5 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
|
|
Tibia
|
|
|
|
Copyright (C) 2023, 2024 Orastron Srl unipersonale
|
|
|
|
Tibia is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
Tibia is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Tibia. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
File authors: Stefano D'Angelo, Paolo Marrone
|
|
|
|
-->
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
|
<title>{{=it.product.name}}</title>
|
|
<script type="text/javascript">
|
|
function request(data) {
|
|
return window.webkit.messageHandlers.messageHandler.postMessage(data);
|
|
}
|
|
|
|
function needAudioPermission() {
|
|
return request({ name: "needAudioPermission" });
|
|
}
|
|
|
|
function requestAudioPermission() {
|
|
return request({ name: "requestAudioPermission" });
|
|
}
|
|
|
|
function audioStart() {
|
|
return request({ name: "audioStart" });
|
|
}
|
|
|
|
function audioStop() {
|
|
return request({ name: "audioStop" });
|
|
}
|
|
|
|
function setParameter(index, value) {
|
|
return request({ name: "setParameter", index: index, value: value });
|
|
}
|
|
|
|
function getParameter(index) {
|
|
return request({ name: "getParameter", index: index });
|
|
}
|
|
|
|
var data = {
|
|
buses: {{=JSON.stringify(it.product.buses, null, 2)}},
|
|
parameters: {{=JSON.stringify(it.product.parameters, null, 2)}}
|
|
};
|
|
|
|
function map(index, value) {
|
|
var p = data.parameters[index];
|
|
return p.map == "logarithmic" ? p.minimum * Math.exp((2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))) * value) : p.minimum + (p.maximum - p.minimum) * value;
|
|
}
|
|
|
|
function unmap(index, value) {
|
|
var p = data.parameters[index];
|
|
return p.map == "logarithmic" ? Math.log(value / p.minimum) / (2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))) : (value - p.minimum) / (p.maximum - p.minimum);
|
|
}
|
|
|
|
var hasAudioPermission = true;
|
|
var audioStarted = false;
|
|
var topButtonElem;
|
|
var outParamInterval;
|
|
|
|
window.onload = async function () {
|
|
topButtonElem = document.getElementById("topButton");
|
|
var paramsElem = document.getElementById("params");
|
|
|
|
for (var i = 0; i < data.buses.length; i++)
|
|
if (data.buses[i].type == "audio" && data.buses[i].direction == "input") {
|
|
hasAudioPermission = !await needAudioPermission();
|
|
break;
|
|
}
|
|
|
|
topButtonElem.value = hasAudioPermission ? "START" : "INIT";
|
|
topButtonElem.addEventListener("click", async function () {
|
|
if (hasAudioPermission) {
|
|
if (audioStarted) {
|
|
clearInterval(outParamInterval);
|
|
await audioStop();
|
|
|
|
paramsElem.innerHTML = "";
|
|
|
|
topButtonElem.value = "START";
|
|
audioStarted = false;
|
|
} else {
|
|
if (await audioStart()) {
|
|
for (var i = 0; i < data.parameters.length; i++) {
|
|
var div = document.createElement("div");
|
|
|
|
var label = document.createElement("label");
|
|
label.setAttribute("for", "p" + i);
|
|
label.innerText = data.parameters[i].name;
|
|
|
|
var range = document.createElement("input");
|
|
range.classList.add("range");
|
|
range.setAttribute("type", "range");
|
|
range.setAttribute("id", "p" + i);
|
|
range.setAttribute("name", "p" + i);
|
|
if (data.parameters[i].isBypass || data.parameters[i].toggled) {
|
|
range.setAttribute("min", 0);
|
|
range.setAttribute("max", 1);
|
|
range.setAttribute("step", 1);
|
|
} else {
|
|
range.setAttribute("min", 0);
|
|
range.setAttribute("max", 1);
|
|
range.setAttribute("step", data.parameters[i].integer ? 1 / (data.parameters[i].maximum - data.parameters[i].minimum) : "any");
|
|
}
|
|
range.value = unmap(i, data.parameters[i].defaultValue);
|
|
if (data.parameters[i].direction == "output")
|
|
range.setAttribute("readonly", "true");
|
|
else {
|
|
let index = i;
|
|
range.addEventListener("input",
|
|
async function (ev) {
|
|
await setParameter(index, map(index, parseFloat(ev.target.value)));
|
|
});
|
|
}
|
|
|
|
div.appendChild(label);
|
|
div.appendChild(document.createElement("br"));
|
|
div.appendChild(range);
|
|
paramsElem.appendChild(div);
|
|
}
|
|
|
|
outParamInterval = setInterval(
|
|
async function () {
|
|
for (var i = 0; i < data.parameters.length; i++)
|
|
if (data.parameters[i].direction == "output") {
|
|
document.getElementById("p" + i).value = unmap(i, await getParameter(i));
|
|
}
|
|
}, 50);
|
|
|
|
topButtonElem.value = "STOP";
|
|
audioStarted = true;
|
|
} else
|
|
alert("Could not start audio");
|
|
}
|
|
} else {
|
|
await requestAudioPermission();
|
|
var interval = setInterval(
|
|
async function () {
|
|
if (!await needAudioPermission()) {
|
|
gotAudioPermission();
|
|
clearInterval(interval);
|
|
}
|
|
}, 50);
|
|
}
|
|
});
|
|
};
|
|
|
|
function gotAudioPermission() {
|
|
hasAudioPermission = true;
|
|
topButtonElem.value = "START";
|
|
}
|
|
</script>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
user-select: none;
|
|
}
|
|
|
|
body {
|
|
margin: 1em;
|
|
}
|
|
|
|
#topButton {
|
|
width: 100%;
|
|
border: 0;
|
|
background-color: #04aa6d;
|
|
color: white;
|
|
padding: 0.5em;
|
|
text-align: center;
|
|
margin-bottom: 1em;
|
|
padding: 1em;
|
|
}
|
|
|
|
.range {
|
|
width: 90%;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<input id="topButton" type="button">
|
|
<div id="params"></div>
|
|
</body>
|
|
</html>
|