Compare commits
No commits in common. "bdc8b286c1440ff9dfdf718a8c482a01d964e7fb" and "57be46cb342c559e75c7d621eb272e1b219f6815" have entirely different histories.
bdc8b286c1
...
57be46cb34
45
Logo.svg
|
|
@ -1,45 +0,0 @@
|
|||
<?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>
|
||||
|
Before Width: | Height: | Size: 9.1 KiB |
|
|
@ -1,64 +0,0 @@
|
|||
{
|
||||
"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%" }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?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>
|
||||
|
After Width: | Height: | Size: 541 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 501 B After Width: | Height: | Size: 501 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 473 B After Width: | Height: | Size: 473 B |
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 439 B |
|
Before Width: | Height: | Size: 662 B After Width: | Height: | Size: 662 B |
|
|
@ -0,0 +1 @@
|
|||
<?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>
|
||||
|
After Width: | Height: | Size: 506 B |
|
|
@ -1 +0,0 @@
|
|||
<?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>
|
||||
|
Before Width: | Height: | Size: 378 B |
|
|
@ -1 +0,0 @@
|
|||
<?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>
|
||||
|
Before Width: | Height: | Size: 525 B |
|
|
@ -1 +0,0 @@
|
|||
<?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>
|
||||
|
Before Width: | Height: | Size: 552 B |
|
|
@ -1 +0,0 @@
|
|||
<?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>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
|
|
@ -1,5 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="3" height="1200">
|
||||
|
||||
<line style="fill: rgb(0, 216, 0); stroke: rgb(255, 0, 0);" x1="1" y1="1" x2="1" y2="1200"></line>
|
||||
<line style="fill: rgb(0, 216, 0); stroke: rgb(0, 216, 0);" x1="1" y1="1" x2="1" y2="1200"></line>
|
||||
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 175 B After Width: | Height: | Size: 175 B |
100
index.html
|
|
@ -1,94 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no" />
|
||||
<title>Conductor</title>
|
||||
<link rel="icon" href="/Logo.svg" type="image/svg+xml">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vertical Line Animation</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</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>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="title">Conductor</div>
|
||||
|
||||
<div class="sheet-music-window" id="music-window">
|
||||
<object type="image/svg+xml" data="/assets/svg/time-pointer.svg" class="time-indicator"
|
||||
id="time-indicator"></object>
|
||||
<object
|
||||
type="image/svg+xml"
|
||||
data="/assets/svg/time-pointer.svg"
|
||||
class="time-indicator"
|
||||
id="time-indicator"
|
||||
></object>
|
||||
</div>
|
||||
</div>
|
||||
<div id="about-content">
|
||||
|
||||
<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 Salford’s 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>
|
||||
|
||||
<script src="/src/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
18
notes.txt
|
|
@ -1,18 +0,0 @@
|
|||
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
|
|
@ -1,144 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
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
|
|
@ -1,30 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
314
src/script.js
|
|
@ -1,295 +1,79 @@
|
|||
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 = 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}<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 {
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const svgFiles = [
|
||||
{ fileName: 'Gong.svg', yPos: '20%' },
|
||||
{ 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++) {
|
||||
const staveWrapper = document.createElement("div");
|
||||
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.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");
|
||||
const timeIndicator = document.querySelector('#time-indicator');
|
||||
|
||||
// Debugging log to ensure the element is found
|
||||
if (timeIndicator) {
|
||||
console.log('timeIndicator element found');
|
||||
} else {
|
||||
console.log('timeIndicator element not found');
|
||||
}
|
||||
|
||||
timeIndicator.addEventListener("animationiteration", () => {
|
||||
currStaveNumber++;
|
||||
if (currStaveNumber > numStaves) {
|
||||
cleanUpAndRestart();
|
||||
}
|
||||
});
|
||||
const icons = document.querySelectorAll('.event-icon');
|
||||
|
||||
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.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);
|
||||
document.addEventListener('click', () => {
|
||||
|
||||
// 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 randomStaveNumber = Math.floor(Math.random() * numStaves + 1);
|
||||
const randomFileNumber = Math.floor(Math.random() * numFiles + 1);
|
||||
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";
|
||||
console.log(`${svgFiles[randomStaveNumber].fileName}`);
|
||||
|
||||
newObject.style.left = `${
|
||||
xPosition - document.documentElement.clientWidth / 200
|
||||
}px`;
|
||||
newObject.style.top = `${instrument.yPos}`;
|
||||
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';
|
||||
|
||||
// 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
|
||||
const staveWrapper = document.getElementById(`stave-wrapper-${randomStaveNumber}`);
|
||||
staveWrapper.appendChild(newObject);
|
||||
};
|
||||
});
|
||||
|
||||
let strikeNumber = 0;
|
||||
|
||||
setupWebSocketListeners(); // Setup the WebSocket listeners
|
||||
resetTimeout(); // Start the timeout timer
|
||||
});
|
||||
})
|
||||
196
styles.css
|
|
@ -2,220 +2,50 @@
|
|||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: rgb(24, 24, 24);
|
||||
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);
|
||||
background-color: rgb(24, 24, 24);
|
||||
position: absoulute;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.sheet-music-window {
|
||||
position: relative;
|
||||
width: 80vw;
|
||||
max-width: 700px;
|
||||
height: 70%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
background-color: rgb(24,24,24);
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.conductor-title{
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.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);
|
||||
background-color: rgb(49, 45, 45);
|
||||
|
||||
}
|
||||
|
||||
.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 */
|
||||
.title {
|
||||
height: 20vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stave-wrapper {
|
||||
position: relative;
|
||||
background-color: rgb(24,24,24);
|
||||
border: 1px solid rgb(24,24,24);
|
||||
padding-top: 30px;
|
||||
padding-bottom: 20px;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.time-indicator {
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
/* height: 100%; */
|
||||
width: 2px; /* Adjust width of SVG as needed */
|
||||
height: 100%; /* Adjust height of SVG as needed */
|
||||
animation: moveRight 10s linear infinite;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
.fade-in {
|
||||
opacity: 1;
|
||||
z-index: 2; /* Ensure it is above other elements */
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease;
|
||||
transition: opacity 0.8s ease;
|
||||
}
|
||||
|
||||
@keyframes rotate360 {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes moveRight {
|
||||
0% {
|
||||
left: 0;
|
||||
|
|
|
|||