Add /beeper

This commit is contained in:
Sofia 2019-04-17 21:24:05 +03:00
parent 2c6402ff4b
commit a68dd83183
4 changed files with 361 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Beeper!</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="main.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body onload="main()">
<div class="content">
<p class="timer"><span id="seconds">0</span><span class="timer-milliseconds">.<span id="milliseconds">00</span></span></p>
<div class="padding">
<p class="inline">Do a beep at </p>
<div class="input-container"><button id="minus" class="scroller">-</button><input id="time-input"
placeholder="5"></input><button id="plus" class="scroller">+</button></div>
<p class="inline">second intervals</p>
</div>
<p class="padding"><button id="begin">Begin!</button></p>
<div id="audiocontrols">
<div class="inline">
<p>Volume (<span id="volume">100</span>%):</p>
<input class="padding" id="volume-slider" type="range" min="0" max="100" value="100" class="slider">
</div>
<div class="inline">
<p>Custom audio file:</p>
<input id="file" type="file" accept="audio/*">
<p id="audiotext">default audio</p>
</div>
</div>
<div class="footnote">
<p><a href="https://opengameart.org/content/select-beep-and-error">Default beep sound by dklon</a></p>
</div>
<audio id="audio" controls>
<source id="audiosource" src="beep.ogg">
</audio>
</div>
</body>
</html>

View File

@ -0,0 +1,160 @@
var beeperBegun = false;
var beepInterval = 0;
var beepTimeCounter = 0;
var intervalId = 0;
var timeChangedWhileBegun = false;
var lastSec = -1;
var showBeep = 0;
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
function main() {
timeChanged();
updateInvalidness();
document.getElementById("plus").onclick = () => changeSeconds(1);
document.getElementById("minus").onclick = () => changeSeconds(-1);
document.getElementById("time-input").onchange = () => {
timeChanged();
updateInvalidness();
};
document.getElementById("begin").onclick = toggle;
var audio = document.getElementById("audio");
let slider = document.getElementById("volume-slider");
document.getElementById("volume-slider").onchange = () => {
audio.volume = (slider.value / 100);
document.getElementById("volume").innerText = slider.value;
};
document.getElementById("file").addEventListener('change', () => {
var file = document.getElementById("file").files[0];
document.getElementById("audiosource").setAttribute("src", URL.createObjectURL(file));
document.getElementById("audio").load();
});
document.getElementById("audio").addEventListener("loadeddata", (event) => {
document.getElementById("audiotext").innerText = "Loaded audio";
});
document.getElementById("audio").addEventListener("loadstart", (event) => {
document.getElementById("audiotext").innerText = "Loading/Error";
});
console.log("Beeper initialized!");
}
function isTimeValid() {
value = document.getElementById("time-input").value;
if (value != "" && (isNaN(value) || value < 1)) {
return false;
}
return true;
}
function getTime() {
if (!isTimeValid()) {
return 1;
}
value = document.getElementById("time-input").value;
if (value == "") {
return 5;
}
return parseFloat(value);
}
function updateInvalidness() {
input = document.getElementById("time-input");
if (!isTimeValid()) {
input.classList = "invalid";
} else {
input.classList = "";
}
}
function changeSeconds(diff) {
value = document.getElementById("time-input").value;
if (!isNaN(value)) {
if (value == "") {
value = 5;
}
value = parseFloat(value);
if ((value + diff) >= 1 || diff > 0) {
input.value = value + diff;
updateInvalidness();
timeChanged();
}
}
}
function timeChanged() {
if (isTimeValid()) {
if (beeperBegun) {
timeChangedWhileBegun = true;
return;
}
time = getTime();
sec = Math.floor(time);
millis = Math.floor((time - sec) * 100) / 100;
millis = Intl.NumberFormat("en-US", { minimumFractionDigits: 2 }).format(millis);
millis = ("" + millis).slice(2);
seconds = document.getElementById("seconds").innerText = sec;
milliseconds = document.getElementById("milliseconds").innerText = millis;
beepInterval = getTime();
beepTimeCounter = beepInterval;
}
}
function toggle() {
var button = document.getElementById("begin");
if (!beeperBegun && !isTimeValid()) {
return;
}
beeperBegun = !beeperBegun;
if (beeperBegun) {
button.innerText = "Stop!";
intervalId = setInterval(update, 10);
} else {
button.innerText = "Begin!";
clearInterval(intervalId);
if (timeChangedWhileBegun) {
timeChangedWhileBegun = false;
timeChanged();
}
lastSec = -1;
showBeep = 0;
document.title = "Beeper!";
document.getElementById("audio").pause()
}
}
function update() {
var seconds = document.getElementById("seconds");
var milliseconds = document.getElementById("milliseconds");
beepTimeCounter -= 0.01;
showBeep -= 0.1;
if (beepTimeCounter <= 0) {
beepTimeCounter = beepInterval;
showBeep = 0.5;
document.getElementById("audio").fastSeek(0)
document.getElementById("audio").play()
}
var sec = Math.floor(beepTimeCounter);
seconds.innerText = sec;
var millis = Math.floor((beepTimeCounter - sec) * 100) / 100;
millis = Intl.NumberFormat("en-US", { minimumFractionDigits: 2 }).format(millis);
millis = ("" + millis).slice(2);
milliseconds.innerText = millis;
if (lastSec != sec) {
lastSec = sec;
if (showBeep > 0) {
document.title = "Beeeep!";
} else {
document.title = "Beeper - " + sec;
}
}
}

View File

@ -0,0 +1,154 @@
:root {
font-family: Helvetica, sans-serif;
}
* {
margin: 0;
padding: 0;
}
body {
width: 100%;
height: 100%;
background-color: #44444a;
font-size: 1.1em;
}
.padding {
margin-bottom: 2em;
}
.content {
padding-top: 10vh;
text-align: center;
color: #eee;
}
.timer {
font-size: 15vw;
margin: 0;
}
.timer-milliseconds {
font-size: 25%;
font-family: Iosevka, monospace;
}
.inline {
display: inline-block;
}
.input-container {
display: inline-block;
height: 1.9em;
}
button {
display: inline-block;
border: none;
margin: 0;
padding: 0.3em;
padding-left: 0.6em;
padding-right: 0.6em;
font-size: 1em;
transition: 0.2s;
font-family: helvetica, sans-serif;
background-color: #ddd;
font-size: 1em;
}
audio {
display: none;
}
.scroller {
height: 100%;
}
.scroller:first-child {
border-top-left-radius: 0.3em;
border-bottom-left-radius: 0.3em;
background-color: #eb6868;
}
.scroller:last-child {
border-top-right-radius: 0.3em;
border-bottom-right-radius: 0.3em;
background-color: #77e777;
}
.scroller:first-child:hover {
background-color: #dd5151;
}
.scroller:last-child:hover {
background-color: #53db53;
}
button:hover {
background-color: #c0c0c0;
}
#time-input {
border: none;
background: none;
position: relative;
background-color: #eee;
max-width: 5ch;
height: 100%;
text-align: center;
transition: 0.2s;
font-size: 1em;
font-family: helvetica, sans-serif;
}
#volume-slider {
display: inline-block;
}
#time-input:hover {
background-color: #cbcbcb;
}
#audiocontrols {
display: inline-flex;
width: 50vw;
}
#audiocontrols > * {
width: 50%;
}
#file {
width: 10em;
}
.invalid {
background-color: #dd7979
}
.invalid:hover {
background-color: #c56161
}
.footnote {
position: absolute;
width: 100%;
text-align: center;
bottom: 0;
padding-bottom: 2em;
}
.footnote a {
color: #c7c5ee;
}
@media (max-width: 900px) {
.content {
padding: 0;
}
.timer {
font-size: 40vw;
}
}