Used in 2018 ROF

This commit is contained in:
Neale Pickett 2018-03-18 18:07:08 +00:00
parent 88c2022927
commit f155d52b6d
4 changed files with 275 additions and 0 deletions

26
README.md Normal file
View File

@ -0,0 +1,26 @@
This is a pure HTML5 playlist,
specifically designed for theater work.
You give it a play list, and it cues them up,
one at a time.
Press "play" to play the cued-up track,
use the arrow keys to select a different track.
The normal browser media controls are available too.
You can also plug a Korg NanoKontrol 2 in,
and use its play/stop/prev/next buttons,
as well as the first fader.
This features a massive time display,
so everybody else in the control booth can see how far into the track you are,
for things like light cues, etc.
Just drop these three files in the directory with all your tracks,
and edit the HTML to have the right list of tracks.
You can have the same track more than once, if you want.
Author
------
Neale Pickett

50
playlist.css Normal file
View File

@ -0,0 +1,50 @@
body {
background-color: #000;
color: #fa4;
font-family: sans-serif;
}
audio {
min-width: 40em;
}
#currentTime {
background-color: #001;
float: right;
font-size: 1500%;
font-family: "Roboto", "Droid Sans Mono", monospace;
}
#controls {
padding: 1em;
}
#controls a {
font-size: 200%;
padding: 0.5em;
}
#playlist {
width: auto;
}
.current {
background-color: #224;
}
@keyframes pulse {
0% {
background-color: #430;
}
25% {
background-color: inherit;
}
75% {
background-color: inherit;
}
100% {
background-color: #430;
}
}
.fin {
animation: pulse 1s infinite;
}

40
playlist.html Normal file
View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>2018 ROF</title>
<meta name="viewport" content="width=device-width">
<link href="playlist.css" rel="stylesheet">
<script src="playlist.js"></script>
</head>
<body>
<audio preload id="audio" controls="controls">
Your browser does not support HTML5 Audio!
</audio>
<div id="currentTime">00:00</div>
<div id="controls">
<a id="prev"></a>
<a id="next"></a>
</div>
<ul id="playlist">
<li>0-0 God.mp3</li>
<li>1-2 Amsterdam Blues.mp3</li>
<li>1-3 Minute 5.m4a</li>
<li>1-4 Axial Symmetry (Tommy's Tarbukas).mp3</li>
<li>1-5 I'm Here Because I'm Here (Song).mp3</li>
<li>1-6 The Cuil Aodha Jig - The Lark on the Strand.m4a</li>
<li>1-7 Shetland Reels long.mp3</li>
<li>1-8 Ellery Klein & Ryan Lacey - King of the Faeries 124.mp3</li>
<li>1-9 Ni Liom Fein - 121.mp3</li>
<li>2-1 2018 ROF Disco_r1_session_2018-01-27_12.33.mp3</li>
<li>2-2 Gillie (Short).mp3</li>
<li>2-3 Scottiche 113.mp3</li>
<li>2-4 The Hunt 70 Kevin Joyce (ab).wav</li>
<li>2-5 Slow Jig ROF 2018.1.mp3</li>
<li>2-6 Matt & Nat's Faster 120.mp3</li>
<li>2-7 Neale Pickett - 2018 ROF Curtain (original).mp3</li>
</ul>
</body>
</html>

159
playlist.js Normal file
View File

@ -0,0 +1,159 @@
var base = ".";
function loadTrack(e) {
let li = e.srcElement;
let audio = document.querySelector("#audio");
audio.src = base + "/" + li.textContent;
audio.load();
// Update "current"
for (let cur of document.querySelectorAll(".current")) {
cur.classList.remove("current");
}
li.classList.add("current");
}
function clickOn(element) {
let e = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true
});
element.dispatchEvent(e);
}
function prev() {
let cur = document.querySelector(".current");
let prev = cur.previousElementSibling;
if (prev) {
cur = prev;
}
clickOn(cur);
}
function next() {
let cur = document.querySelector(".current");
let next = cur.nextElementSibling;
if (next) {
cur = next;
}
clickOn(cur);
}
function ended() {
next();
}
function mmss(s) {
let mm = Math.floor(s / 60);
let ss = Math.floor(s % 60);
if (ss < 10) {
ss = "0" + ss;
}
return mm + ":" + ss;
}
function timeupdate(e) {
let currentTime = e.srcElement.currentTime;
let duration = e.srcElement.duration;
let tgt = document.querySelector("#currentTime");
document.querySelector("#currentTime").textContent = mmss(currentTime);
if (duration - currentTime < 20) {
tgt.classList.add("fin");
} else {
tgt.classList.remove("fin");
}
}
function keydown(e) {
let audio = document.querySelector("#audio");
switch (event.key) {
case " ": // space bar
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
break;
case "ArrowDown": // Next track
next();
break;
case "ArrowUp": // Previous track
prev();
break;
}
}
function midiMessage(e) {
let audio = document.querySelector("#audio");
let data = e.data;
let ctrl = data[1];
let val = data[2];
if (data[0] == 176) {
switch (ctrl) {
case 0: // master volume slider
audio.volume = val / 127;
break;
case 41: // play button
if (val == 127) {
audio.play();
}
break;
case 42: // stop button
if (val == 127) {
audio.pause();
}
break;
case 58: // prev button
if (val == 127) {
prev();
}
break;
case 59: // next button
if (val == 127) {
next();
}
break;
}
}
}
function handleMidiAccess(access) {
for (let input of access.inputs.values()) {
input.addEventListener("midimessage", midiMessage);
}
}
function run() {
let audio = document.querySelector("#audio");
// Set up events:
// - Prev/Next buttons
// - ended / timeupdate events on audio
// - Track items
document.querySelector("#prev").addEventListener("click", prev);
document.querySelector("#next").addEventListener("click", next);
audio.addEventListener("ended", ended);
audio.addEventListener("timeupdate", timeupdate);
for (let li of document.querySelectorAll("#playlist li")) {
li.addEventListener("click", loadTrack);
}
// Bind keypress events
// - space: play/pause
//
document.addEventListener("keydown", keydown);
// Load up first track
document.querySelector("#playlist li").classList.add("current");
prev();
navigator.requestMIDIAccess().then(handleMidiAccess);
}
window.addEventListener("load", run);