diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..86ba1a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+music/
diff --git a/2023-a.html b/2023-a.html
new file mode 100644
index 0000000..b62d865
--- /dev/null
+++ b/2023-a.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+ ROF 2023-A
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - 0-0 God.mp3
+ - 01 Drums of Belfast.m4a
+ - 04 The Jura Wedding Reels.m4a
+ - 07 Geantraí.mp3
+ - 15 The Sweets of May (Ceili).mp3
+ - Ni Liom Fein - 121.mp3
+ - --- Maria ---
+ - --- St Patrick's Day---
+ - 2-05 Wellerman – Sea Shanty.m4a
+ - 01 Boogie Woogie Bugle Boy.m4a
+ - Amsterdam Blues Extra A Original.mp3
+ - ----- Intermission -----
+ - 2 - 1 - Adventure of a Lifetime.m4a
+ - 2 - 2 - El Portorico de los Machetes.mp3
+ - 2 - 3 - Orange Rouge.wav
+ - 2 - 4 - Live Set
+ - 2 - 5 - Live Set
+ - 2 - 6 - Pink Panther.mp3
+ - 2 - 7 - Alegrias.wav
+ - 2 - 8 - Rock n Rince.mp3
+ - 2 - 9 - Finale 1.m4a
+ - 2 - 9 - Finale 2.mp3
+
+
+
diff --git a/playlist.js b/playlist.mjs
similarity index 59%
rename from playlist.js
rename to playlist.mjs
index c297b33..e3397e3 100644
--- a/playlist.js
+++ b/playlist.mjs
@@ -1,16 +1,127 @@
-// jshint asi:true
+let ctx = new AudioContext()
-// HTML5 Playlist by Neale Pickett
-// https://github.com/nealey/playlst
+const Millisecond = 1
+const Second = 1000 * Millisecond
+const Minute = 60 * Second
+class Track {
+ constructor() {
+ this.startedAt = 0
+ this.pausedAt = 0
+ console.log(this)
+ window.track = this
+ }
-var base = "."
+ async load(url) {
+ this.filename = url.split("/").pop()
+ let resp = await fetch(url)
+ let buf = await resp.arrayBuffer()
+ this.abuf = await ctx.decodeAudioData(buf)
+ }
-function loadTrack(e) {
+ Duration() {
+ if (this.abuf) {
+ return this.abuf.duration * Second
+ }
+ return 0
+ }
+}
+
+class Playlist {
+ constructor(base="./music") {
+ this.base = base
+ this.list = {}
+ this.current = null
+ this.startedAt = 0
+ this.pausedAt = 0
+ }
+
+ async add(filename) {
+ let track = new Track()
+ this.list[filename] = track
+ await track.load(`${this.base}/${filename}`)
+ return track
+ }
+
+ async load(filename) {
+ this.stop()
+ this.current = this.list[filename]
+ if (!this.current) {
+ this.current = await this.add(filename)
+ }
+ }
+
+ play(pos=null) {
+ let offset = this.pausedAt / Second
+ if (pos) {
+ offset = this.current.abuf.duration * pos
+ }
+ if (this.startedAt) {
+ this.stop()
+ }
+ console.log(offset)
+ this.source = new AudioBufferSourceNode(ctx)
+ this.source.buffer = this.current.abuf
+ this.source.connect(ctx.destination)
+ this.source.start(0, offset)
+ this.startedAt = (ctx.currentTime - offset) * Second
+ this.pausedAt = 0
+ }
+
+ pause() {
+ let pos = this.CurrentTime()
+ this.stop()
+ this.pausedAt = pos
+ }
+
+ stop() {
+ if (this.source) {
+ this.source.disconnect()
+ this.source.stop()
+ }
+ this.pausedAt = 0
+ this.startedAt = 0
+ }
+
+ PlayPause() {
+ console.log("Play/Pause")
+ if (this.startedAt) {
+ this.pause()
+ } else {
+ this.play()
+ }
+ }
+
+ Seek(pos) {
+ if (this.startedAt) {
+ this.play(pos)
+ } else {
+ this.pausedAt = this.Duration() * pos
+ }
+ }
+
+ CurrentTime() {
+ if (this.startedAt) {
+ return ctx.currentTime*Second - this.startedAt
+ }
+ if (this.pausedAt) {
+ return this.pausedAt
+ }
+ return 0
+ }
+
+ Duration() {
+ return this.current.Duration()
+ }
+}
+
+let playlist = new Playlist()
+window.playlist = playlist
+
+async function loadTrack(e) {
let li = e.target
- let audio = document.querySelector("#audio")
- audio.src = base + "/" + li.textContent
- audio.load()
+
+ playlist.load(li.textContent)
// Update "current"
for (let cur of document.querySelectorAll(".current")) {
@@ -50,9 +161,9 @@ function ended() {
next()
}
-function mmss(s) {
- let mm = Math.floor(s / 60)
- let ss = Math.floor(s % 60)
+function mmss(duration) {
+ let mm = Math.floor(duration / Minute)
+ let ss = Math.floor((duration / Second) % 60)
if (ss < 10) {
ss = "0" + ss
@@ -60,28 +171,21 @@ function mmss(s) {
return mm + ":" + ss
}
-function durationchange(e) {
- let duration = e.target.duration
-
- document.querySelector("#duration").textContent = mmss(duration)
- timeupdate(e)
-}
-
function volumechange(e) {
document.querySelector("#vol").value = e.target.volume
}
-function timeupdate(e) {
- let currentTime = e.target.currentTime
- let duration = e.target.duration || 1
+function timeupdate() {
+ let currentTime = playlist.CurrentTime()
+ let duration = playlist.Duration()
let tgt = document.querySelector("#currentTime")
let pos = document.querySelector("#pos")
pos.value = currentTime / duration
tgt.textContent = mmss(currentTime)
- if (duration - currentTime < 20) {
+ if (duration - currentTime < 20 * Second) {
tgt.classList.add("fin")
} else {
tgt.classList.remove("fin")
@@ -90,9 +194,7 @@ function timeupdate(e) {
function setPos(e) {
let val = e.target.value
- let audio = document.querySelector("#audio")
-
- audio.currentTime = audio.duration * val
+ playlist.Seek(val)
}
function setGain(e) {
@@ -105,13 +207,9 @@ function setGain(e) {
function keydown(e) {
let audio = document.querySelector("#audio")
- switch (event.key) {
+ switch (e.key) {
case " ": // space bar
- if (audio.paused) {
- audio.play()
- } else {
- audio.pause()
- }
+ playlist.PlayPause()
break
case "ArrowDown": // Next track
@@ -189,12 +287,13 @@ function run() {
document.querySelector("#pos").addEventListener("input", setPos)
document.querySelector("#vol").addEventListener("input", setGain)
audio.addEventListener("ended", ended)
- audio.addEventListener("timeupdate", timeupdate)
- audio.addEventListener("durationchange", durationchange)
audio.addEventListener("volumechange", volumechange)
for (let li of document.querySelectorAll("#playlist li")) {
+ playlist.add(li.textContent)
li.addEventListener("click", loadTrack)
}
+
+ setInterval(() => timeupdate(), 250 * Millisecond)
document.querySelector("#vol").value = audio.volume