some changes to facilitate auto loading on startup

This commit is contained in:
joe 2025-04-05 22:55:13 +01:00
parent 078f0d57ca
commit bdc8b286c1
6 changed files with 83 additions and 31 deletions

View File

@ -7,6 +7,7 @@
"bdrum3-fff-rr1.mp3", "bdrum3-fff-rr1.mp3",
"bdrumnew-hit-v7-rr1-sum-(1).mp3" "bdrumnew-hit-v7-rr1-sum-(1).mp3"
], ],
"midi-channel-name": "conductorOrchestralBass",
"image": { "filename": "bass.svg", "yPos": "13%" } "image": { "filename": "bass.svg", "yPos": "13%" }
}, },
"Snare": { "Snare": {
@ -15,16 +16,19 @@
"ropesnare-low-ns-main-vl3-rr2.mp3", "ropesnare-low-ns-main-vl3-rr2.mp3",
"ropesnare-low-tsn-main-vl4-rr1.mp3" "ropesnare-low-tsn-main-vl4-rr1.mp3"
], ],
"midi-channel-name": "conductorSnare",
"image": { "filename": "snare.svg", "yPos": "26%" } "image": { "filename": "snare.svg", "yPos": "26%" }
}, },
"Surdo": { "Surdo": {
"directory": "/assets/instruments/surdo", "directory": "/assets/instruments/surdo",
"filenames": ["surdo-5.mp3", "surdo-6.mp3", "surdo-7.mp3"], "filenames": ["surdo-5.mp3", "surdo-6.mp3", "surdo-7.mp3"],
"midi-channel-name":"conductorSnare",
"image": { "filename": "surdo.svg", "yPos": "39%" } "image": { "filename": "surdo.svg", "yPos": "39%" }
}, },
"Surdo Napa": { "Surdo Napa": {
"directory": "/assets/instruments/surdo-napa", "directory": "/assets/instruments/surdo-napa",
"filenames": ["surdo-1.mp3", "surdo-3.mp3", "surdo-4.mp3"], "filenames": ["surdo-1.mp3", "surdo-3.mp3", "surdo-4.mp3"],
"midi-channel-name": "conductorSurdoNapa",
"image": { "filename": "surdo-napa.svg", "yPos": "42%" } "image": { "filename": "surdo-napa.svg", "yPos": "42%" }
}, },
"Timpani Large": { "Timpani Large": {
@ -32,20 +36,19 @@
"filenames": [ "filenames": [
"timpani1-hit-v4-rr1-sum.mp3", "timpani1-hit-v4-rr1-sum.mp3",
"timpani2-roll-v3-rr1-sum.mp3", "timpani2-roll-v3-rr1-sum.mp3",
"timpani2-roll-v3-rr1-sum.wav",
"timpani7b-hit-v5-rr2-main.mp3", "timpani7b-hit-v5-rr2-main.mp3",
"timpani7d-hit-v2-rr1-main.mp3" "timpani7d-hit-v2-rr1-main.mp3"
], ],
"midi-channel-name":"conductorTimpaniLarge",
"image": { "filename": "timpani-large.svg", "yPos": "55%" } "image": { "filename": "timpani-large.svg", "yPos": "55%" }
}, },
"Timpani Small": { "Timpani Small": { "directory": "/assets/instruments/timpani-small",
"directory": "/assets/instruments/timpani-small",
"filenames": [ "filenames": [
"timpani1a-hit-v5-rr1-main.mp3", "timpani1a-hit-v5-rr1-main.mp3",
"timpani1-roll-v3-rr1-sum.wav",
"timpani2-hit-v3-rr1-sum.mp3", "timpani2-hit-v3-rr1-sum.mp3",
"timpani4-hit-v2-rr1-sum.mp3" "timpani4-hit-v2-rr1-sum.mp3"
], ],
"midi-channel-name": "conductorTimpaniSmall",
"image": { "filename": "timpani-small.svg", "yPos": "68%" } "image": { "filename": "timpani-small.svg", "yPos": "68%" }
}, },
"Toms": { "Toms": {
@ -55,6 +58,7 @@
"toml-hitm-v4-rr2-mid.mp3", "toml-hitm-v4-rr2-mid.mp3",
"toml-rollm-v2-rr1-mid.mp3" "toml-rollm-v2-rr1-mid.mp3"
], ],
"midi-channel-name": "conductorToms",
"image": { "filename": "toms.svg", "yPos": "81%" } "image": { "filename": "toms.svg", "yPos": "81%" }
} }
} }

View File

@ -16,15 +16,17 @@
</div> </div>
</div> </div>
<div id="buttons"> <div id="buttons">
<img src="/assets/svg/mute.svg" class="audio" id="mute"></img> <img src="/assets/svg/mute.svg" class="audio" id="mute">
<img src="/assets/svg/menu.svg" class="menu" id="menu-button"></img> <img src="/assets/svg/menu.svg" class="menu" id="menu-button">
</div> </div>
<div id="main-content"> <div id="main-content">
<div class="title-title"> <div class="title-title">
The Conductor The Conductor
</div> </div>
<div class="title" id="title"> <div class="title" id="title">
15.5.2024 08:00:00 - 08:01:00 UTC 15.5.2024 08:00:00 - 08:01:00 UTC
@ -46,19 +48,26 @@
<div class="instruments-key" id="instrument-key-div"></div> <div class="instruments-key" id="instrument-key-div"></div>
</div> </div>
<p> <p>
The Conductor translates live lightning strikes from around the world into a graphic score for seven percussion instruments. The Conductor translates live lightning strikes from around the world into a graphic score for seven percussion
instruments.
</p> </p>
<p> <p>
The project was conceived and developed by the artist Mishka Henner between 2023 and 2024 with a team of musicians, sound artists and acoustics engineers during an artist's residency at Energy House 2.0 at the University of Salford. The project was conceived and developed by the artist Mishka Henner between 2023 and 2024 with a team of
musicians, sound artists and acoustics engineers during an artist's residency at Energy House 2.0 at the
University of Salford.
</p> </p>
<p> <p>
The Conductor was first performed at the University of Salfords Acoustic Laboratories during the Sounds From the Other City Festival on 5 May 2024. The Conductor was first performed at the University of Salfords Acoustic Laboratories during the Sounds From
the Other City Festival on 5 May 2024.
</p> </p>
<p> <p>
Click <a href="https://mishkahenner.com/The-Conductor" style="color: #fff; text-decoration:underline">here</a> to read more about the project. Download a copy of the artist's graphic score <a href="https://files.cargocollective.com/c20096/CONDUCTOR-SHEET-MUSIC-Black-BG.pdf" style="color: #fff; text-decoration:underline">here</a>. Click <a href="https://mishkahenner.com/The-Conductor" style="color: #fff; text-decoration:underline">here</a>
to read more about the project. Download a copy of the artist's graphic score <a
href="https://files.cargocollective.com/c20096/CONDUCTOR-SHEET-MUSIC-Black-BG.pdf"
style="color: #fff; text-decoration:underline">here</a>.
</p> </p>
<br /> <br />
<div class="production-credits"> <div class="production-credits">
@ -66,16 +75,18 @@
<div> <div>
Project Conception and Design by Mishka Henner. Project Conception and Design by Mishka Henner.
</div> </div>
Data Capture, Web Design and Coding by Joe Gibson. Data Capture, Web Design and Coding by Joe Gibson.
<div> <div>
Lightning data from Blitzortung.org Lightning data from Blitzortung.org
</div> </div>
<p> <p>
With support from the University of Salford Art Collection in partnership with Open Eye Gallery, Liverpool as part of the LOOK Photo Biennial, and Castlefield Gallery, Manchester. Generously supported by Friends of Energy House Labs. With support from the University of Salford Art Collection in partnership with Open Eye Gallery, Liverpool as
part of the LOOK Photo Biennial, and Castlefield Gallery, Manchester. Generously supported by Friends of
Energy House Labs.
</p> </p>
</div> </div>
</div> </div>
</div> </div>
<script type="module" src="/src/script.js"></script> <script type="module" src="/src/script.js"></script>
</body> </body>

View File

@ -17,7 +17,6 @@ async function decodeAudioData(context, arrayBuffer) {
async function loadAudioSamples(context, directory, filenames) { async function loadAudioSamples(context, directory, filenames) {
const audioFiles = filenames; const audioFiles = filenames;
console.log(filenames);
const audioBuffers = {}; const audioBuffers = {};
for (const file of audioFiles) { for (const file of audioFiles) {
@ -59,6 +58,7 @@ export async function loadInstruments() {
samples: samples, samples: samples,
image: imageData, image: imageData,
yPos: config.image.yPos, // Store base64-encoded image data yPos: config.image.yPos, // Store base64-encoded image data
midiChannelName: config["midi-channel-name"],
}; };
} }

30
src/midi.js Normal file
View File

@ -0,0 +1,30 @@
export async function sendMidiMessage(midiChannelName, sampleNumber ) {
try {
const midiAccess = await navigator.requestMIDIAccess();
const availableMidiOutputs = midiAccess.outputs.values();
let midiOut;
if (availableMidiOutputs.length === 0) {
console.error("No MIDI output devices found.");
return;
}
for ( const availableMidiOutput of availableMidiOutputs){
if (availableMidiOutput.name === midiChannelName){
midiOut = availableMidiOutput;
break;
}
}
// MIDI Note On (Play Note)
midiOut.send([0x90, 36 + sampleNumber, 127]);
// MIDI Note Off after 500ms
setTimeout(() => {
midiOut.send([0x80, 36 + sampleNumber, 0]); // Stop Note
}, 500);
} catch (error) {
console.error("Failed to get MIDI access:", error);
}
}

View File

@ -1,12 +1,15 @@
import { Client, BrowserSocketFactory } from "./blitz.js"; import { Client, BrowserSocketFactory } from "./blitz.js";
import { loadInstruments } from "./instruments.js"; import { loadInstruments } from "./instruments.js";
import { sendMidiMessage } from "./midi.js";
document.addEventListener("DOMContentLoaded", async () => { document.addEventListener("DOMContentLoaded", async () => {
let showing; let showing;
let audioContext; let audioContext;
let interacted = false; let interacted = true;
let gainNode; let gainNode;
sendMidiMessage();
function startAudio() { function startAudio() {
audioContext = new (window.AudioContext || window.webkitAudioContext)(); audioContext = new (window.AudioContext || window.webkitAudioContext)();
gainNode = audioContext.createGain(); gainNode = audioContext.createGain();
@ -73,7 +76,6 @@ document.addEventListener("DOMContentLoaded", async () => {
showing = "main-content"; showing = "main-content";
document.getElementById("menu-button").onclick = function () { document.getElementById("menu-button").onclick = function () {
console.log(showing);
toggleInfo(); toggleInfo();
}; };
} }
@ -141,6 +143,7 @@ document.addEventListener("DOMContentLoaded", async () => {
client.removeAllListeners("close"); client.removeAllListeners("close");
client.on("data", (strike) => { client.on("data", (strike) => {
lastReceived = Date.now(); // Update the last received timestamp lastReceived = Date.now(); // Update the last received timestamp
resetTimeout(); // Reset the timeout on any data received resetTimeout(); // Reset the timeout on any data received
@ -173,7 +176,6 @@ document.addEventListener("DOMContentLoaded", async () => {
let currStaveNumber = 1; let currStaveNumber = 1;
const instruments = await loadInstruments(); const instruments = await loadInstruments();
console.log(instruments);
const instNames = Object.keys(instruments); const instNames = Object.keys(instruments);
showMainContent(); showMainContent();
@ -184,7 +186,6 @@ document.addEventListener("DOMContentLoaded", async () => {
const instrumentsKey = document.getElementById("instrument-key-div"); const instrumentsKey = document.getElementById("instrument-key-div");
for (const instrument of instNames) { for (const instrument of instNames) {
console.log(instrument);
const keyDiv = document.createElement("div"); const keyDiv = document.createElement("div");
const keySvg = document.createElement("object"); const keySvg = document.createElement("object");
const keyName = document.createElement("div"); const keyName = document.createElement("div");
@ -239,16 +240,18 @@ document.addEventListener("DOMContentLoaded", async () => {
const playSound = (instrument) => { const playSound = (instrument) => {
if (interacted) { if (interacted) {
const source = audioContext.createBufferSource(); // const source = audioContext.createBufferSource();
const samples = instrument.samples; const samples = instrument.samples;
const sampleKeys = Object.keys(samples); const sampleKeys = Object.keys(samples);
const numSamples = sampleKeys.length; const numSamples = sampleKeys.length;
const randomKey = const randomSampleNumber = Math.floor(Math.random() * (numSamples - 1));
sampleKeys[Math.floor(Math.random() * (numSamples - 1))]; // const randomKey =
// sampleKeys[randomSampleNumber];
sendMidiMessage(instrument.midiChannelName, randomSampleNumber);
source.buffer = samples[`${randomKey}`]; // source.buffer = samples[`${randomKey}`];
source.connect(gainNode); // source.connect(gainNode);
source.start(); // source.start();
} }
}; };

View File

@ -5,7 +5,7 @@ body {
align-items: center; align-items: center;
background-color: rgb(24, 24, 24); background-color: rgb(24, 24, 24);
height: 100vh; height: 100vh;
overflow-x: hidden; overflow: hidden;
} }
object { object {
@ -17,6 +17,9 @@ html {
overflow-x: hidden; overflow-x: hidden;
} }
* {
box-sizing: border-box;
}
#main-content { #main-content {
position: absolute; position: absolute;
@ -29,6 +32,7 @@ html {
align-items: center; align-items: center;
opacity: 0; opacity: 0;
transition: opacity 2s ease; transition: opacity 2s ease;
overflow: hidden;
} }