Compare commits

...

10 Commits

Author SHA1 Message Date
joe bdc8b286c1 some changes to facilitate auto loading on startup 2025-04-05 22:55:13 +01:00
skelbon 078f0d57ca reconnections sorted 2025-01-17 19:03:40 +00:00
skelbon 19c306ad79 original working version 2025-01-17 16:00:37 +00:00
skelbon c4acccbb85 latest update 2024-08-08 17:36:04 +01:00
skelbon d3c931eed1 latest changes 2024-07-26 11:28:21 +01:00
skelbon 7a3ab4dff7 changes 2024-07-17 15:05:41 +01:00
skelbon eced53d390 sounds loaded and inserted 2024-07-17 15:03:40 +01:00
skelbon 909ba64e1a dickin about with some audio 2024-07-12 22:05:14 +01:00
skelbon d37e81ae11 added blitz ws link 2024-07-08 13:07:38 +01:00
skelbon e0257071e7 linked up the blitzortung ws 2024-07-07 15:52:06 +01:00
49 changed files with 927 additions and 100 deletions

45
Logo.svg Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 337.93 336.08">
<defs>
<style>
.cls-1 {
fill: #fff;
stroke-width: 0px;
}
</style>
</defs>
<g id="Layer_1-2">
<path class="cls-1"
d="M298.88,187.23c-5.36-.86-10.64-1.71-15.93-2.56-8.05-1.3-16.1-2.59-24.15-3.88-7.72-1.24-15.44-2.48-23.16-3.72-4.73-.76-9.46-1.52-14.19-2.29-.29-.05-.58-.07-1.11-.14,1.33,2.76,2.59,5.35,3.84,7.94-.05.06-.09.13-.14.19-7.85-4.06-15.7-8.11-23.55-12.17.01-.08.03-.15.04-.23,8.68-2.24,17.35-4.47,26.03-6.71.04.06.08.12.12.18-2.03,2.22-4.05,4.45-6.21,6.82h53.81c-4-6.14-7.91-12.15-11.93-18.32,1.48.08,2.76.14,4.04.22,6.09.38,12.17.76,18.26,1.15,6.85.44,13.7.89,20.55,1.32,5.75.36,11.51.71,17.26,1.07,2.86.18,5.72.36,8.58.59.3.02.74.34.82.61,2.04,6.9,4.05,13.8,6.06,20.71.02.06,0,.13,0,.39-17.13-4.02-34.22-8.03-51.59-12.1.31.54.48.84.66,1.14,3.87,6.27,7.75,12.53,11.61,18.8.18.29.23.66.28.99Z" />
<path class="cls-1"
d="M110.59,167.67c.18-.11.42-.26.6-.21,4.47,1.2,8.93,2.43,13.39,3.65,3.85,1.06,7.7,2.12,11.84,3.26-8.27,4.11-16.31,8.11-24.35,12.1-.05-.05-.11-.11-.16-.16,1.54-2.62,3.07-5.24,4.74-8.1-17.68,3.75-35.1,7.44-52.53,11.13,5.1,5.14,10.16,10.25,15.23,15.36-.05.09-.1.18-.15.27-1.5.23-3,.47-4.5.69-7.64,1.12-15.28,2.25-22.92,3.36-8.43,1.23-16.86,2.45-25.3,3.68-5.01.73-10.01,1.46-15.02,2.21-.59.09-.9-.04-1.19-.57-3.3-6.17-6.63-12.32-9.95-18.49-.1-.19-.17-.41-.32-.78,17.67.39,35.21.78,52.74,1.16.04-.07.09-.15.13-.22-5.55-5.8-11.1-11.61-16.86-17.62,26.71-1.31,53.14-2.6,79.85-3.91-1.84-2.37-3.54-4.57-5.28-6.81Z" />
<path class="cls-1"
d="M118.4,139.59c-.34-.15-.61-.27-1.08-.47,3.2-.66,6.18-1.28,9.52-1.97-14.63-10.56-29.04-20.97-43.69-31.55-.4,7.38-.79,14.5-1.18,21.81-.35-.24-.6-.37-.81-.54-17.35-14.28-34.69-28.56-52.04-42.84-.4-.33-.72-.57-.48-1.22,2.45-6.69,4.87-13.4,7.29-20.11.04-.12.12-.23.26-.48,11.5,13.29,22.96,26.52,34.42,39.76.09-.02.17-.05.26-.07.62-7.97,1.25-15.95,1.87-23.96,18.76,18.71,37.46,37.35,56.36,56.19.57-3.08,1.09-5.88,1.61-8.68.08-.03.16-.06.25-.09,3.95,7.85,7.89,15.7,11.97,23.82-8.33-3.26-16.4-6.41-24.54-9.59Z" />
<path class="cls-1"
d="M239.24,139.44c8.85-3.93,17.64-7.83,26.61-11.8-6.22-4.03-12.27-7.95-18.49-11.98,2.22-.83,4.23-1.58,6.25-2.33,19.26-7.11,38.52-14.22,57.77-21.36.87-.32,1.33-.21,1.93.5,4.37,5.21,8.79,10.38,13.19,15.56.19.22.37.46.67.84-17.4,3.28-34.67,6.53-52.23,9.84,6.88,4.69,13.55,9.24,20.44,13.94-25.82,6.79-51.43,13.53-77.29,20.34,2.35,1.99,4.54,3.84,6.73,5.69-.02.09-.04.17-.06.26-8.79-.53-17.59-1.05-26.38-1.58-.02-.08-.04-.16-.06-.25,6.99-5.54,13.98-11.07,20.96-16.61.08.04.15.07.23.11-.95,2.86-1.89,5.71-2.94,8.86,7.74-3.42,15.18-6.72,22.69-10.05Z" />
<path class="cls-1"
d="M286.48,205.13c11.77,6.12,23.46,12.22,35.17,18.29.72.38.98.73.86,1.59-.99,6.92-1.92,13.86-2.87,20.79-.02.13-.08.25-.17.52-14.04-10.63-28.02-21.21-42.25-31.98,1.1,8.26,2.16,16.19,3.26,24.42-22.35-14.54-44.5-28.94-66.78-43.43v8.97c-5.62-7.01-11.14-13.89-16.82-20.98,9.12,1.51,17.97,2.98,26.81,4.45.03.07.05.15.08.22-2.79,1.23-5.58,2.46-8.6,3.79,16.51,7.3,32.8,14.51,49.32,21.82-1.15-7.28-2.27-14.36-3.42-21.7,8.57,4.46,16.96,8.83,25.42,13.23Z" />
<path class="cls-1"
d="M52.42,268.86c-2.94,1.85-5.82,3.65-8.68,5.48-.45.29-.76.35-1.22-.01-5.63-4.38-11.29-8.73-16.93-13.08-.1-.08-.21-.16-.49-.38,16.37-6.82,32.6-13.58,49.06-20.44-7.74-3.18-15.23-6.25-22.9-9.4,23.84-11.99,47.48-23.88,71.35-35.88-2.75-1.48-5.33-2.86-8.17-4.39,9.07-1.36,17.83-2.67,26.89-4.02-5.87,7.09-11.56,13.96-17.24,20.82-.09-.02-.18-.04-.27-.06.33-2.97.65-5.94,1.02-9.25-14.66,10.6-29.08,21.03-43.66,31.58,6.93,2.66,13.68,5.25,20.61,7.9-16.55,10.44-32.92,20.77-49.36,31.13Z" />
<path class="cls-1"
d="M56.75,129.2c20.44,7.88,40.81,15.73,61.44,23.68-.74-3.03-1.42-5.82-2.11-8.61.06-.04.12-.09.18-.13,6.82,5.58,13.64,11.15,20.45,16.73,0,.08-.02.16-.03.24-8.97.4-17.95.79-26.92,1.19-.02-.07-.04-.13-.06-.2,2.47-1.77,4.93-3.54,7.65-5.49-17.71-3.74-35.13-7.41-52.81-11.15,2.65,6.9,5.22,13.58,7.87,20.49-1.33-.36-2.44-.64-3.54-.95-20.77-5.78-41.53-11.56-62.3-17.32-.78-.22-1.1-.53-1.16-1.39-.46-6.72-.99-13.43-1.49-20.14-.03-.39,0-.78,0-1.33,15.97,7.5,31.84,14.95,48.02,22.55-2.8-7.84-5.5-15.39-8.29-23.21,4.51,1.73,8.78,3.37,13.11,5.04Z" />
<path class="cls-1"
d="M223.76,110.14c5.54-6.13,11.04-12.2,16.7-18.46-7.34-1.17-14.47-2.3-21.74-3.46.33-.35.53-.6.77-.82,16.08-15.64,32.16-31.29,48.23-46.93.38-.37.66-.6,1.27-.31,6.38,3.1,12.77,6.16,19.16,9.24.17.08.34.19.62.36-14.53,10.02-28.97,19.97-43.66,30.1,8.23,1.51,16.19,2.97,24.36,4.47-20.79,16.64-41.44,33.16-62.28,49.84,3.01.88,5.82,1.71,8.89,2.61-8.54,3.18-16.85,6.28-25.45,9.49,4.28-8.18,8.41-16.08,12.54-23.98.08,0,.16.01.24.02.3,2.98.6,5.95.91,8.93.09.04.18.07.27.11,6.38-7.05,12.75-14.1,19.18-21.2Z" />
<path class="cls-1"
d="M279.42,293.62c-1.51,2.43-2.99,4.79-4.57,7.33-8.53-15.48-16.96-30.78-25.39-46.09-.09,0-.17-.02-.26-.02-2.28,7.69-4.56,15.38-6.93,23.35-14.49-22.34-28.83-44.46-43.33-66.83-1.18,2.86-2.28,5.51-3.38,8.16-.08,0-.17,0-.25,0-2.22-8.5-4.44-17-6.73-25.8,7.74,5.09,15.23,10.02,22.71,14.94-.02.06-.04.13-.06.19h-9.41c12.11,13.36,24.03,26.52,36.13,39.88,1.94-7.17,3.81-14.08,5.74-21.2,1.73,2.16,3.31,4.14,4.88,6.11,12.46,15.65,24.91,31.3,37.4,46.92.71.89.73,1.46.12,2.4-2.27,3.49-4.43,7.05-6.68,10.65Z" />
<path class="cls-1"
d="M102.49,308.12c-1.67,2.5-3.28,4.95-4.95,7.36-.21.3-.77.6-1.09.53-7.09-1.69-14.16-3.43-21.45-5.22,12.13-12.82,24.17-25.54,36.21-38.25-.02-.09-.03-.17-.05-.26-8.05.22-16.1.44-24.46.66,16.89-20.62,33.61-41.02,50.49-61.63-3.09-.24-5.98-.47-8.87-.69-.04-.06-.07-.13-.11-.19,7.44-4.73,14.88-9.45,22.32-14.18.07.05.15.09.22.14-2.38,8.57-4.77,17.14-7.15,25.71-.08,0-.17,0-.25.01-.92-2.86-1.84-5.71-2.85-8.88-9.06,15.62-17.95,30.96-26.98,46.51,7.4-.37,14.57-.74,22.06-1.11-11.11,16.62-22.08,33.03-33.09,49.49Z" />
<path class="cls-1"
d="M225.89,11.08c1.22,0,2.35,0,3.76,0-9.3,15.22-18.41,30.14-27.69,45.34,8.15-1.95,15.98-3.83,24.08-5.78-12.21,23.64-24.3,47.07-36.51,70.72,3.09-.4,5.93-.77,8.78-1.15.04.08.08.15.12.23-6.27,6.14-12.54,12.27-18.81,18.41-.08-.02-.16-.04-.24-.06.54-8.88,1.08-17.76,1.62-26.65.08-.03.16-.05.24-.08,1.49,2.6,2.98,5.2,4.47,7.8.09,0,.19,0,.28.01,5.5-16.84,10.99-33.68,16.57-50.79-7.2,1.91-14.15,3.75-21.27,5.64.16-.47.25-.78.37-1.07,8.27-20.75,16.54-41.49,24.78-62.24.3-.76.68-.97,1.46-.94,5.96.23,11.93.4,17.99.6Z" />
<path class="cls-1"
d="M81.46,46.26c-1.88-3.77-3.72-7.47-5.57-11.16-.22-.44-.37-.77.07-1.23,5.02-5.17,10.01-10.36,15.01-15.54.04-.05.11-.06.34-.19,5.07,16.77,10.12,33.5,15.18,50.22l.26.03c3.83-7.04,7.66-14.07,11.63-21.38,9.5,24.84,18.9,49.43,28.42,74.33,1.76-2.56,3.38-4.91,5-7.27.08.01.17.02.25.03.39,8.74.79,17.48,1.16,25.8-6.23-6.02-12.65-12.22-19.07-18.42.05-.08.1-.17.15-.25,2.96.63,5.93,1.27,9.17,1.96-9.06-15.59-17.97-30.93-27.01-46.48-3.39,6.6-6.67,12.98-10.05,19.56-8.37-16.79-16.64-33.37-24.94-50.01Z" />
<path class="cls-1"
d="M143.9,327.94c4.86-13.83,9.7-27.58,14.54-41.33-.07-.06-.14-.12-.21-.18-7.25,3.45-14.51,6.9-22.03,10.48,7-25.65,13.92-51.05,20.93-76.74-2.95,1.04-5.67,2.01-8.4,2.97-.05-.05-.1-.11-.15-.16,4.86-7.32,9.73-14.64,14.59-21.96.08.01.16.03.25.04,1.33,8.8,2.65,17.6,3.98,26.4-.07.04-.14.08-.21.11-2.01-2.24-4.01-4.47-6.02-6.71-.09.02-.18.03-.27.05-1.86,17.62-3.71,35.25-5.59,53.09,6.62-3.34,13.03-6.58,19.62-9.91-.05.49-.07.8-.12,1.1-3.74,21.95-7.49,43.9-11.2,65.85-.14.84-.41,1.22-1.31,1.38-6.82,1.18-13.63,2.43-20.44,3.65-.22.04-.45,0-.81,0,.96-2.74,1.89-5.4,2.86-8.13Z" />
<path class="cls-1"
d="M171.35,123.95c-1.72,4.34-3.41,8.62-5.09,12.89-.08,0-.16.02-.24.02-3.14-8.34-6.28-16.67-9.42-25.01.06-.06.12-.11.17-.17,2.44,1.78,4.87,3.55,7.31,5.33.08-.04.16-.08.24-.12-1.87-17.6-3.73-35.2-5.63-53.08-5.79,4.65-11.38,9.14-17.11,13.75-.05-.5-.1-.81-.11-1.13-.93-22.22-1.85-44.43-2.81-66.64-.04-.96.24-1.38,1.12-1.73,6.28-2.5,12.53-5.06,18.79-7.6.3-.12.61-.24,1.12-.45-2.24,17.48-4.46,34.8-6.68,52.12.07.05.15.1.22.16,6.38-4.88,12.75-9.76,19.37-14.82-1.48,26.55-2.95,52.82-4.43,79.39,2.68-1.64,5.15-3.15,7.62-4.67.06.04.11.08.17.12-1.52,3.86-3.05,7.72-4.6,11.65Z" />
<path class="cls-1"
d="M222.29,288.1c2.67,10.34,5.3,20.61,7.98,30.87.2.77.09,1.17-.59,1.63-5.68,3.8-11.33,7.64-16.99,11.46-.27.18-.55.34-.99.61-1.46-17.53-2.9-34.9-4.35-52.28-.09-.04-.17-.09-.26-.13-5.22,6.09-10.44,12.18-15.85,18.49-4.1-26.28-8.16-52.28-12.26-78.57-2.26,2.14-4.35,4.13-6.45,6.11-.07-.04-.14-.08-.21-.12,1.45-8.65,2.89-17.29,4.34-25.94l.24-.05c4.81,7.5,9.63,15.01,14.44,22.51-.04.06-.08.13-.12.19-2.77-1.24-5.55-2.48-8.6-3.85,5.6,17.13,11.11,33.96,16.71,51.07,4.69-5.75,9.24-11.31,13.92-17.05,3.04,11.81,6.03,23.39,9.03,35.05Z" />
<path class="cls-1"
d="M187.92,183.72c-6.16,3.54-12.26,7.03-18.34,10.55-.68.4-1.19.43-1.91.02-6.86-3.98-13.73-7.92-20.62-11.85-.64-.36-.85-.77-.85-1.49.03-7.9.03-15.8,0-23.69,0-.75.2-1.19.88-1.57,6.89-3.92,13.76-7.87,20.62-11.84.67-.39,1.16-.37,1.82,0,6.89,3.99,13.79,7.95,20.71,11.9.56.32.79.66.79,1.33-.02,8-.02,16,0,23.99,0,.66-.2,1.04-.79,1.33-.77.39-1.51.85-2.32,1.32Z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -0,0 +1,64 @@
{
"Orchestral Bass": {
"directory": "/assets/instruments/orchestral-bass",
"filenames": [
"bassdrum-cresc-short.mp3",
"bassdrum-hit-f.mp3",
"bdrum3-fff-rr1.mp3",
"bdrumnew-hit-v7-rr1-sum-(1).mp3"
],
"midi-channel-name": "conductorOrchestralBass",
"image": { "filename": "bass.svg", "yPos": "13%" }
},
"Snare": {
"directory": "/assets/instruments/snare",
"filenames": [
"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": {
"directory": "/assets/instruments/timpani-large",
"filenames": [
"timpani1-hit-v4-rr1-sum.mp3",
"timpani2-roll-v3-rr1-sum.mp3",
"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",
"filenames": [
"timpani1a-hit-v5-rr1-main.mp3",
"timpani2-hit-v3-rr1-sum.mp3",
"timpani4-hit-v2-rr1-sum.mp3"
],
"midi-channel-name": "conductorTimpaniSmall",
"image": { "filename": "timpani-small.svg", "yPos": "68%" }
},
"Toms": {
"directory": "/assets/instruments/toms",
"filenames": [
"tomh-hitm-v4-rr2-mid.mp3",
"toml-hitm-v4-rr2-mid.mp3",
"toml-rollm-v2-rr1-mid.mp3"
],
"midi-channel-name": "conductorToms",
"image": { "filename": "toms.svg", "yPos": "81%" }
}
}

View File

Before

Width:  |  Height:  |  Size: 457 B

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 501 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 473 B

View File

Before

Width:  |  Height:  |  Size: 507 B

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 662 B

After

Width:  |  Height:  |  Size: 662 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29.23 20.87"><defs><style>.cls-1{fill:#fff;stroke-width:0px;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><g id="Layer_1-2"><path class="cls-1" d="M20.2,10.52c0,3.15-2.5,5.71-5.59,5.71s-5.58-2.55-5.58-5.71,2.5-5.71,5.58-5.71,5.59,2.55,5.59,5.71"/><path class="cls-2" d="M0,.5c3.67,0,6.64,4.45,6.64,9.94S3.67,20.37,0,20.37"/><path class="cls-2" d="M29.23,20.37c-3.67,0-6.64-4.45-6.64-9.94S25.56.5,29.23.5"/></g></svg>

Before

Width:  |  Height:  |  Size: 541 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.32 23.97"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><g id="Layer_1-2"><path class="cls-1" d="M14.82,7.72c0,3.99-3.21,7.22-7.16,7.22S.5,11.71.5,7.72,3.7.5,7.66.5s7.16,3.24,7.16,7.22Z"/><path class="cls-1" d="M7.66,13.21c-1.53,3.42-3.07,6.84-4.6,10.26h9.2c-1.53-3.42-3.07-6.84-4.6-10.26Z"/><ellipse class="cls-1" cx="7.66" cy="7.72" rx="4.55" ry="4.68"/></g></svg>

Before

Width:  |  Height:  |  Size: 506 B

1
assets/svg/menu.svg Executable file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17.54 10.79"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><g id="Layer_1-2"><line class="cls-1" y1=".5" x2="17.54" y2=".5"/><line class="cls-1" y1="5.39" x2="17.54" y2="5.39"/><line class="cls-1" y1="10.29" x2="17.54" y2="10.29"/></g></svg>

After

Width:  |  Height:  |  Size: 378 B

1
assets/svg/mute.svg Executable file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.27 15.64"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><g id="Layer_1-2"><line class="cls-1" x1="19.78" y1="4.49" x2="13.66" y2="10.61"/><line class="cls-1" x1="13.66" y1="4.49" x2="19.78" y2="10.61"/><polygon class="cls-1" points=".5 11.16 3.84 11.16 10.92 14.82 10.92 .82 3.84 4.49 .5 4.49 .5 11.15 .5 11.16"/><line class="cls-1" x1="3.84" y1="4.49" x2="3.84" y2="11.16"/></g></svg>

After

Width:  |  Height:  |  Size: 525 B

1
assets/svg/sound-on.svg Executable file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.27 15.64"><defs><style>.cls-1{fill:none;stroke:#fff;stroke-miterlimit:10;}</style></defs><g id="Layer_1-2"><path class="cls-1" d="M13.66,4.49l.17.2c1.35,1.67,1.35,4.05,0,5.72l-.17.2"/><path class="cls-1" d="M15.68,2.12l.29.36c2.4,2.95,2.4,7.18,0,10.14l-.29.36"/><polygon class="cls-1" points=".5 11.16 3.84 11.16 10.92 14.82 10.92 .82 3.84 4.49 .5 4.49 .5 11.15 .5 11.16"/><line class="cls-1" x1="3.84" y1="4.49" x2="3.84" y2="11.16"/></g></svg>

After

Width:  |  Height:  |  Size: 552 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 266.18 28.35"><defs><style>.cls-1{fill:none;}.cls-1,.cls-2{stroke-width:0px;}.cls-3{clip-path:url(#clippath);}.cls-2{fill:#fff;}</style><clipPath id="clippath"><rect class="cls-1" width="266.18" height="28.35"/></clipPath></defs><g id="Layer_1-2"><g class="cls-3"><path class="cls-2" d="M257.75,27.95v-12.16c0-1.1,1.89-2.6,2.95-2.6h5.47v-4.92h-12.13v19.68h3.7ZM238.3,23.42c-1.89,0-4.57-2.95-4.57-4.49v-1.69c0-1.54,2.68-4.45,4.57-4.45h2.68c1.85,0,4.61,2.95,4.61,4.45v1.69c0,1.5-2.76,4.49-4.61,4.49h-2.68ZM241.34,28.35c2.84,0,7.99-6.46,7.99-9.17v-2.13c0-2.72-5.16-9.17-7.99-9.17h-3.35c-2.84,0-7.99,6.46-7.99,9.17v2.13c0,2.72,5.16,9.17,7.99,9.17h3.35ZM224.21,23.03c-1.02,0-2.64-1.65-2.64-2.84v-7.4h4.61v-4.53h-4.61V2.76h-3.54v5.51h-3.94v4.53h3.94v7.8c0,2.87,3.31,7.36,5.79,7.36h3.94v-4.92h-3.54ZM204.72,28.35c2.16,0,6.61-4.61,7.09-7.44h-3.74c-.55,1.18-2.05,2.52-3.5,2.52h-2.44c-1.69,0-4.37-2.95-4.37-4.49v-1.69c0-1.54,2.68-4.45,4.37-4.45h2.44c1.46,0,2.99,1.3,3.5,2.48h3.74c-.35-2.6-4.53-7.4-7.09-7.4h-2.91c-2.83,0-7.79,6.42-7.79,9.17v2.13c0,2.72,4.96,9.17,7.79,9.17h2.91ZM177.24,28.15c.98,0,2.2-1.18,2.79-2.05h3.74v1.85h5.51V8.27h-3.54v11.38c0,1.69-2.17,3.19-3.43,3.19h-1.89c-1.26,0-3.43-1.5-3.43-3.03v-11.53h-3.54v15.98c0,1.65,1.77,3.9,2.8,3.9h.99ZM157.28,23.42c-2.09,0-4.96-2.76-4.96-4.29v-2.09c0-1.54,2.87-4.25,4.96-4.25h2.05c2.05,0,4.88,2.75,4.88,4.25v2.09c0,1.5-2.84,4.29-4.88,4.29h-2.05ZM158.5,28.35c1.34,0,2.72-1.38,4.05-2.91h1.77v2.52h3.54V.39h-3.54v10.39h-1.77c-1.34-1.54-2.72-2.91-4.05-2.91h-2.52c-2.24,0-7.4,6.46-7.4,9.17v2.13c0,2.72,5.16,9.17,7.4,9.17h2.52ZM131.69,27.95v-11.38c0-1.69,2.17-3.19,3.43-3.19h2.09c1.26,0,3.43,1.1,3.43,3.03v11.53h3.54V11.57c0-1.26-1.57-3.5-2.72-3.5h-1.22c-1.26,0-2.32,1.22-2.84,2.05h-3.74v-1.85h-5.51v19.68h3.54ZM112.4,23.42c-1.89,0-4.57-2.95-4.57-4.49v-1.69c0-1.54,2.68-4.45,4.57-4.45h2.68c1.85,0,4.61,2.95,4.61,4.45v1.69c0,1.5-2.76,4.49-4.61,4.49h-2.68ZM115.43,28.35c2.83,0,7.99-6.46,7.99-9.17v-2.13c0-2.72-5.16-9.17-7.99-9.17h-3.35c-2.83,0-7.99,6.46-7.99,9.17v2.13c0,2.72,5.16,9.17,7.99,9.17h3.35ZM90.55,28.35c3.5,0,9.17-5.2,10.2-10.31h-4.13c-.75,3.15-3.66,5.2-5.71,5.2h-3.35c-3.15,0-7.13-5.75-7.13-7.91v-2.16c0-2.24,3.98-8.03,7.13-8.03h3.35c2.01,0,5.28,2.6,5.67,5.16h4.13C100.04,5.12,94.01,0,90.55,0h-2.95c-4.37,0-11.1,8.66-11.1,12.83v2.76c0,4.09,6.73,12.76,11.1,12.76h2.95ZM48.54,16.26c.71-1.73,2.48-3.46,4.17-3.46h3.15c1.46,0,3.11,1.38,3.94,3.46h-11.26ZM55.91,28.35c2.09,0,6.42-3.9,7.28-6.69h-4.13c-.71,1.02-2.01,1.77-3.19,1.77h-3.15c-1.69,0-3.74-2.05-4.17-4.01h14.96v-1.97c0-3.31-5-9.57-7.6-9.57h-3.07c-2.87,0-8.03,6.46-8.03,9.17v2.13c0,2.72,5.16,9.17,8.03,9.17h3.07ZM28.54,27.95v-11.38c0-1.69,1.97-3.19,3.23-3.19h1.85c1.26,0,3.23,1.3,3.23,3.03v11.53h3.54v-15.79c0-1.46-2.01-4.1-3.43-4.1h-1.69c-1.02,0-2.4,1.18-3.07,2.05h-3.66V.39h-3.54v27.56h3.54ZM20.87.39H0v4.92h8.66v22.64h3.54V5.31h8.66V.39Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="1200"> <svg xmlns="http://www.w3.org/2000/svg" width="3" height="1200">
<line style="fill: rgb(0, 216, 0); stroke: rgb(0, 216, 0);" x1="1" y1="1" x2="1" y2="1200"></line> <line style="fill: rgb(0, 216, 0); stroke: rgb(255, 0, 0);" x1="1" y1="1" x2="1" y2="1200"></line>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 175 B

After

Width:  |  Height:  |  Size: 175 B

View File

@ -1,22 +1,94 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8" /> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta charset="UTF-8" />
<title>Vertical Line Animation</title> <meta name="viewport" content="width=device-width, user-scalable=no" />
<link rel="stylesheet" href="styles.css" /> <title>Conductor</title>
</head> <link rel="icon" href="/Logo.svg" type="image/svg+xml">
<body> <link rel="stylesheet" href="styles.css" />
<div class="title">Conductor</div> </head>
<body>
<div id="loading-screen">
<object type="image/svg+xml" data="/Logo.svg" class="logo"></object>
<div class="loading">
</div>
</div>
<div id="buttons">
<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" id="title">
15.5.2024 08:00:00 - 08:01:00 UTC
</div>
<div class="sheet-music-window" id="music-window"> <div class="sheet-music-window" id="music-window">
<object <object type="image/svg+xml" data="/assets/svg/time-pointer.svg" class="time-indicator"
type="image/svg+xml" id="time-indicator"></object>
data="/assets/svg/time-pointer.svg"
class="time-indicator"
id="time-indicator"
></object>
</div> </div>
<script src="/src/script.js"></script> </div>
</body> <div id="about-content">
</html>
<div class="about-title">
<img src="/assets/svg/the-conductor-title.svg"></img>
</div>
<div class="about-content">
<div class="safari">
<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.
</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.
</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.
</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>.
</p>
<br />
<div class="production-credits">
<br />
<div>
Project Conception and Design by Mishka Henner.
</div>
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.
</p>
</div>
</div>
</div>
<script type="module" src="/src/script.js"></script>
</body>
</html>

18
notes.txt Normal file
View File

@ -0,0 +1,18 @@
stop zooming issue - resize rules
mishka gonna send an x icon for the back behaviour
look at memory leak??
make the sound and menu icons part of an 'app bar' along with the conductor logo
make the mid size the default size but double check the size on the phone isnt too small
refactor when it's all done
format the key as per the pdf
sort out the title size
sort out the blitzortung connection issue
make the text max size smaller
about page make title smaller

144
src/blitz.js Normal file
View File

@ -0,0 +1,144 @@
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach((listener) => listener(...args));
}
}
removeAllListeners() {
this.events = {};
}
}
// Convert Node.js module system to ES6 module system
export class NotConnectedError extends Error {
constructor(client) {
super("Client not connected");
this.client = client;
}
}
export const Polarity = {
Negative: 0,
Positive: 1,
};
export const Region = {
Unknown: 0,
Europe: 1,
Oceania: 2,
NorthAmerica: 3,
Asia: 4,
SouthAmerica: 5,
};
export class Client extends EventEmitter {
constructor(socketFactory) {
super();
this.socketFactory = socketFactory;
}
getSocket() {
return this.socket;
}
connect(url = this.generateRandomConnectionUrl()) {
const socket = (this.socket = this.socketFactory.make(url));
socket.onmessage = (event) => {
const rawData = this.decode(event.data);
this.emit("data", this.buildStrikeData(JSON.parse(rawData)));
};
socket.onopen = () => {
this.sendJSON({ a: 111 });
this.emit("connect", socket);
};
socket.onerror = (err) => this.emit("error", err);
}
close() {
if (!this.socket) {
throw new NotConnectedError(this);
}
this.socket.close();
this.removeAllListeners();
}
processRawLocation(location) {
return {
latitude: location.lat,
longitude: location.lon,
altitude: location.alt,
};
}
buildStrikeData(strike) {
return {
location: this.processRawLocation(strike),
deviation: strike.mds,
delay: strike.delay,
time: new Date(Math.floor(strike.time / 1e6)),
detectors: strike.sig.map((rawDec) => ({
id: rawDec.sta,
location: this.processRawLocation(rawDec),
status: rawDec.status,
delay: rawDec.time,
})),
polarity: strike.pol > 0 ? Polarity.Positive : Polarity.Negative,
maxDeviation: strike.mds,
maxCircularGap: strike.mcg,
region: strike.region,
};
}
decode(b) {
let a,
e = {},
d = b.split(""),
c = d[0],
f = c,
g = [c],
h = 256,
o = h;
for (let i = 1; i < d.length; i++) {
let charCode = d[i].charCodeAt(0);
a = h > charCode ? d[i] : e[charCode] ? e[charCode] : f + c;
g.push(a);
c = a.charAt(0);
e[o] = f + c;
o++;
f = a;
}
return g.join("");
}
sendJSON(data) {
this.socket.send(JSON.stringify(data));
}
generateRandomConnectionUrl() {
const knownServerIds = [1, 7, 8];
return `wss://ws${
knownServerIds[Math.floor(Math.random() * knownServerIds.length)]
}.blitzortung.org:443/`;
}
}
export class BrowserSocketFactory {
make(url) {
return new WebSocket(url);
}
}

66
src/instruments.js Normal file
View File

@ -0,0 +1,66 @@
async function loadInstrumentsConfig() {
const response = await fetch("/assets/instruments/instruments.json");
return await response.json();
}
async function fetchAudioData(url) {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
return arrayBuffer;
}
async function decodeAudioData(context, arrayBuffer) {
return new Promise((resolve, reject) => {
context.decodeAudioData(arrayBuffer, resolve, reject);
});
}
async function loadAudioSamples(context, directory, filenames) {
const audioFiles = filenames;
const audioBuffers = {};
for (const file of audioFiles) {
const arrayBuffer = await fetchAudioData(`${directory}/${file}`);
const audioBuffer = await decodeAudioData(context, arrayBuffer);
const fileName = file.split("/").pop(); // Extract filename without path for reference
audioBuffers[fileName] = audioBuffer;
}
return audioBuffers;
}
async function fetchImageData(url) {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob); // Convert to base64
});
}
export async function loadInstruments() {
const instrumentsConfig = await loadInstrumentsConfig();
const context = new (window.AudioContext || window.webkitAudioContext)();
const instruments = {};
for (const [instrument, config] of Object.entries(instrumentsConfig)) {
const samples = await loadAudioSamples(
context,
config.directory,
config.filenames
);
const imageData = await fetchImageData(
`${config.directory}/${config.image.filename}`
);
instruments[instrument] = {
samples: samples,
image: imageData,
yPos: config.image.yPos, // Store base64-encoded image data
midiChannelName: config["midi-channel-name"],
};
}
return instruments;
}

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,79 +1,295 @@
document.addEventListener('DOMContentLoaded', () => { import { Client, BrowserSocketFactory } from "./blitz.js";
const svgFiles = [ import { loadInstruments } from "./instruments.js";
{ fileName: 'Gong.svg', yPos: '20%' }, import { sendMidiMessage } from "./midi.js";
{ fileName: 'Orchestral Bass.svg', yPos: '10%' },
{ fileName: 'Snare.svg', yPos: '20%' },
{ fileName: 'Surdo Napa.svg', yPos: '30%' },
{ fileName: 'Surdo.svg', yPos: '25%' },
{ fileName: 'Timpani Large.svg', yPos: '40%' },
{ fileName: 'Timpani Small.svg', yPos: '30%' },
{ fileName: 'Toms.svg', yPos: '25%' },
{ fileName: 'Tubular Bells.svg', yPos: '0%' }
];
const numStaves = 6;
const numFiles = svgFiles.length;
const sheetWindow = document.getElementById("music-window");
for (let i = 1; i <= numStaves; i++) { document.addEventListener("DOMContentLoaded", async () => {
const staveWrapper = document.createElement('div'); let showing;
staveWrapper.classList.add(`stave-wrapper`); let audioContext;
staveWrapper.setAttribute("id", `stave-wrapper-${i}`); let interacted = true;
staveWrapper.style.position = 'relative'; let gainNode;
const staveObject = document.createElement('object');
staveObject.type = 'image/svg+xml';
staveObject.data = 'assets/svg/Stave.svg';
staveObject.classList.add('stave-svg');
staveWrapper.appendChild(staveObject); sendMidiMessage();
sheetWindow.appendChild(staveWrapper);
}
const timeIndicator = document.querySelector('#time-indicator'); function startAudio() {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
gainNode = audioContext.createGain();
gainNode.gain.value = 0;
gainNode.connect(audioContext.destination);
}
// Debugging log to ensure the element is found function muter() {
if (timeIndicator) { fadeOutVolume();
console.log('timeIndicator element found'); }
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}<span class="tab-space"></span>${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 { } else {
console.log('timeIndicator element not found'); 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
} }
timeIndicator.addEventListener("animationiteration", () => { // Create a new client instance and re-establish the connection
const icons = document.querySelectorAll('.event-icon'); client = new Client(new BrowserSocketFactory());
setupWebSocketListeners(); // Set up listeners for the new WebSocket
client.connect(); // Reconnect
icons.forEach((icon) => { // Reset timeout after reconnecting
icon.classList.add('fade-out'); resetTimeout(); // Ensure timeout is re-established after reconnection
icon.addEventListener('transitionend', () => { }
icon.remove();
}); 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;
}
}); });
document.addEventListener('click', () => { client.on("error", (message) => {
console.log("WebSocket error:", message);
const randomStaveNumber = Math.floor(Math.random() * numStaves + 1); reconnectWebSocket();
const randomFileNumber = Math.floor(Math.random() * numFiles + 1);
const rect = timeIndicator.getBoundingClientRect();
const sheetLeft = sheetWindow.getBoundingClientRect().left;
const xPosition = rect.left + window.scrollX - sheetLeft;
console.log(`${svgFiles[randomStaveNumber].fileName}`);
const newObject = document.createElement('div');
newObject.classList.add('event-icon');
newObject.style.position = 'absolute';
newObject.style.left = `${xPosition}px`;
newObject.style.top = `${svgFiles[randomFileNumber].yPos}`;
const eventIcon = document.createElement('object');
eventIcon.type = 'image/svg+xml';
eventIcon.data = `assets/svg/${svgFiles[randomFileNumber].fileName}`;
eventIcon.style.width = '35px';
eventIcon.style.height = '35px';
// eventIcon.style.backgroundColor = 'red';
newObject.appendChild(eventIcon);
const staveWrapper = document.getElementById(`stave-wrapper-${randomStaveNumber}`);
staveWrapper.appendChild(newObject);
}); });
}) client.on("close", () => {
console.log("WebSocket closed, attempting to reconnect...");
reconnectWebSocket();
});
}
let currStaveNumber = 1;
const instruments = await loadInstruments();
const instNames = Object.keys(instruments);
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
resetTimeout(); // Start the timeout timer
});

View File

@ -2,50 +2,220 @@
body { body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* justify-content: center; */
align-items: center; align-items: center;
background-color: rgb(24, 24, 24); background-color: rgb(24, 24, 24);
position: absoulute;
height: 100vh; height: 100vh;
overflow: hidden;
}
object {
margin-bottom: 10px;
}
html {
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
#main-content {
position: absolute;
width: 100%;
max-width: 800px;
height: 100%;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity 2s ease;
overflow: hidden;
}
#about-content {
position: relative;
flex-direction: column;
display: none;
width: 80vw;
max-width: 700px;
padding-right: 10px;
height: 100%;
color: #fff;
/* justify-content: center; */
align-items: center;
font-family: 'Courier';
font-size: clamp(8pt, 3vw, 12pt);
line-height: 1.2;
margin: 20px;
opacity: 0;
transition: opacity 2s ease;
}
#loading-screen {
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
transition: opacity 1s ease;
}
#buttons {
display: none;
opacity: 0;
transition: opacity 1s ease;
}
.logo {
color: #fff;
width: 20%;
height: 20%;
animation: rotate360 10s linear infinite;
}
.loading {
font-family: Helvetica;
font-size: 10pt;
margin: 20px;
}
.event-icon {
width: 1vw;
min-width: 10px;
}
.instruments-key {
position: relative;
display: flex;
margin: 8px;
padding-top: 8% ;
padding-bottom: 8% ;
flex-direction: row;
align-content: center;
justify-content: space-around;
}
.instrument-key {
display: flex;
flex-direction: column;
vertical-align: baseline;
align-items: center;
text-align: center;
justify-content: space-between;
width: clamp(10px,5rem,24px);
font-size: clamp(8px, 1vw, 12px);
} }
.sheet-music-window { .sheet-music-window {
position: relative; position: relative;
width: 80vw; width: 80vw;
max-width: 700px; max-width: 700px;
height: auto; height: 70%;
margin: 0; margin: 0;
background-color: rgb(49, 45, 45); background-color: rgb(24,24,24);
margin-bottom: 100px;
} }
.title { .conductor-title{
height: 20vh; width: 40%;
position: relative; }
.menu {
position: fixed;
padding: 40px;
width: 21px;
top: 0;
left: 0;
flex: 0 0 auto;
z-index: 99;
}
.audio{
position: fixed;
padding: 40px;
width: 20px;
top: 0;
right: 0;
flex: 0 0 auto;
z-index: 10;
}
.title{
top: 30px;
width: 100%;
margin: 30px;
text-align: center;
color: white;
background-color: rgb(24,24,24);
/* height: 20vh; */
font-family: Helvetica;
font-size: clamp(8px,1.1vw, 18px);
}
.about-title {
top: 30px;
width: 50%;
}
.title-title {
font-family: Helvetica;
color: #fff;
font-size: clamp(12px,1.5vw, 24px);
}
.production-credits {
font-size: smaller;
}
.tab-space::before {
content: '\00a0\00a0\00a0\00a0\00a0\00a0'; /* 6 non-breaking spaces */
} }
.stave-wrapper { .stave-wrapper {
position: relative; position: relative;
background-color: rgb(24,24,24); background-color: rgb(24,24,24);
border: 1px solid rgb(24,24,24); border: 1px solid rgb(24,24,24);
padding: 30px; padding-top: 30px;
padding-bottom: 20px;
} }
.time-indicator { .time-indicator {
top: 0; top: 0;
left: 0; left: 0;
position: absolute; position: absolute;
width: 2px; /* Adjust width of SVG as needed */ width: 2px;
height: 100%; /* Adjust height of SVG as needed */ /* height: 100%; */
animation: moveRight 10s linear infinite; animation: moveRight 10s linear infinite;
z-index: 2; /* Ensure it is above other elements */ z-index: 2;
}
.fade-in {
opacity: 1;
} }
.fade-out { .fade-out {
opacity: 0; opacity: 0;
transition: opacity 0.8s ease; transition: opacity 1s ease;
} }
@keyframes rotate360 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes moveRight { @keyframes moveRight {
0% { 0% {
left: 0; left: 0;