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

View File

@ -16,15 +16,17 @@
</div>
</div>
<div id="buttons">
<img src="/assets/svg/mute.svg" class="audio" id="mute"></img>
<img src="/assets/svg/menu.svg" class="menu" id="menu-button"></img>
<img src="/assets/svg/mute.svg" class="audio" id="mute">
<img src="/assets/svg/menu.svg" class="menu" id="menu-button">
</div>
<div id="main-content">
<div class="title-title">
The Conductor
</div>
<div class="title-title">
The Conductor
</div>
<div class="title" id="title">
15.5.2024 08:00:00 - 08:01:00 UTC
@ -46,19 +48,26 @@
<div class="instruments-key" id="instrument-key-div"></div>
</div>
<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>
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>
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>
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>
<br />
<div class="production-credits">
@ -66,16 +75,18 @@
<div>
Project Conception and Design by Mishka Henner.
</div>
Data Capture, Web Design and Coding by Joe Gibson.
Data Capture, Web Design and Coding by Joe Gibson.
<div>
Lightning data from Blitzortung.org
</div>
<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>
</div>
</div>
</div>
</div>
<script type="module" src="/src/script.js"></script>
</body>

View File

@ -17,7 +17,6 @@ async function decodeAudioData(context, arrayBuffer) {
async function loadAudioSamples(context, directory, filenames) {
const audioFiles = filenames;
console.log(filenames);
const audioBuffers = {};
for (const file of audioFiles) {
@ -59,6 +58,7 @@ export async function loadInstruments() {
samples: samples,
image: imageData,
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 { loadInstruments } from "./instruments.js";
import { sendMidiMessage } from "./midi.js";
document.addEventListener("DOMContentLoaded", async () => {
let showing;
let audioContext;
let interacted = false;
let interacted = true;
let gainNode;
sendMidiMessage();
function startAudio() {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
gainNode = audioContext.createGain();
@ -19,7 +22,7 @@ document.addEventListener("DOMContentLoaded", async () => {
}
function unMute() {
startAudio();
startAudio();
fadeInVolume();
}
@ -73,7 +76,6 @@ document.addEventListener("DOMContentLoaded", async () => {
showing = "main-content";
document.getElementById("menu-button").onclick = function () {
console.log(showing);
toggleInfo();
};
}
@ -141,6 +143,7 @@ document.addEventListener("DOMContentLoaded", async () => {
client.removeAllListeners("close");
client.on("data", (strike) => {
lastReceived = Date.now(); // Update the last received timestamp
resetTimeout(); // Reset the timeout on any data received
@ -173,7 +176,6 @@ document.addEventListener("DOMContentLoaded", async () => {
let currStaveNumber = 1;
const instruments = await loadInstruments();
console.log(instruments);
const instNames = Object.keys(instruments);
showMainContent();
@ -184,7 +186,6 @@ document.addEventListener("DOMContentLoaded", async () => {
const instrumentsKey = document.getElementById("instrument-key-div");
for (const instrument of instNames) {
console.log(instrument);
const keyDiv = document.createElement("div");
const keySvg = document.createElement("object");
const keyName = document.createElement("div");
@ -239,16 +240,18 @@ document.addEventListener("DOMContentLoaded", async () => {
const playSound = (instrument) => {
if (interacted) {
const source = audioContext.createBufferSource();
// const source = audioContext.createBufferSource();
const samples = instrument.samples;
const sampleKeys = Object.keys(samples);
const numSamples = sampleKeys.length;
const randomKey =
sampleKeys[Math.floor(Math.random() * (numSamples - 1))];
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();
// source.buffer = samples[`${randomKey}`];
// source.connect(gainNode);
// source.start();
}
};

View File

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