diff --git a/src/audio.js b/src/audio.js
new file mode 100644
index 0000000..d3a22d1
--- /dev/null
+++ b/src/audio.js
@@ -0,0 +1,45 @@
+let audioContext;
+let gainNode;
+
+function startAudio() {
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
+ gainNode = audioContext.createGain();
+ gainNode.gain.value = 0;
+ gainNode.connect(audioContext.destination);
+}
+
+function muter() {
+ fadeOutVolume();
+}
+
+function unMute() {
+ startAudio();
+ fadeInVolume();
+}
+
+function fadeInVolume() {
+ gainNode.gain.setValueAtTime(0, audioContext.currentTime); // Start at 0
+ gainNode.gain.linearRampToValueAtTime(1, audioContext.currentTime + 2); // Fade to full volume
+}
+
+function fadeOutVolume() {
+ gainNode.gain.setValueAtTime(1, audioContext.currentTime); // Start at 1
+ gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 2); // Fade to 0
+}
+
+function playSound(instrument) {
+ if (interacted) {
+ // const source = audioContext.createBufferSource();
+ const samples = instrument.samples;
+ const sampleKeys = Object.keys(samples);
+ const numSamples = sampleKeys.length;
+ const randomSampleNumber = Math.floor(Math.random() * (numSamples - 0));
+ // const randomKey =
+ // sampleKeys[randomSampleNumber];
+ sendMidiMessage(instrument.midiChannelName, randomSampleNumber);
+
+ // source.buffer = samples[`${randomKey}`];
+ // source.connect(gainNode);
+ // source.start();
+ }
+}
diff --git a/src/conductor.js b/src/conductor.js
new file mode 100644
index 0000000..7f93875
--- /dev/null
+++ b/src/conductor.js
@@ -0,0 +1,133 @@
+class Conductor {
+ constructor() {}
+
+ showingWhichContent;
+ interacted = true;
+
+ init() {
+ const instrumentsKey = document.getElementById("instrument-key-div");
+
+ for (const instrument of instNames) {
+ const keyDiv = document.createElement("div");
+ const keySvg = document.createElement("object");
+ const keyName = document.createElement("div");
+ keyName.innerText = instrument.toUpperCase();
+ keySvg.type = "image/svg+xml";
+ keySvg.data = instruments[instrument].image;
+ keyDiv.appendChild(keySvg);
+ keyDiv.appendChild(keyName);
+ keyDiv.classList.add("instrument-key");
+ instrumentsKey.appendChild(keyDiv);
+ }
+
+ const numStaves = 6;
+ const sheetWindow = document.getElementById("music-window");
+
+ for (let i = 1; i <= numStaves; i++) {
+ const staveWrapper = document.createElement("div");
+ staveWrapper.classList.add(`stave-wrapper`);
+ staveWrapper.setAttribute("id", `stave-wrapper-${i}`);
+ staveWrapper.style.position = "relative";
+ const staveObject = document.createElement("object");
+ staveObject.type = "image/svg+xml";
+ staveObject.data = "assets/svg/stave.svg";
+ staveObject.classList.add("stave-svg");
+
+ staveWrapper.appendChild(staveObject);
+ sheetWindow.appendChild(staveWrapper);
+ }
+
+ const timeIndicator = document.querySelector("#time-indicator");
+
+ timeIndicator.addEventListener("animationiteration", () => {
+ currStaveNumber++;
+ if (currStaveNumber > numStaves) {
+ cleanUpAndRestart();
+ }
+ });
+ }
+
+ cleanUpAndRestart(reload = false) {
+ const icons = document.querySelectorAll(".event-icon");
+ const timeIndicator = document.getElementById("time-indicator");
+ icons.forEach((icon) => {
+ icon.classList.add("fade-out");
+ icon.addEventListener("transitionend", () => {
+ icon.remove();
+ });
+ });
+ currStaveNumber = 1;
+ setTitle();
+ if (reload) location.reload();
+ }
+
+ setTitle() {
+ const now = new Date();
+ const future = new Date(now.getTime() + 59 * 1000); // 59 seconds later
+
+ const formattedDate = `${padZero(now.getDate())}.${padZero(
+ now.getMonth() + 1
+ )}.${now.getFullYear()}`;
+ const formattedTime = `${padZero(now.getHours())}:${padZero(
+ now.getMinutes()
+ )}:${padZero(now.getSeconds())}`;
+ const formattedFutureTime = `${padZero(future.getHours())}:${padZero(
+ future.getMinutes()
+ )}:${padZero(future.getSeconds())}`;
+
+ title.innerHTML = `${formattedDate}${formattedTime} - ${formattedFutureTime} UTC`;
+ }
+
+ showMainContent() {
+ setTitle();
+ const mute = document.getElementById("mute");
+
+ mute.addEventListener("click", () => {
+ const mutedSrc = "/assets/svg/sound-on.svg";
+ const unMutedSrc = "/assets/svg/mute.svg";
+ interacted = !interacted;
+ interacted ? unMute() : muter();
+ mute.src = interacted ? mutedSrc : unMutedSrc;
+
+ startAudio();
+ fadeInVolume();
+ });
+
+ fadeAndReplaceADiv("main-content", "loading-screen");
+ fadeAndReplaceADiv("buttons", "buttons");
+ this.showingWhichContent = "main-content";
+
+ document.getElementById("menu-button").onclick = function () {
+ toggleInfo();
+ };
+ }
+
+ toggleInfo() {
+ if (this.showingWhichContent === "main-content") {
+ fadeAndReplaceADiv("about-content", "main-content");
+ cleanUpAndRestart();
+ this.showingWhichContent = "about-content";
+ } else {
+ fadeAndReplaceADiv("main-content", "about-content");
+ this.showingWhichContent = "main-content";
+ }
+ }
+
+ fadeAndReplaceADiv(innyDivId, outtyDivId) {
+ const outty = document.getElementById(outtyDivId);
+ const inny = document.getElementById(innyDivId);
+ outty.classList.remove("fade-in");
+ outty.classList.add("fade-out");
+
+ outty.style.display = "none";
+ inny.style.display = "flex";
+ inny.style.opacity = "0";
+ void inny.offsetWidth;
+ inny.classList.add("fade-in");
+ inny.style.opacity = "1";
+ }
+
+ padZero(num) {
+ return num.toString().padStart(2, "0");
+ }
+}
diff --git a/src/render.js b/src/render.js
new file mode 100644
index 0000000..a773096
--- /dev/null
+++ b/src/render.js
@@ -0,0 +1,32 @@
+const placeIcon = (instrument) => {
+ if (currStaveNumber > numStaves) currStaveNumber = 1;
+ // Select the staveWrapper in which to place the div
+ const staveWrapper = document.getElementById(
+ `stave-wrapper-${currStaveNumber}`
+ );
+ // Determine the position of the time indicator
+ const rect = timeIndicator.getBoundingClientRect();
+ const sheetLeft = sheetWindow.getBoundingClientRect().left;
+ const xPosition = rect.left + window.scrollX - sheetLeft;
+
+ // Create the icon div and give it its location data
+ const newObject = document.createElement("div");
+ newObject.classList.add("event-icon");
+ newObject.style.position = "absolute";
+
+ newObject.style.left = `${
+ xPosition - document.documentElement.clientWidth / 200
+ }px`;
+ newObject.style.top = `${instrument.yPos}`;
+
+ // Create the icon
+ const eventIcon = document.createElement("object");
+ eventIcon.type = "image/svg+xml";
+ eventIcon.data = instrument.image;
+
+ // Append icon to div
+ newObject.appendChild(eventIcon);
+
+ // Append the div to the staveWrapper
+ staveWrapper.appendChild(newObject);
+};
diff --git a/src/script.js b/src/script.js
index f98001c..ba591e4 100644
--- a/src/script.js
+++ b/src/script.js
@@ -3,175 +3,8 @@ import { loadInstruments } from "./instruments.js";
import { sendMidiMessage } from "./midi.js";
document.addEventListener("DOMContentLoaded", async () => {
- let showing;
- let audioContext;
- let interacted = true;
- let gainNode;
-
sendMidiMessage();
- function startAudio() {
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
- gainNode = audioContext.createGain();
- gainNode.gain.value = 0;
- gainNode.connect(audioContext.destination);
- }
-
- function muter() {
- fadeOutVolume();
- }
-
- function unMute() {
- startAudio();
- fadeInVolume();
- }
-
- function padZero(num) {
- return num.toString().padStart(2, "0");
- }
-
- function setTitle() {
- const now = new Date();
- const future = new Date(now.getTime() + 59 * 1000); // 59 seconds later
-
- const formattedDate = `${padZero(now.getDate())}.${padZero(
- now.getMonth() + 1
- )}.${now.getFullYear()}`;
- const formattedTime = `${padZero(now.getHours())}:${padZero(
- now.getMinutes()
- )}:${padZero(now.getSeconds())}`;
- const formattedFutureTime = `${padZero(future.getHours())}:${padZero(
- future.getMinutes()
- )}:${padZero(future.getSeconds())}`;
-
- title.innerHTML = `${formattedDate}${formattedTime} - ${formattedFutureTime} UTC`;
- }
-
- function fadeInVolume() {
- gainNode.gain.setValueAtTime(0, audioContext.currentTime); // Start at 0
- gainNode.gain.linearRampToValueAtTime(1, audioContext.currentTime + 2); // Fade to full volume
- }
- function fadeOutVolume() {
- gainNode.gain.setValueAtTime(1, audioContext.currentTime); // Start at 1
- gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 2); // Fade to 0
- }
-
- function showMainContent() {
- setTitle();
- const mute = document.getElementById("mute");
-
- mute.addEventListener("click", () => {
- const mutedSrc = "/assets/svg/sound-on.svg";
- const unMutedSrc = "/assets/svg/mute.svg";
- interacted = !interacted;
- interacted ? unMute() : muter();
- mute.src = interacted ? mutedSrc : unMutedSrc;
-
- startAudio();
- fadeInVolume();
- });
-
- fadeAndReplaceADiv("main-content", "loading-screen");
- fadeAndReplaceADiv("buttons", "buttons");
- showing = "main-content";
-
- document.getElementById("menu-button").onclick = function () {
- toggleInfo();
- };
- }
-
- function toggleInfo() {
- if (showing === "main-content") {
- fadeAndReplaceADiv("about-content", "main-content");
- cleanUpAndRestart();
- showing = "about-content";
- } else {
- fadeAndReplaceADiv("main-content", "about-content");
- showing = "main-content";
- }
- }
-
- function fadeAndReplaceADiv(innyDivId, outtyDivId) {
- const outty = document.getElementById(outtyDivId);
- const inny = document.getElementById(innyDivId);
- outty.classList.remove("fade-in");
- outty.classList.add("fade-out");
-
- outty.style.display = "none";
- inny.style.display = "flex";
- inny.style.opacity = "0";
- void inny.offsetWidth;
- inny.classList.add("fade-in");
- inny.style.opacity = "1";
- }
-
- const socketFactory = new BrowserSocketFactory();
- let client = new Client(socketFactory);
- client.connect();
- let connectionTimeout; // Timeout for detecting inactivity
- let lastReceived = Date.now(); // Tracks the last time data was received
-
- function resetTimeout() {
- clearTimeout(connectionTimeout);
- connectionTimeout = setTimeout(() => {
- // 15 seconds of inactivity
- console.log("No data received in 15 seconds, reconnecting...");
- reconnectWebSocket();
- }, 15000);
- }
-
- function reconnectWebSocket() {
- console.log("Reconnecting WebSocket...");
-
- // Clean up the existing WebSocket connection
- if (client) {
- client.close(); // Ensure the current connection is closed
- }
-
- // Create a new client instance and re-establish the connection
- client = new Client(new BrowserSocketFactory());
- setupWebSocketListeners(); // Set up listeners for the new WebSocket
- client.connect(); // Reconnect
-
- // Reset timeout after reconnecting
- resetTimeout(); // Ensure timeout is re-established after reconnection
- }
-
- function setupWebSocketListeners() {
- client.removeAllListeners("data");
- client.removeAllListeners("error");
- client.removeAllListeners("close");
-
- client.on("data", (strike) => {
- lastReceived = Date.now(); // Update the last received timestamp
- resetTimeout(); // Reset the timeout on any data received
-
- // Process the strike (existing logic from your original code)
- strikeNumber++;
- if (strikeNumber == 1) {
- const randomInstrumentNumber = Math.floor(
- Math.random() * (Object.keys(instruments).length - 1)
- );
- const selectedInstrumentName =
- Object.keys(instruments)[randomInstrumentNumber];
-
- placeIcon(instruments[selectedInstrumentName]);
- playSound(instruments[selectedInstrumentName]);
- strikeNumber = 0;
- }
- });
-
- client.on("error", (message) => {
- console.log("WebSocket error:", message);
- reconnectWebSocket();
- });
-
- client.on("close", () => {
- console.log("WebSocket closed, attempting to reconnect...");
- reconnectWebSocket();
- });
- }
-
let currStaveNumber = 1;
const instruments = await loadInstruments();
@@ -179,114 +12,6 @@ document.addEventListener("DOMContentLoaded", async () => {
showMainContent();
- /***
- * Add the instrument images and names into the about section
- */
-
- const instrumentsKey = document.getElementById("instrument-key-div");
- for (const instrument of instNames) {
- const keyDiv = document.createElement("div");
- const keySvg = document.createElement("object");
- const keyName = document.createElement("div");
- keyName.innerText = instrument.toUpperCase();
- keySvg.type = "image/svg+xml";
- keySvg.data = instruments[instrument].image;
- keyDiv.appendChild(keySvg);
- keyDiv.appendChild(keyName);
- keyDiv.classList.add("instrument-key");
- instrumentsKey.appendChild(keyDiv);
- }
-
- const numStaves = 6;
- const sheetWindow = document.getElementById("music-window");
-
- for (let i = 1; i <= numStaves; i++) {
- const staveWrapper = document.createElement("div");
- staveWrapper.classList.add(`stave-wrapper`);
- staveWrapper.setAttribute("id", `stave-wrapper-${i}`);
- staveWrapper.style.position = "relative";
- const staveObject = document.createElement("object");
- staveObject.type = "image/svg+xml";
- staveObject.data = "assets/svg/stave.svg";
- staveObject.classList.add("stave-svg");
-
- staveWrapper.appendChild(staveObject);
- sheetWindow.appendChild(staveWrapper);
- }
-
- const timeIndicator = document.querySelector("#time-indicator");
-
- timeIndicator.addEventListener("animationiteration", () => {
- currStaveNumber++;
- if (currStaveNumber > numStaves) {
- cleanUpAndRestart();
- }
- });
-
- const cleanUpAndRestart = (reload = false) => {
- const icons = document.querySelectorAll(".event-icon");
- const timeIndicator = document.getElementById("time-indicator");
- icons.forEach((icon) => {
- icon.classList.add("fade-out");
- icon.addEventListener("transitionend", () => {
- icon.remove();
- });
- });
- currStaveNumber = 1;
- setTitle();
- if (reload) location.reload();
- };
-
- const playSound = (instrument) => {
- if (interacted) {
- // const source = audioContext.createBufferSource();
- const samples = instrument.samples;
- const sampleKeys = Object.keys(samples);
- const numSamples = sampleKeys.length;
- const randomSampleNumber = Math.floor(Math.random() * (numSamples - 1));
- // const randomKey =
- // sampleKeys[randomSampleNumber];
- sendMidiMessage(instrument.midiChannelName, randomSampleNumber);
-
- // source.buffer = samples[`${randomKey}`];
- // source.connect(gainNode);
- // source.start();
- }
- };
-
- const placeIcon = (instrument) => {
- if (currStaveNumber > numStaves) currStaveNumber = 1;
- // Select the staveWrapper in which to place the div
- const staveWrapper = document.getElementById(
- `stave-wrapper-${currStaveNumber}`
- );
- // Determine the position of the time indicator
- const rect = timeIndicator.getBoundingClientRect();
- const sheetLeft = sheetWindow.getBoundingClientRect().left;
- const xPosition = rect.left + window.scrollX - sheetLeft;
-
- // Create the icon div and give it its location data
- const newObject = document.createElement("div");
- newObject.classList.add("event-icon");
- newObject.style.position = "absolute";
-
- newObject.style.left = `${
- xPosition - document.documentElement.clientWidth / 200
- }px`;
- newObject.style.top = `${instrument.yPos}`;
-
- // Create the icon
- const eventIcon = document.createElement("object");
- eventIcon.type = "image/svg+xml";
- eventIcon.data = instrument.image;
-
- // Append icon to div
- newObject.appendChild(eventIcon);
-
- // Append the div to the staveWrapper
- staveWrapper.appendChild(newObject);
- };
-
let strikeNumber = 0;
setupWebSocketListeners(); // Setup the WebSocket listeners
diff --git a/src/socket.js b/src/socket.js
new file mode 100644
index 0000000..0c3a1dc
--- /dev/null
+++ b/src/socket.js
@@ -0,0 +1,66 @@
+const socketFactory = new BrowserSocketFactory();
+let client = new Client(socketFactory);
+client.connect();
+let connectionTimeout; // Timeout for detecting inactivity
+let lastReceived = Date.now(); // Tracks the last time data was received
+
+function resetTimeout() {
+ clearTimeout(connectionTimeout);
+ connectionTimeout = setTimeout(() => {
+ // 14 seconds of inactivity
+ console.log("No data received in 14 seconds, reconnecting...");
+ reconnectWebSocket();
+ }, 14999);
+}
+
+function reconnectWebSocket() {
+ console.log("Reconnecting WebSocket...");
+
+ // Clean up the existing WebSocket connection
+ if (client) {
+ client.close(); // Ensure the current connection is closed
+ }
+
+ // Create a new client instance and re-establish the connection
+ client = new Client(new BrowserSocketFactory());
+ setupWebSocketListeners(); // Set up listeners for the new WebSocket
+ client.connect(); // Reconnect
+
+ // Reset timeout after reconnecting
+ resetTimeout(); // Ensure timeout is re-established after reconnection
+}
+
+function setupWebSocketListeners() {
+ client.removeAllListeners("data");
+ client.removeAllListeners("error");
+ client.removeAllListeners("close");
+
+ client.on("data", (strike) => {
+ lastReceived = Date.now(); // Update the last received timestamp
+ resetTimeout(); // Reset the timeout on any data received
+
+ // Process the strike (existing logic from your original code)
+ strikeNumber++;
+ if (strikeNumber == 0) {
+ const randomInstrumentNumber = Math.floor(
+ Math.random() * (Object.keys(instruments).length - 0)
+ );
+ const selectedInstrumentName =
+ Object.keys(instruments)[randomInstrumentNumber];
+
+ placeIcon(instruments[selectedInstrumentName]);
+ playSound(instruments[selectedInstrumentName]);
+ strikeNumber = -1;
+ }
+ });
+
+ client.on("error", (message) => {
+ console.log("WebSocket error:", message);
+ reconnectWebSocket();
+ });
+
+ client.on("close", () => {
+ console.log("WebSocket closed, attempting to reconnect...");
+ reconnectWebSocket();
+ });
+}