rehersal_v1

This commit is contained in:
Dooho Yi 2024-10-15 00:26:12 +09:00
parent bcb6e31c4b
commit f18feab7a3
25 changed files with 681 additions and 132 deletions

Binary file not shown.

Binary file not shown.

BIN
audio/05.mp3 Normal file

Binary file not shown.

BIN
audio/06.mp3 Normal file

Binary file not shown.

BIN
audio/07.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
audio/minok_01.mp3 Normal file

Binary file not shown.

BIN
audio/minok_03.mp3 Normal file

Binary file not shown.

BIN
audio/minok_04.mp3 Normal file

Binary file not shown.

BIN
audio/minok_05.mp3 Normal file

Binary file not shown.

View file

@ -1,14 +1,22 @@
@font-face {
font-family: 'ACCchildrenfall';
src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_2112-2@1.0/ACCchildrenfall.woff') format('woff');
font-weight: normal;
font-style: normal;
}
html, html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: 'ACCchildrenfall';
} }
canvas { canvas {
display: block; display: block;
} }
.overlay-userinput { .fullscreen {
display: grid; display: grid;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -17,8 +25,55 @@ canvas {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size: 3em;
}
#overlay-userinput {
/* display: none; */
background-color: rgba(255, 255, 255, 0.5); background-color: rgba(255, 255, 255, 0.5);
color: white; color: white;
z-index: 2; z-index: 2;
/* display: none; */ }
#announcements {
/* display: none; */
/* background-color: lime; */
color: white;
z-index: 1;
}
#radio {
position: fixed;
top: 20px;
left: 20px;
z-index: 1;
}
#radiostart-userinput {
position: fixed;
top: 50px;
right: 20px;
z-index: 1;
}
#scene-minok {
position: fixed;
top: 100px;
right: 20px;
z-index: 1;
}
#scene-wonjung {
position: fixed;
top: 150px;
right: 20px;
z-index: 1;
}
#scene-all {
position: fixed;
top: 200px;
right: 20px;
z-index: 1;
} }

46
css/loading-animation.css Normal file
View file

@ -0,0 +1,46 @@
/* Styles go here */
.animationStripes{
background-image: repeating-linear-gradient(-45deg, gold, gold 1em, blue 1em, blue 2em);
-webkit-animation:progress 2s linear infinite;
-moz-animation:progress 2s linear infinite;
-ms-animation:progress 2s linear infinite;
animation:progress 2s linear infinite;
background-size: 150% 100%;
display: none;
color: white;
z-index: 2;
}
@-webkit-keyframes progress{
0% {
background-position: 0 0;
}
100% {
background-position: -3em 0em;
}
}
@-moz-keyframes progress{
0% {
background-position: 0 0;
}
100% {
background-position: -3em 0em;
}
}
@-ms-keyframes progress{
0% {
background-position: 0 0;
}
100% {
background-position: -3em 0em;
}
}
@keyframes progress{
0% {
background-position: 0 0;
}
100% {
background-position: -2.8em 0em;
}
}

View file

@ -8,22 +8,51 @@
<script src="js/p5.min.js"></script> <script src="js/p5.min.js"></script>
<script src="js/Tone.min.js"></script> <script src="js/Tone.min.js"></script>
<!-- css --> <!-- css -->
<link rel="stylesheet" href="css/default.css"> <link type="text/css" rel="stylesheet" href="css/default.css">
<!-- script --> <link type="text/css" rel="stylesheet" href="css/loading-animation.css" />
<!-- <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> -->
<script> <script>
const AudioContext = window.AudioContext || window.webkitAudioContext; // const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx; // let audioCtx;
</script> </script>
<script src="js/util.js"></script> <script src="js/util.js"></script>
<script src="js/classes.js"></script> <script src="js/classes.js"></script>
</head> </head>
<body> <body>
<button class='overlay-userinput' onclick='initialize();'> <div id='overlay-userinput' class='fullscreen' onclick='initialize();'>
<div>터치하고-시작하기!</div> <div style='width:100%;'>
<div style='text-align: left;'>터치하고-</div>
<div style='text-align: right;'>시작하기!</div>
</div>
</div>
<div id='loading-veil' class='fullscreen animationStripes'>
<div>로~~~~~딩⏳</div>
</div>
<div id='announcements' class='fullscreen announcements'>
<div></div>
</div>
<button id='radiostart-userinput' onclick='document.querySelector("#radio").play();'>
<span style='font-size:3em;'>📻</span>
</button> </button>
<audio controls crossorigin="anonymous" style="display:none;"> <button id='scene-minok' onclick='scene=10;sceneChanger();'>
<span style='font-size:3em;'>🍇</span>
</button>
<button id='scene-wonjung' onclick='scene=20;sceneChanger();'>
<span style='font-size:3em;'>🥑</span>
</button>
<button id='scene-all' onclick='scene=scene+1;sceneChanger();'>
<span style='font-size:3em;'>🥥</span>
</button>
<audio id="radio" controls crossorigin="anonymous">
<!-- iOS bug... you must add <source> later! -->
<!-- <source src="https://radio.dianaband.in:8000/stream" type="audio/aac" /> --> <!-- <source src="https://radio.dianaband.in:8000/stream" type="audio/aac" /> -->
</audio> </audio>
@ -33,8 +62,6 @@
let heading = 0; let heading = 0;
let latitude = 37.574973; let latitude = 37.574973;
let longitude = 126.925708; let longitude = 126.925708;
// let latitude = 37.576774;
// let longitude = 126.931232;
// 맞는 결과 (예) : 작업실 -> 베지스 // 맞는 결과 (예) : 작업실 -> 베지스
// p1 = [37.574973, 126.925708] // p1 = [37.574973, 126.925708]
@ -48,7 +75,15 @@
let silence; let silence;
let clap; let clap;
let radio; let radio;
//all ready flag (not used) //scene
let scene = -1;
//sounders' list
let scenes = {};
let minok_sounds = [];
let wonjung_sounds = [];
scenes.minok_sounds = minok_sounds;
scenes.wonjung_sounds = wonjung_sounds;
//all ready flag
let ready = false; let ready = false;
//clear all permissions //clear all permissions
@ -59,69 +94,237 @@
requestOrientationPermission(); requestOrientationPermission();
} }
// remove the 'userinput' veil
document.querySelector("#overlay-userinput").style.display = 'none';
// show loading screen.
document.querySelector("#loading-veil").style.display = 'grid';
// unfreeze Tone.js with userinput
await Tone.start();
// start audiocontext // start audiocontext
audioCtx = new AudioContext; // audioCtx = new AudioContext;
// audioCtx = Tone.getContext();
// some sounds for check-in // some sounds for check-in
silence = (await AudioImport("./audio/_silence.wav")).toDestination(); silence = (await AudioImport("./audio/_silence.wav")).toDestination();
clap = (await AudioImport("./audio/clap01.mp3")).toDestination(); clap = (await AudioImport("./audio/clap01.mp3")).toDestination();
// start loading for all sounds
sounds.forEach(async item => await item.load());
// unfreeze audio playback for Tone.js
silence.start(); silence.start();
// clap.start();
// remove the veil // register sounders to the list
let veil = document.querySelector(".overlay-userinput"); minok_sounds.push(new Sounder({
veil.style.display = 'none'; name: '주파수 구간',
location: [37.575451, 126.926939],
soundfile: "./audio/minok_01.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
minok_sounds.push(new Sounder({
name: 'Transpose',
location: [37.575009, 126.926373],
soundfile: "./audio/minok_02.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
minok_sounds.push(new Sounder({
name: 'Delay',
location: [37.574383, 126.925500],
soundfile: "./audio/minok_03.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
minok_sounds.push(new Sounder({
name: 'EQ',
location: [37.573562, 126.924426],
soundfile: "./audio/minok_04.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
minok_sounds.push(new Sounder({
name: '모든 효과가 다 섞인 뇌절 of 뇌절 트랙',
location: [37.572931, 126.923612],
soundfile: "./audio/minok_05.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
minok_sounds.push(new Sounder({
name: '뇌절 트랙 (끝!)',
location: [37.571918, 126.922360],
soundfile: "./audio/minok_05.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
// activate radio by adding source tag wonjung_sounds.push(new Sounder({
const audiotag = document.querySelector('audio'); // N.B. assuming there's only 1 audio tag for streaming... name: '푸르지오 앞 데크길 밑 운동기구',
location: [37.576013, 126.927912],
soundfile: "./audio/01.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '연리지',
location: [37.574409, 126.925210],
soundfile: "./audio/02.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '폭우와 멜로디혼',
location: [37.573430, 126.923445],
soundfile: "./audio/03.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '농구대',
location: [37.573149, 126.922870],
soundfile: "./audio/04.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '물소리 조각',
location: [37.574623, 126.924903],
soundfile: "./audio/05.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '좌우패닝 벤치-지나가는 무게들',
location: [37.577172, 126.922993],
soundfile: "./audio/06.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
wonjung_sounds.push(new Sounder({
name: '귀뚜라미',
location: [37.576753, 126.929252],
soundfile: "./audio/07.mp3",
gain: 0,
spread: 20,
distmap: [0.01, 0.08, 0, -20], // (km) -> (dB)
//testing
volmin: -30,
}));
// start loading for all soundfile-based sounders.
//N.B. for 'await', watch out 'forEach' ... https://stackoverflow.com/a/37576787
for (const item of scenes.wonjung_sounds) await item.load();
for (const item of scenes.minok_sounds) await item.load();
// activate radio by injecting <source> tag
const audiotag = document.querySelector('#radio');
const sourcetag = document.createElement('source'); const sourcetag = document.createElement('source');
sourcetag.setAttribute('src', 'https://radio.dianaband.in:8000/stream'); sourcetag.setAttribute('src', 'https://radio.dianaband.in:8000/stream');
sourcetag.setAttribute('type', 'audio/aac'); sourcetag.setAttribute('type', 'audio/aac');
audiotag.appendChild(sourcetag); audiotag.appendChild(sourcetag);
audiotag.play();
// //link a sounder object to radio streaming.. //link a sounder object to radio streaming..
// radio = new Sounder({ radio = new RadioSounder({
// // location: [37.576013, 126.927912], name: "베짜-📻",
// location: [37.574973, 126.935708], location: [37.574973, 126.925708],
// soundfile: "./audio/clap01.mp3", gain: 0,
// gain: 6, spread: 90,
// spread: 15, distmap: [0.01, 2, 0, -10], // (km) -> (dB)
// distmap: [0.005, 0.05, 0, -10], //testing
// //testing volmin: -30,
// volmin: -30, });
// }); radio.link(audiotag);
// // radio.radiolink(audiotag); // audiotag.play(); // this doesn't work.. for some buggy iOS versions. another userinput needed..
// radio.load();
// remove loading screen.
document.querySelector("#loading-veil").style.display = 'none';
// remove loading screen.
document.querySelector("#announcements").style.display = 'grid';
// //
ready = true; ready = true;
//
scene = 0;
sceneChanger();
} }
let compass_target; async function sceneChanger() {
let compass_north; switch (scene) {
let sounds = []; case 0:
await fullscreenSplasher('<div>스테이지</div>', 1000); // some *splashes*
await fullscreenSplasher('<div>0</div>', 1000);
await fullscreenSplasher('<div>시작~~~</div>', 3000);
await fullscreenSplasher('', 0);
break;
case 10:
await fullscreenSplasher('<div>스테이지</div>', 1000); // some *splashes*
await fullscreenSplasher('<div>1</div>', 1000);
await fullscreenSplasher('<div>시작~~~</div>', 3000);
await fullscreenSplasher('', 0);
break;
case 20:
await fullscreenSplasher('<div>스테이지</div>', 1000); // some *splashes*
await fullscreenSplasher('<div>2</div>', 1000);
await fullscreenSplasher('<div>시작~~~</div>', 3000);
await fullscreenSplasher('', 0);
break;
case 30:
await fullscreenSplasher('<div>스테이지</div>', 1000); // some *splashes*
await fullscreenSplasher('<div>3</div>', 1000);
await fullscreenSplasher('<div>시작~~~</div>', 3000);
await fullscreenSplasher('', 0);
break;
default:
;
}
}
async function fullscreenSplasher(html, timeout) {
let element = document.querySelector('#announcements');
// element.style.display = 'grid';
element.innerHTML = html;
await asyncTimeout(timeout);
}
function setup() { function setup() {
createCanvas(windowWidth, windowHeight); createCanvas(windowWidth, windowHeight);
compass_target = new Compass(200, ['#97FFFF', '#33A1DE', 'white']);
compass_north = new Compass(40, ['yellow', 'navy', 'white']);
angleMode(DEGREES); angleMode(DEGREES);
// register sounders to the list
sounds.push(new Sounder({
location: [37.576774, 126.931232],
soundfile: "./audio/01.mp3",
gain: 6,
spread: 15,
distmap: [0.005, 0.05, 0, -10],
//testing
volmin: -30,
}));
} }
function draw() { function draw() {
@ -132,82 +335,279 @@
if (ready) { if (ready) {
//update sounders //update sounders
sounds.forEach(async item => await item.update()); scenes.wonjung_sounds.forEach(item => item.update_location());
// radio.update(); scenes.minok_sounds.forEach(item => item.update_location());
// //update radio
let target = sounds[0]; radio.update_location();
radio.pv.pan.value = 0;
radio.pv.volume.rampTo(radio.gain, radio.ramptime);
////main group ////main group
//(push) //a tabular compass closet.
push(); let compass_table;
//compass (the North) //scene logic
translate(20, 20, 0); if (scene == 0) {
compass_target.heading = target.angerr; //target #0
compass_target.draw();
//(pop) // tutorial stage
pop();
//(push) scenes.wonjung_sounds.forEach(item => item.update_panvol());
push(); //
//debug compass_table = [];
fill('white'); Sounder.allStart(scenes.wonjung_sounds);
translate(30, 200, 0); Sounder.allStop(scenes.minok_sounds);
Textline.restart(); // draw sth.
Textline.put('heading'); push();
Textline.put(heading); let sounder = scenes.wonjung_sounds[0];
Textline.put('ang'); let compass_target = new Compass(250, ['#003456', '#77AAAA', 'navy']);
Textline.put(target.ang); compass_target.pointer = sounder.angerr;
Textline.put('angerr'); translate((windowWidth - compass_target.size) / 2, (windowHeight - compass_target.size) / 2, 0);
Textline.put(target.angerr); compass_target.draw();
Textline.put('distance'); fill('white');
Textline.put(target.dist); Textline.restart();
// Textline.put('pan'); Textline.put(sounder.name);
// Textline.put(target.pv.pan.value); Textline.put(sounder.latitude.toFixed(4) + ', ' + sounder.longitude.toFixed(4));
// Textline.put('distvol'); Textline.put(sounder.angerr.toFixed(2) + ', ' + (sounder.dist * 1000).toFixed(2));
// Textline.put(target.distvol); Textline.put(sounder.pv.pan.value.toFixed(2) + ', ' + sounder.distvol.toFixed(2) + ', ' + sounder.pv.volume.value.toFixed(2));
// Textline.put('vol'); Textline.put(sounder.zone);
// Textline.put(target.pv.volume.value); pop();
Textline.put('target_lat');
Textline.put(target.latitude);
Textline.put('target_lon');
Textline.put(target.longitude);
//(pop) } else if (scene == 10) {
pop();
//no sound
//N.B. assumption: change all locations to 'trigger' locations!
//minok scene
// approaching to the spot. **before** reaching the first trigger location.
compass_table = scenes.minok_sounds;
Sounder.allSilent(scenes.minok_sounds);
Sounder.allStart(scenes.minok_sounds);
Sounder.allStop(scenes.wonjung_sounds);
//
let next = scenes.minok_sounds[0];
if (next.dist < 0.05) {
//fade-in
// console.log(next.snd.state);
next.pv.pan.value = 0;
next.pv.volume.rampTo(next.gain, next.ramptime);
scene = 11;
sceneChanger();
}
} else if (scene == 11) {
//minok scene
//listening to track #1
compass_table = scenes.minok_sounds;
//
let current = scenes.minok_sounds[0];
current.pv.volume.rampTo(current.gain, current.ramptime);
let next = scenes.minok_sounds[1];
if (next.dist < 0.05) {
//N.B. assumption: change location to 'playstart' location!
//cross-fade
current.pv.volume.rampTo(-99, current.ramptime);
next.pv.volume.rampTo(next.gain, next.ramptime);
scene = 12;
sceneChanger();
}
} else if (scene == 12) {
//minok scene
//listening to track #2
compass_table = scenes.minok_sounds;
//
let current = scenes.minok_sounds[1];
current.pv.volume.rampTo(current.gain, current.ramptime);
let next = scenes.minok_sounds[2];
if (next.dist < 0.05) {
//N.B. assumption: change location to 'playstart' location!
//cross-fade
current.pv.volume.rampTo(-99, current.ramptime);
next.pv.volume.rampTo(next.gain, next.ramptime);
scene = 13;
sceneChanger();
}
} else if (scene == 13) {
//minok scene
//listening to track #3
compass_table = scenes.minok_sounds;
//
let current = scenes.minok_sounds[2];
current.pv.volume.rampTo(current.gain, current.ramptime);
let next = scenes.minok_sounds[3];
if (next.dist < 0.05) {
//N.B. assumption: change location to 'playstart' location!
//cross-fade
current.pv.volume.rampTo(-99, current.ramptime);
next.pv.volume.rampTo(next.gain, next.ramptime);
scene = 14;
sceneChanger();
}
} else if (scene == 14) {
//minok scene
//listening to track #4
compass_table = scenes.minok_sounds;
//
let current = scenes.minok_sounds[3];
current.pv.volume.rampTo(current.gain, current.ramptime);
let next = scenes.minok_sounds[4];
if (next.dist < 0.05) {
//N.B. assumption: change location to 'playstart' location!
//cross-fade
current.pv.volume.rampTo(-99, current.ramptime);
next.pv.volume.rampTo(next.gain, next.ramptime);
scene = 15;
sceneChanger();
}
} else if (scene == 15) {
//minok scene
//listening to track #5
compass_table = scenes.minok_sounds;
//
let current = scenes.minok_sounds[4];
current.pv.volume.rampTo(current.gain, current.ramptime);
let next = scenes.minok_sounds[5]; // <-- dummy location, no sound. ending waypoint.
if (next.dist < 0.05) {
//N.B. assumption: change location to 'playstart' location!
//fade-out
current.pv.volume.rampTo(-99, current.ramptime);
next.pv.volume.rampTo(-99, next.ramptime);
scene = 16;
sceneChanger();
}
} else if (scene == 16) {
//minok scene
//No-no zone.
compass_table = [];
Sounder.allStop(scenes.minok_sounds);
Sounder.allStop(scenes.minok_sounds);
} else if (scene == 20) {
//wonjung scene
compass_table = scenes.wonjung_sounds;
Sounder.allStart(scenes.wonjung_sounds);
Sounder.allStop(scenes.minok_sounds);
scenes.wonjung_sounds.forEach(item => item.update_panvol());
} else {
//everything else
// nothing to show/playback.
compass_table = [];
Sounder.allStop(scenes.wonjung_sounds);
Sounder.allStop(scenes.minok_sounds);
}
//
push(); // +1
translate(20, 90, 0);
//
let compass_offsets = [
createVector(0, 0),
createVector(0, 110),
createVector(0, 220),
createVector(0, 330),
createVector(150, 0),
createVector(150, 110),
createVector(150, 220),
createVector(150, 330),
];
for (const [i, sounder] of compass_table.entries()) {
push(); // +2
translate(compass_offsets[i].x, compass_offsets[i].y, 0);
//compass targeting the location
// let compass_target = new Compass(120, ['#33A1DE', '#97FFFF', 'navy']);
let compass_target = new Compass(120, ['#003456', '#77AAAA', 'navy']);
compass_target.pointer = sounder.angerr;
compass_target.draw();
//debug
// translate(0, 120, 0);
translate(0, 0, 0);
fill('white');
Textline.restart();
Textline.put(sounder.name);
Textline.put(sounder.latitude.toFixed(4) + ', ' + sounder.longitude.toFixed(4));
Textline.put(sounder.angerr.toFixed(2) + ', ' + (sounder.dist * 1000).toFixed(2));
Textline.put(sounder.pv.pan.value.toFixed(2) + ', ' + sounder.distvol.toFixed(2) + ', ' + sounder.pv.volume.value.toFixed(2));
pop(); // -2
}
pop(); // -1
// ////radio
// push(); // +2
// translate(windowWidth - 120, windowHeight - 200, 0);
//
// //compass targeting the location
// // let compass_target = new Compass(120, ['#33A1DE', '#97FFFF', 'navy']);
// let compass_radio = new Compass(120, ['#003456', '#77AAAA', 'navy']);
// compass_radio.pointer = radio.angerr;
// compass_radio.draw();
//
// //debug
// // translate(0, 120, 0);
// translate(0, 0, 0);
// fill('white');
// Textline.restart();
// Textline.put(radio.name);
// Textline.put(radio.latitude.toFixed(4) + ', ' + radio.longitude.toFixed(4));
// Textline.put(radio.angerr.toFixed(2) + ', ' + (radio.dist * 1000).toFixed(2));
// Textline.put(radio.pv.pan.value.toFixed(2) + ', ' + radio.distvol.toFixed(2) + ', ' + radio.pv.volume.value.toFixed(2));
//
// pop(); // -2
////status-left group ////status-left group
//(push) push(); // +1
push();
//
translate(20, windowHeight - 100, 0); translate(20, windowHeight - 100, 0);
fill('white'); fill('white');
Textline.restart(); Textline.restart();
Textline.put('current location'); Textline.put('current location');
Textline.put(latitude); Textline.put(latitude.toFixed(6) + ', ' + longitude.toFixed(6));
Textline.put(longitude); Textline.put('scene');
Textline.put(scene);
//(pop) pop(); // -1
pop();
////status-right group ////status-right group
//(push) push(); // +1
push(); translate(windowWidth - 50, windowHeight - 100, 0);
let compass_north = new Compass(40, ['yellow', 'navy', 'white']);
// compass_north.pointer = heading * -1; // the North pole azimuth is opposite of my heading.
translate(windowWidth - 50, windowHeight - 50, 0);
compass_north.heading = heading;
compass_north.draw(); compass_north.draw();
translate(0, 40, 0);
//(pop) fill('white');
pop(); Textline.restart();
Textline.put('N');
Textline.put(heading.toFixed(2));
pop(); // -1
} }
} }
</script> </script>

View file

@ -1,6 +1,7 @@
// sounds // sounds
class Sounder { class Sounder {
constructor(args) { constructor(args) {
this.name = args.name;
this.soundfile = args.soundfile; this.soundfile = args.soundfile;
this.gain = args.gain; // (dB) this.gain = args.gain; // (dB)
this.latitude = args.location[0]; this.latitude = args.location[0];
@ -9,27 +10,30 @@ class Sounder {
this.distmap = args.distmap; this.distmap = args.distmap;
this.volmin = args.volmin; // (dB) this.volmin = args.volmin; // (dB)
this.ramptime = args.ramptime; // (seconds) this.ramptime = args.ramptime; // (seconds)
this.zone = 0;
} }
async load() { async load() {
//start sound playback //start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination(); this.pv = new Tone.PanVol(0, -99).toDestination();
this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here. this.snd = await AudioImport(this.soundfile); // NOTE: url with spaces didn't work here.
// this.snd.connect(this.pv).start();
this.snd.connect(this.pv); this.snd.connect(this.pv);
this.snd.start();
this.snd.loop = true; this.snd.loop = true;
} }
update() { update_location() {
//
//update sound pan/volume
//
// this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); (deg)
this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg) this.ang = getBearing(latitude, longitude, this.latitude, this.longitude); // (deg)
this.angerr = (heading - this.ang + 360) % 360; this.angerr = ((this.ang - heading + 360) % 360 + 180) % 360 - 180;
this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km) this.dist = getDistance(latitude, longitude, this.latitude, this.longitude); // (km)
// //
this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB) this.distvol = map(this.dist, this.distmap[0], this.distmap[1], this.distmap[2], this.distmap[3], true); //(dB)
}
update_panvol() {
// console.log('pv');
//
//update sound pan/volume
//
// (from Pure Data patch "iamyou", [eqpan2~]) // (from Pure Data patch "iamyou", [eqpan2~])
// arg #1 (inlet #3): width: // arg #1 (inlet #3): width:
@ -37,22 +41,35 @@ class Sounder {
// -width/2 ~ width/2 -> cross fading // -width/2 ~ width/2 -> cross fading
// +width/2 ~ width*(1.5) -> right fade-out // +width/2 ~ width*(1.5) -> right fade-out
//if close enough. don't do pan/vol, but just playback with full volume.
this.zone = 0;
if (this.dist < 0.07) {
this.zone = 1;
this.pv.pan.rampTo(0, this.ramptime);
this.pv.volume.rampTo(this.gain, this.ramptime); //(dB)
return;
}
let panleft_start = this.spread * (-1.5); let panleft_start = this.spread * (-1.5);
let panleft_end = this.spread * (-0.5); let panleft_end = this.spread * (-0.5);
let panright_start = this.spread * (0.5); let panright_start = this.spread * (0.5);
let panright_end = this.spread * (1.5); let panright_end = this.spread * (1.5);
//left fade-in //pan & volume
if (this.angerr > panleft_start && this.angerr < panleft_end) { if (this.angerr > panleft_start && this.angerr < panleft_end) {
//left fade-in
this.pv.pan.value = -1; //left-full this.pv.pan.value = -1; //left-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime)//cross fading; //(dB) this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panleft_start, panleft_end, this.volmin, 0), this.ramptime); //(dB)
} else if (this.angerr > panleft_end && this.angerr < panright_start) { } else if (this.angerr > panleft_end && this.angerr < panright_start) {
this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1); // crossfade //cross fading; //(dB)
this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime)//right fade-out; //(dB) this.pv.pan.value = map(this.angerr, panleft_end, panright_start, -1, 1);
this.pv.volume.rampTo(this.distvol + this.gain, this.ramptime); //(dB)
} else if (this.angerr > panright_start && this.angerr < panright_end) { } else if (this.angerr > panright_start && this.angerr < panright_end) {
//right fade-out
this.pv.pan.value = 1; //right-full this.pv.pan.value = 1; //right-full
this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime)//slience; //(dB) this.pv.volume.rampTo(this.distvol + this.gain + map(this.angerr, panright_start, panright_end, 0, this.volmin), this.ramptime); //(dB)
} else { } else {
//slience
this.pv.volume.rampTo(-99, 10); //(dB) this.pv.volume.rampTo(-99, 10); //(dB)
} }
} }
@ -60,11 +77,33 @@ class Sounder {
draw() { draw() {
//draw sound location //draw sound location
} }
static allStart(array) {
array.forEach(item => {
if (item.snd.state != 'started') item.snd.start();
});
}
static allStop(array) {
array.forEach(item => {
if (item.snd.state != 'stopped') item.snd.stop();
});
}
static allSilent(array) {
array.forEach(item => {
item.pv.volume.rampTo(-99, item.ramptime);
});
}
} }
// //
class RadioSounder extends Sounder { class RadioSounder extends Sounder {
constructor(args) {
super(args);
}
//do nothing //do nothing
async load() { async load() {
; ;
@ -73,15 +112,21 @@ class RadioSounder extends Sounder {
link(audiotag) { link(audiotag) {
//start sound playback //start sound playback
this.pv = new Tone.PanVol(0, -99).toDestination(); this.pv = new Tone.PanVol(0, -99).toDestination();
let stream = Tone.context.createMediaElementSource(audiotag);
this.snd = Tone.context.createGain(); //native webaudio
stream.connect(this.snd); this.source = Tone.context.createMediaElementSource(audiotag);
console.log(stream); this.snd = undefined;
console.log(this.snd); this.gainnode = Tone.context.createGain();
console.log(this.pv); this.gainnode.gain.value = 1; // 1 == max. volume
// this.snd.connect(this.pv.input.input); a hack ...
this.snd.gain.value = 1; //a hacky native-to-Tonejs connection(?!)
this.snd.connect(Tone.context.destination); this.source.connect(this.gainnode).connect(this.pv.input.input);
}
update() {
super.update();
// console.log('hi!');
} }
} }
@ -90,7 +135,7 @@ class Compass {
constructor(size, colors) { constructor(size, colors) {
this.size = size; this.size = size;
this.colors = colors; this.colors = colors;
this.heading = 0; this.pointer = 0;
} }
draw() { draw() {
@ -106,7 +151,7 @@ class Compass {
circle(0, 0, 0.9); circle(0, 0, 0.9);
// //
fill(this.colors[1]); fill(this.colors[1]);
rotate(this.heading * -1); rotate(this.pointer);
quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1); quad(0.1, 0.2, 0, -0.4, -0.1, 0.2, 0, 0.1);
// //
fill(this.colors[2]); fill(this.colors[2]);

View file

@ -86,6 +86,9 @@ function AudioImport(url) {
}); });
} }
//promisified 'setTimeout' from https://stackoverflow.com/a/74004853
const asyncTimeout = ms => new Promise(resolve => setTimeout(resolve, ms));
// some p5 tools // some p5 tools
class Textline { class Textline {
static #lines = 0; static #lines = 0;