Auto-advance track
This commit is contained in:
parent
72741a64d1
commit
ceab3b137a
|
@ -31,6 +31,8 @@
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<a id="prev">⏮</a>
|
<a id="prev">⏮</a>
|
||||||
<a id="next">⏭</a>
|
<a id="next">⏭</a>
|
||||||
|
<a id="pause">⏸️</a>
|
||||||
|
<a id="play">▶️</a>
|
||||||
|
|
||||||
<input type="range" min="0.0" max="1.0" list="tickmarks" step="any" id="vol">
|
<input type="range" min="0.0" max="1.0" list="tickmarks" step="any" id="vol">
|
||||||
<datalist id="tickmarks">
|
<datalist id="tickmarks">
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
<li>2-05 Wellerman – Sea Shanty.m4a</li>
|
<li>2-05 Wellerman – Sea Shanty.m4a</li>
|
||||||
<li>01 Boogie Woogie Bugle Boy.m4a</li>
|
<li>01 Boogie Woogie Bugle Boy.m4a</li>
|
||||||
<li>Amsterdam Blues Extra A Original.mp3</li>
|
<li>Amsterdam Blues Extra A Original.mp3</li>
|
||||||
|
<li>06 Mundo Pequeño _ Small World.mp3</li>
|
||||||
</ol>
|
</ol>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
<div id="controls">
|
<div id="controls">
|
||||||
<a id="prev">⏮</a>
|
<a id="prev">⏮</a>
|
||||||
<a id="next">⏭</a>
|
<a id="next">⏭</a>
|
||||||
|
<a id="pause">⏸️</a>
|
||||||
|
<a id="play">▶️</a>
|
||||||
|
|
||||||
<input type="range" min="0.0" max="1.0" list="tickmarks" step="any" id="vol">
|
<input type="range" min="0.0" max="1.0" list="tickmarks" step="any" id="vol">
|
||||||
<datalist id="tickmarks">
|
<datalist id="tickmarks">
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
<li>2-05 Wellerman – Sea Shanty.m4a</li>
|
<li>2-05 Wellerman – Sea Shanty.m4a</li>
|
||||||
<li>01 Boogie Woogie Bugle Boy.m4a</li>
|
<li>01 Boogie Woogie Bugle Boy.m4a</li>
|
||||||
<li>Amsterdam Blues Extra A Original.mp3</li>
|
<li>Amsterdam Blues Extra A Original.mp3</li>
|
||||||
|
<li>06 Mundo Pequeño _ Small World.mp3</li>
|
||||||
</ol>
|
</ol>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -38,6 +38,7 @@ audio {
|
||||||
#playlist {
|
#playlist {
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current {
|
.current {
|
||||||
|
|
76
playlist.mjs
76
playlist.mjs
|
@ -6,7 +6,7 @@ const Minute = 60 * Second
|
||||||
|
|
||||||
class Track {
|
class Track {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.startedAt = 0
|
this.startedAt = false
|
||||||
this.pausedAt = 0
|
this.pausedAt = 0
|
||||||
window.track = this
|
window.track = this
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ class Playlist {
|
||||||
this.base = base
|
this.base = base
|
||||||
this.list = {}
|
this.list = {}
|
||||||
this.current = null
|
this.current = null
|
||||||
|
this.gain = new GainNode(ctx)
|
||||||
|
this.gain.connect(ctx.destination)
|
||||||
this.Stop()
|
this.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +94,7 @@ class Playlist {
|
||||||
this.Stop()
|
this.Stop()
|
||||||
this.source = new AudioBufferSourceNode(ctx)
|
this.source = new AudioBufferSourceNode(ctx)
|
||||||
this.source.buffer = this.current.abuf
|
this.source.buffer = this.current.abuf
|
||||||
this.source.connect(ctx.destination)
|
this.source.connect(this.gain)
|
||||||
this.source.start(0, offset)
|
this.source.start(0, offset)
|
||||||
this.startedAt = ctx.currentTime - offset
|
this.startedAt = ctx.currentTime - offset
|
||||||
}
|
}
|
||||||
|
@ -109,17 +111,25 @@ class Playlist {
|
||||||
this.source.stop()
|
this.source.stop()
|
||||||
}
|
}
|
||||||
this.pausedAt = 0
|
this.pausedAt = 0
|
||||||
this.startedAt = -1
|
this.startedAt = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Playing() {
|
Playing() {
|
||||||
if (this.startedAt > -1) {
|
if (this.startedAt !== false) {
|
||||||
let pos = ctx.currentTime - this.startedAt
|
let pos = ctx.currentTime - this.startedAt
|
||||||
return pos < this.Duration()
|
return pos < this.Duration()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ended() {
|
||||||
|
if (this.startedAt !== false) {
|
||||||
|
let pos = ctx.currentTime - this.startedAt
|
||||||
|
return pos > this.Duration()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
PlayPause() {
|
PlayPause() {
|
||||||
if (this.Playing()) {
|
if (this.Playing()) {
|
||||||
this.Pause()
|
this.Pause()
|
||||||
|
@ -149,6 +159,10 @@ class Playlist {
|
||||||
Duration() {
|
Duration() {
|
||||||
return this.current.Duration()
|
return this.current.Duration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetGain(value) {
|
||||||
|
this.gain.gain.value = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let playlist = new Playlist()
|
let playlist = new Playlist()
|
||||||
|
@ -184,6 +198,16 @@ function prev() {
|
||||||
clickOn(cur)
|
clickOn(cur)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function play() {
|
||||||
|
if (!playlist.Playing()) {
|
||||||
|
playlist.Play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pause() {
|
||||||
|
playlist.Pause()
|
||||||
|
}
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
let cur = document.querySelector(".current")
|
let cur = document.querySelector(".current")
|
||||||
let next = cur.nextElementSibling
|
let next = cur.nextElementSibling
|
||||||
|
@ -193,10 +217,6 @@ function next() {
|
||||||
clickOn(cur)
|
clickOn(cur)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ended() {
|
|
||||||
next()
|
|
||||||
}
|
|
||||||
|
|
||||||
function mmss(duration) {
|
function mmss(duration) {
|
||||||
let mm = Math.floor(duration / Minute)
|
let mm = Math.floor(duration / Minute)
|
||||||
let ss = Math.floor((duration / Second) % 60)
|
let ss = Math.floor((duration / Second) % 60)
|
||||||
|
@ -207,12 +227,8 @@ function mmss(duration) {
|
||||||
return mm + ":" + ss
|
return mm + ":" + ss
|
||||||
}
|
}
|
||||||
|
|
||||||
function volumechange(e) {
|
|
||||||
document.querySelector("#vol").value = e.target.volume
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function update() {
|
||||||
function timeupdate() {
|
|
||||||
let currentTime = playlist.CurrentTime() * Second
|
let currentTime = playlist.CurrentTime() * Second
|
||||||
let duration = playlist.Duration() * Second
|
let duration = playlist.Duration() * Second
|
||||||
let cur = document.querySelector("#currentTime")
|
let cur = document.querySelector("#currentTime")
|
||||||
|
@ -221,13 +237,17 @@ function timeupdate() {
|
||||||
|
|
||||||
pos.value = currentTime / duration
|
pos.value = currentTime / duration
|
||||||
|
|
||||||
|
if (playlist.Ended()) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
cur.textContent = mmss(currentTime)
|
cur.textContent = mmss(currentTime)
|
||||||
if (duration - currentTime < 20 * Second) {
|
if (duration - currentTime < 20 * Second) {
|
||||||
cur.classList.add("fin")
|
cur.classList.add("fin")
|
||||||
} else {
|
} else {
|
||||||
cur.classList.remove("fin")
|
cur.classList.remove("fin")
|
||||||
}
|
}
|
||||||
remain.textContent = mmss(duration - currentTime)
|
remain.textContent = "-" + mmss(duration - currentTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPos(e) {
|
function setPos(e) {
|
||||||
|
@ -237,9 +257,7 @@ function setPos(e) {
|
||||||
|
|
||||||
function setGain(e) {
|
function setGain(e) {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
let audio = document.querySelector("#audio")
|
playlist.SetGain(val)
|
||||||
|
|
||||||
audio.volume = val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function keydown(e) {
|
function keydown(e) {
|
||||||
|
@ -268,15 +286,14 @@ function midiMessage(e) {
|
||||||
if ((data[0] == 0xb0) || (data[0] == 0xbf)) {
|
if ((data[0] == 0xb0) || (data[0] == 0xbf)) {
|
||||||
switch (ctrl) {
|
switch (ctrl) {
|
||||||
case 0: // master volume slider
|
case 0: // master volume slider
|
||||||
|
let volumeSlider = document.querySelector("#vol")
|
||||||
audio.volume = val / 127
|
audio.volume = val / 127
|
||||||
document.querySelector("#vol").value = audio.volume
|
volumeSlider.value = audio.volume
|
||||||
|
volumeSlider.dispatchEvent(new Event("input"))
|
||||||
break
|
break
|
||||||
case 41: // play button
|
case 41: // play button
|
||||||
if (val == 127) {
|
if (val == 127) {
|
||||||
// The first time, the browser will reject this,
|
play()
|
||||||
// because it doesn't consider MIDI input user interaction,
|
|
||||||
// so it looks like an autoplaying video.
|
|
||||||
playlist.Play()
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 42: // stop button
|
case 42: // stop button
|
||||||
|
@ -305,27 +322,24 @@ function handleMidiAccess(access) {
|
||||||
|
|
||||||
for (let output of access.outputs.values()) {
|
for (let output of access.outputs.values()) {
|
||||||
if (output.name == "nanoKONTROL2 MIDI 1") {
|
if (output.name == "nanoKONTROL2 MIDI 1") {
|
||||||
controller = output
|
|
||||||
output.send([0xf0, 0x42, 0x40, 0x00, 0x01, 0x13, 0x00, 0x00, 0x00, 0x01, 0xf7]); // Native Mode (lets us control LEDs, requires sysex privilege)
|
output.send([0xf0, 0x42, 0x40, 0x00, 0x01, 0x13, 0x00, 0x00, 0x00, 0x01, 0xf7]); // Native Mode (lets us control LEDs, requires sysex privilege)
|
||||||
output.send([0xbf, 0x2a, 0x7f]); // Stop
|
output.send([0xbf, 0x20, 0x7f]); // S0 LED on
|
||||||
output.send([0xbf, 0x29, 0x7f]); // Play
|
output.send([0xbf, 0x29, 0x7f]); // Play LED on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
let audio = document.querySelector("#audio")
|
|
||||||
|
|
||||||
// Set up events:
|
// Set up events:
|
||||||
// - Prev/Next buttons
|
// - Prev/Next buttons
|
||||||
// - ended / timeupdate events on audio
|
// - ended / timeupdate events on audio
|
||||||
// - Track items
|
// - Track items
|
||||||
document.querySelector("#prev").addEventListener("click", prev)
|
document.querySelector("#prev").addEventListener("click", prev)
|
||||||
|
document.querySelector("#pause").addEventListener("click", pause)
|
||||||
|
document.querySelector("#play").addEventListener("click", play)
|
||||||
document.querySelector("#next").addEventListener("click", next)
|
document.querySelector("#next").addEventListener("click", next)
|
||||||
document.querySelector("#pos").addEventListener("input", setPos)
|
document.querySelector("#pos").addEventListener("input", setPos)
|
||||||
document.querySelector("#vol").addEventListener("input", setGain)
|
document.querySelector("#vol").addEventListener("input", setGain)
|
||||||
audio.addEventListener("ended", ended)
|
|
||||||
audio.addEventListener("volumechange", volumechange)
|
|
||||||
for (let li of document.querySelectorAll("#playlist li")) {
|
for (let li of document.querySelectorAll("#playlist li")) {
|
||||||
li.classList.add("loading")
|
li.classList.add("loading")
|
||||||
li.addEventListener("click", loadTrack)
|
li.addEventListener("click", loadTrack)
|
||||||
|
@ -335,7 +349,7 @@ function run() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(() => timeupdate(), 250 * Millisecond)
|
setInterval(() => update(), 250 * Millisecond)
|
||||||
|
|
||||||
document.querySelector("#vol").value = audio.volume
|
document.querySelector("#vol").value = audio.volume
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue