Used in 2018 ROF
This commit is contained in:
parent
88c2022927
commit
f155d52b6d
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
Loading…
Reference in New Issue